diff options
-rw-r--r-- | libsolidity/analysis/TypeChecker.cpp | 69 | ||||
-rw-r--r-- | libsolidity/analysis/TypeChecker.h | 2 |
2 files changed, 41 insertions, 30 deletions
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index b6b4ac90..f2056474 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -744,44 +744,55 @@ void TypeChecker::endVisit(ExpressionStatement const& _statement) typeError(_statement.expression().location(), "Invalid integer constant."); } -void TypeChecker::endVisit(Conditional const& _conditional) +bool TypeChecker::visit(Conditional const& _conditional) { - TypePointer const& conditionType = type(_conditional.condition()); - if (!conditionType->isImplicitlyConvertibleTo(BoolType())) - typeError( - _conditional.location(), - "Conditional expression's type " + - conditionType->toString() + - " doesn't match bool type." - ); - - TypePointer const& trueType = type(_conditional.trueExpression()); - TypePointer const& falseType = type(_conditional.falseExpression()); - // we fake it as an equal operator, but any other comparison operator can work. - TypePointer commonType = trueType->binaryOperatorResult(Token::Equal, falseType); - if (!commonType) - { - typeError( - _conditional.location(), - "True expression's type " + - trueType->toString() + - " doesn't match false expression's type " + - falseType->toString() + - "." - ); - // even we can't find a common type, we have to set a type here, - // otherwise the upper statement will not be able to check the type. - commonType = trueType; - } - _conditional.annotation().type = commonType; + expectType(_conditional.condition(), BoolType()); if (_conditional.annotation().lValueRequested) { requireLValue(_conditional.trueExpression()); requireLValue(_conditional.falseExpression()); + TypePointer const& trueType = type(_conditional.trueExpression()); + TypePointer const& falseType = type(_conditional.falseExpression()); + + // as a left value, we require exact match to prevent subtle conversion issues. + if (*trueType != *falseType) + typeError( + _conditional.location(), + "True expression's type " + + trueType->toString() + + " doesn't match false expression's type " + + falseType->toString() + + "." + ); + + _conditional.annotation().type = trueType; _conditional.annotation().isLValue = true; } + else + { + _conditional.trueExpression().accept(*this); + _conditional.falseExpression().accept(*this); + + TypePointer const& trueType = type(_conditional.trueExpression()); + TypePointer const& falseType = type(_conditional.falseExpression()); + + // we fake it as an equal operator, but any other comparison operator can work. + TypePointer commonType = trueType->binaryOperatorResult(Token::Equal, falseType); + if (!commonType) + typeError( + _conditional.location(), + "True expression's type " + + trueType->toString() + + " doesn't match false expression's type " + + falseType->toString() + + "." + ); + + _conditional.annotation().type = commonType; + } + return false; } bool TypeChecker::visit(Assignment const& _assignment) diff --git a/libsolidity/analysis/TypeChecker.h b/libsolidity/analysis/TypeChecker.h index ae96229b..b884db49 100644 --- a/libsolidity/analysis/TypeChecker.h +++ b/libsolidity/analysis/TypeChecker.h @@ -90,7 +90,7 @@ private: virtual void endVisit(Return const& _return) override; virtual bool visit(VariableDeclarationStatement const& _variable) override; virtual void endVisit(ExpressionStatement const& _statement) override; - virtual void endVisit(Conditional const& _conditional) override; + virtual bool visit(Conditional const& _conditional) override; virtual bool visit(Assignment const& _assignment) override; virtual bool visit(TupleExpression const& _tuple) override; virtual void endVisit(BinaryOperation const& _operation) override; |