aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorchriseth <c@ethdev.com>2016-01-25 04:43:48 +0800
committerchriseth <c@ethdev.com>2016-01-25 04:43:48 +0800
commit194679f77ada30b04f483e96197e890e41a0c22c (patch)
tree82ed4cec81cb9dd81cbdc3b8134b80fb7e3de780
parent67c855c583042ddee6261a9921239a3afd086c14 (diff)
parent51caa04238ce78420e6efc2ce15842effddf3856 (diff)
downloaddexon-solidity-194679f77ada30b04f483e96197e890e41a0c22c.tar.gz
dexon-solidity-194679f77ada30b04f483e96197e890e41a0c22c.tar.zst
dexon-solidity-194679f77ada30b04f483e96197e890e41a0c22c.zip
Merge pull request #326 from guanqun/cond-expr
support conditional expression _ ? _ : _
-rw-r--r--docs/control-structures.rst2
-rw-r--r--libsolidity/analysis/TypeChecker.cpp37
-rw-r--r--libsolidity/analysis/TypeChecker.h1
-rw-r--r--libsolidity/ast/AST.h27
-rw-r--r--libsolidity/ast/ASTForward.h1
-rw-r--r--libsolidity/ast/ASTJsonConverter.cpp11
-rw-r--r--libsolidity/ast/ASTJsonConverter.h2
-rw-r--r--libsolidity/ast/ASTPrinter.cpp13
-rw-r--r--libsolidity/ast/ASTPrinter.h2
-rw-r--r--libsolidity/ast/ASTVisitor.h4
-rw-r--r--libsolidity/ast/AST_accept.h22
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp16
-rw-r--r--libsolidity/codegen/ExpressionCompiler.h1
-rw-r--r--libsolidity/parsing/Parser.cpp25
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp186
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp176
-rw-r--r--test/libsolidity/SolidityParser.cpp67
17 files changed, 586 insertions, 7 deletions
diff --git a/docs/control-structures.rst b/docs/control-structures.rst
index c833fbfc..4becfcf1 100644
--- a/docs/control-structures.rst
+++ b/docs/control-structures.rst
@@ -9,7 +9,7 @@ Control Structures
Most of the control structures from C/JavaScript are available in Solidity
except for `switch` and `goto`. So
-there is: `if`, `else`, `while`, `for`, `break`, `continue`, `return`, with
+there is: `if`, `else`, `while`, `for`, `break`, `continue`, `return`, `? :`, with
the usual semantics known from C / JavaScript.
Parentheses can *not* be omitted for conditionals, but curly brances can be omitted
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp
index 69357043..0d74ddba 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -744,6 +744,43 @@ void TypeChecker::endVisit(ExpressionStatement const& _statement)
typeError(_statement.expression().location(), "Invalid integer constant.");
}
+bool TypeChecker::visit(Conditional const& _conditional)
+{
+ expectType(_conditional.condition(), BoolType());
+
+ _conditional.trueExpression().accept(*this);
+ _conditional.falseExpression().accept(*this);
+
+ TypePointer trueType = type(_conditional.trueExpression())->mobileType();
+ TypePointer falseType = type(_conditional.falseExpression())->mobileType();
+
+ TypePointer commonType = Type::commonType(trueType, 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;
+
+ if (_conditional.annotation().lValueRequested)
+ typeError(
+ _conditional.location(),
+ "Conditional expression as left value is not supported yet."
+ );
+
+ return false;
+}
+
bool TypeChecker::visit(Assignment const& _assignment)
{
requireLValue(_assignment.leftHandSide());
diff --git a/libsolidity/analysis/TypeChecker.h b/libsolidity/analysis/TypeChecker.h
index 7829a23d..b884db49 100644
--- a/libsolidity/analysis/TypeChecker.h
+++ b/libsolidity/analysis/TypeChecker.h
@@ -90,6 +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 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;
diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h
index 4baf95d3..e1063467 100644
--- a/libsolidity/ast/AST.h
+++ b/libsolidity/ast/AST.h
@@ -1119,6 +1119,33 @@ public:
ExpressionAnnotation& annotation() const override;
};
+class Conditional: public Expression
+{
+public:
+ Conditional(
+ SourceLocation const& _location,
+ ASTPointer<Expression> const& _condition,
+ ASTPointer<Expression> const& _trueExpression,
+ ASTPointer<Expression> const& _falseExpression
+ ):
+ Expression(_location),
+ m_condition(_condition),
+ m_trueExpression(_trueExpression),
+ m_falseExpression(_falseExpression)
+ {}
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ Expression const& condition() const { return *m_condition; }
+ Expression const& trueExpression() const { return *m_trueExpression; }
+ Expression const& falseExpression() const { return *m_falseExpression; }
+
+private:
+ ASTPointer<Expression> m_condition;
+ ASTPointer<Expression> m_trueExpression;
+ ASTPointer<Expression> m_falseExpression;
+};
+
/// Assignment, can also be a compound assignment.
/// Examples: (a = 7 + 8) or (a *= 2)
class Assignment: public Expression
diff --git a/libsolidity/ast/ASTForward.h b/libsolidity/ast/ASTForward.h
index 6aaa77ce..dad2b2e2 100644
--- a/libsolidity/ast/ASTForward.h
+++ b/libsolidity/ast/ASTForward.h
@@ -69,6 +69,7 @@ class Throw;
class VariableDeclarationStatement;
class ExpressionStatement;
class Expression;
+class Conditional;
class Assignment;
class TupleExpression;
class UnaryOperation;
diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp
index 377fa7e6..df836afe 100644
--- a/libsolidity/ast/ASTJsonConverter.cpp
+++ b/libsolidity/ast/ASTJsonConverter.cpp
@@ -217,6 +217,12 @@ bool ASTJsonConverter::visit(ExpressionStatement const&)
return true;
}
+bool ASTJsonConverter::visit(Conditional const&)
+{
+ addJsonNode("Conditional", {}, true);
+ return true;
+}
+
bool ASTJsonConverter::visit(Assignment const& _node)
{
addJsonNode("Assignment",
@@ -397,6 +403,11 @@ void ASTJsonConverter::endVisit(ExpressionStatement const&)
goUp();
}
+void ASTJsonConverter::endVisit(Conditional const&)
+{
+ goUp();
+}
+
void ASTJsonConverter::endVisit(Assignment const&)
{
goUp();
diff --git a/libsolidity/ast/ASTJsonConverter.h b/libsolidity/ast/ASTJsonConverter.h
index de891cc6..b7fc84e9 100644
--- a/libsolidity/ast/ASTJsonConverter.h
+++ b/libsolidity/ast/ASTJsonConverter.h
@@ -67,6 +67,7 @@ public:
bool visit(Throw const& _node) override;
bool visit(VariableDeclarationStatement const& _node) override;
bool visit(ExpressionStatement const& _node) override;
+ bool visit(Conditional const& _node) override;
bool visit(Assignment const& _node) override;
bool visit(TupleExpression const& _node) override;
bool visit(UnaryOperation const& _node) override;
@@ -99,6 +100,7 @@ public:
void endVisit(Throw const&) override;
void endVisit(VariableDeclarationStatement const&) override;
void endVisit(ExpressionStatement const&) override;
+ void endVisit(Conditional const&) override;
void endVisit(Assignment const&) override;
void endVisit(TupleExpression const&) override;
void endVisit(UnaryOperation const&) override;
diff --git a/libsolidity/ast/ASTPrinter.cpp b/libsolidity/ast/ASTPrinter.cpp
index d4f13e47..bc981f7d 100644
--- a/libsolidity/ast/ASTPrinter.cpp
+++ b/libsolidity/ast/ASTPrinter.cpp
@@ -248,6 +248,14 @@ bool ASTPrinter::visit(ExpressionStatement const& _node)
return goDeeper();
}
+bool ASTPrinter::visit(Conditional const& _node)
+{
+ writeLine("Conditional");
+ printType(_node);
+ printSourcePart(_node);
+ return goDeeper();
+}
+
bool ASTPrinter::visit(Assignment const& _node)
{
writeLine(string("Assignment using operator ") + Token::toString(_node.assignmentOperator()));
@@ -480,6 +488,11 @@ void ASTPrinter::endVisit(ExpressionStatement const&)
m_indentation--;
}
+void ASTPrinter::endVisit(Conditional const&)
+{
+ m_indentation--;
+}
+
void ASTPrinter::endVisit(Assignment const&)
{
m_indentation--;
diff --git a/libsolidity/ast/ASTPrinter.h b/libsolidity/ast/ASTPrinter.h
index d9b5e252..334fefc7 100644
--- a/libsolidity/ast/ASTPrinter.h
+++ b/libsolidity/ast/ASTPrinter.h
@@ -75,6 +75,7 @@ public:
bool visit(Throw const& _node) override;
bool visit(VariableDeclarationStatement const& _node) override;
bool visit(ExpressionStatement const& _node) override;
+ bool visit(Conditional const& _node) override;
bool visit(Assignment const& _node) override;
bool visit(TupleExpression const& _node) override;
bool visit(UnaryOperation const& _node) override;
@@ -115,6 +116,7 @@ public:
void endVisit(Throw const&) override;
void endVisit(VariableDeclarationStatement const&) override;
void endVisit(ExpressionStatement const&) override;
+ void endVisit(Conditional const&) override;
void endVisit(Assignment const&) override;
void endVisit(TupleExpression const&) override;
void endVisit(UnaryOperation const&) override;
diff --git a/libsolidity/ast/ASTVisitor.h b/libsolidity/ast/ASTVisitor.h
index f04d9682..625f395d 100644
--- a/libsolidity/ast/ASTVisitor.h
+++ b/libsolidity/ast/ASTVisitor.h
@@ -73,6 +73,7 @@ public:
virtual bool visit(Throw& _node) { return visitNode(_node); }
virtual bool visit(VariableDeclarationStatement& _node) { return visitNode(_node); }
virtual bool visit(ExpressionStatement& _node) { return visitNode(_node); }
+ virtual bool visit(Conditional& _node) { return visitNode(_node); }
virtual bool visit(Assignment& _node) { return visitNode(_node); }
virtual bool visit(TupleExpression& _node) { return visitNode(_node); }
virtual bool visit(UnaryOperation& _node) { return visitNode(_node); }
@@ -115,6 +116,7 @@ public:
virtual void endVisit(Throw& _node) { endVisitNode(_node); }
virtual void endVisit(VariableDeclarationStatement& _node) { endVisitNode(_node); }
virtual void endVisit(ExpressionStatement& _node) { endVisitNode(_node); }
+ virtual void endVisit(Conditional& _node) { endVisitNode(_node); }
virtual void endVisit(Assignment& _node) { endVisitNode(_node); }
virtual void endVisit(TupleExpression& _node) { endVisitNode(_node); }
virtual void endVisit(UnaryOperation& _node) { endVisitNode(_node); }
@@ -169,6 +171,7 @@ public:
virtual bool visit(Throw const& _node) { return visitNode(_node); }
virtual bool visit(VariableDeclarationStatement const& _node) { return visitNode(_node); }
virtual bool visit(ExpressionStatement const& _node) { return visitNode(_node); }
+ virtual bool visit(Conditional const& _node) { return visitNode(_node); }
virtual bool visit(Assignment const& _node) { return visitNode(_node); }
virtual bool visit(TupleExpression const& _node) { return visitNode(_node); }
virtual bool visit(UnaryOperation const& _node) { return visitNode(_node); }
@@ -211,6 +214,7 @@ public:
virtual void endVisit(Throw const& _node) { endVisitNode(_node); }
virtual void endVisit(VariableDeclarationStatement const& _node) { endVisitNode(_node); }
virtual void endVisit(ExpressionStatement const& _node) { endVisitNode(_node); }
+ virtual void endVisit(Conditional const& _node) { endVisitNode(_node); }
virtual void endVisit(Assignment const& _node) { endVisitNode(_node); }
virtual void endVisit(TupleExpression const& _node) { endVisitNode(_node); }
virtual void endVisit(UnaryOperation const& _node) { endVisitNode(_node); }
diff --git a/libsolidity/ast/AST_accept.h b/libsolidity/ast/AST_accept.h
index 61370c55..dee9d5b1 100644
--- a/libsolidity/ast/AST_accept.h
+++ b/libsolidity/ast/AST_accept.h
@@ -551,6 +551,28 @@ void VariableDeclarationStatement::accept(ASTConstVisitor& _visitor) const
_visitor.endVisit(*this);
}
+void Conditional::accept(ASTVisitor& _visitor)
+{
+ if (_visitor.visit(*this))
+ {
+ m_condition->accept(_visitor);
+ m_trueExpression->accept(_visitor);
+ m_falseExpression->accept(_visitor);
+ }
+ _visitor.endVisit(*this);
+}
+
+void Conditional::accept(ASTConstVisitor& _visitor) const
+{
+ if (_visitor.visit(*this))
+ {
+ m_condition->accept(_visitor);
+ m_trueExpression->accept(_visitor);
+ m_falseExpression->accept(_visitor);
+ }
+ _visitor.endVisit(*this);
+}
+
void Assignment::accept(ASTVisitor& _visitor)
{
if (_visitor.visit(*this))
diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp
index 040217da..9536c727 100644
--- a/libsolidity/codegen/ExpressionCompiler.cpp
+++ b/libsolidity/codegen/ExpressionCompiler.cpp
@@ -176,6 +176,22 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
m_context.appendJump(eth::AssemblyItem::JumpType::OutOfFunction);
}
+bool ExpressionCompiler::visit(Conditional const& _condition)
+{
+ CompilerContext::LocationSetter locationSetter(m_context, _condition);
+ _condition.condition().accept(*this);
+ eth::AssemblyItem trueTag = m_context.appendConditionalJump();
+ _condition.falseExpression().accept(*this);
+ utils().convertType(*_condition.falseExpression().annotation().type, *_condition.annotation().type);
+ eth::AssemblyItem endTag = m_context.appendJumpToNew();
+ m_context << trueTag;
+ m_context.adjustStackOffset(-_condition.annotation().type->sizeOnStack());
+ _condition.trueExpression().accept(*this);
+ utils().convertType(*_condition.trueExpression().annotation().type, *_condition.annotation().type);
+ m_context << endTag;
+ return false;
+}
+
bool ExpressionCompiler::visit(Assignment const& _assignment)
{
CompilerContext::LocationSetter locationSetter(m_context, _assignment);
diff --git a/libsolidity/codegen/ExpressionCompiler.h b/libsolidity/codegen/ExpressionCompiler.h
index 379aa65a..f00b24e8 100644
--- a/libsolidity/codegen/ExpressionCompiler.h
+++ b/libsolidity/codegen/ExpressionCompiler.h
@@ -71,6 +71,7 @@ public:
void appendConstStateVariableAccessor(const VariableDeclaration& _varDecl);
private:
+ virtual bool visit(Conditional const& _condition) override;
virtual bool visit(Assignment const& _assignment) override;
virtual bool visit(TupleExpression const& _tuple) override;
virtual bool visit(UnaryOperation const& _unaryOperation) override;
diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp
index 4ac3381c..d9ec1a49 100644
--- a/libsolidity/parsing/Parser.cpp
+++ b/libsolidity/parsing/Parser.cpp
@@ -932,13 +932,26 @@ ASTPointer<Expression> Parser::parseExpression(
)
{
ASTPointer<Expression> expression = parseBinaryExpression(4, _lookAheadIndexAccessStructure);
- if (!Token::isAssignmentOp(m_scanner->currentToken()))
+ if (Token::isAssignmentOp(m_scanner->currentToken()))
+ {
+ Token::Value assignmentOperator = expectAssignmentOperator();
+ ASTPointer<Expression> rightHandSide = parseExpression();
+ ASTNodeFactory nodeFactory(*this, expression);
+ nodeFactory.setEndPositionFromNode(rightHandSide);
+ return nodeFactory.createNode<Assignment>(expression, assignmentOperator, rightHandSide);
+ }
+ else if (m_scanner->currentToken() == Token::Value::Conditional)
+ {
+ m_scanner->next();
+ ASTPointer<Expression> trueExpression = parseExpression();
+ expectToken(Token::Colon);
+ ASTPointer<Expression> falseExpression = parseExpression();
+ ASTNodeFactory nodeFactory(*this, expression);
+ nodeFactory.setEndPositionFromNode(falseExpression);
+ return nodeFactory.createNode<Conditional>(expression, trueExpression, falseExpression);
+ }
+ else
return expression;
- Token::Value assignmentOperator = expectAssignmentOperator();
- ASTPointer<Expression> rightHandSide = parseExpression();
- ASTNodeFactory nodeFactory(*this, expression);
- nodeFactory.setEndPositionFromNode(rightHandSide);
- return nodeFactory.createNode<Assignment>(expression, assignmentOperator, rightHandSide);
}
ASTPointer<Expression> Parser::parseBinaryExpression(
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index 3ef5ebbe..73e2d662 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -86,6 +86,192 @@ BOOST_AUTO_TEST_CASE(exp_operator_const_signed)
BOOST_CHECK(callContractFunction("f()", bytes()) == toBigEndian(u256(-8)));
}
+BOOST_AUTO_TEST_CASE(conditional_expression_true_literal)
+{
+ char const* sourceCode = R"(
+ contract test {
+ function f() returns(uint d) {
+ return true ? 5 : 10;
+ }
+ })";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callContractFunction("f()", bytes()) == toBigEndian(u256(5)));
+}
+
+BOOST_AUTO_TEST_CASE(conditional_expression_false_literal)
+{
+ char const* sourceCode = R"(
+ contract test {
+ function f() returns(uint d) {
+ return false ? 5 : 10;
+ }
+ })";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callContractFunction("f()", bytes()) == toBigEndian(u256(10)));
+}
+
+BOOST_AUTO_TEST_CASE(conditional_expression_multiple)
+{
+ char const* sourceCode = R"(
+ contract test {
+ function f(uint x) returns(uint d) {
+ return x > 100 ?
+ x > 1000 ? 1000 : 100
+ :
+ x > 50 ? 50 : 10;
+ }
+ })";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callContractFunction("f(uint256)", u256(1001)) == toBigEndian(u256(1000)));
+ BOOST_CHECK(callContractFunction("f(uint256)", u256(500)) == toBigEndian(u256(100)));
+ BOOST_CHECK(callContractFunction("f(uint256)", u256(80)) == toBigEndian(u256(50)));
+ BOOST_CHECK(callContractFunction("f(uint256)", u256(40)) == toBigEndian(u256(10)));
+}
+
+BOOST_AUTO_TEST_CASE(conditional_expression_with_return_values)
+{
+ char const* sourceCode = R"(
+ contract test {
+ function f(bool cond, uint v) returns (uint a, uint b) {
+ cond ? a = v : b = v;
+ }
+ })";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callContractFunction("f(bool,uint256)", true, u256(20)) == encodeArgs(u256(20), u256(0)));
+ BOOST_CHECK(callContractFunction("f(bool,uint256)", false, u256(20)) == encodeArgs(u256(0), u256(20)));
+}
+
+BOOST_AUTO_TEST_CASE(conditional_expression_storage_memory_1)
+{
+ char const* sourceCode = R"(
+ contract test {
+ bytes2[2] data1;
+ function f(bool cond) returns (uint) {
+ bytes2[2] memory x;
+ x[0] = "aa";
+ bytes2[2] memory y;
+ y[0] = "bb";
+
+ data1 = cond ? x : y;
+
+ uint ret = 0;
+ if (data1[0] == "aa")
+ {
+ ret = 1;
+ }
+
+ if (data1[0] == "bb")
+ {
+ ret = 2;
+ }
+
+ return ret;
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callContractFunction("f(bool)", true) == encodeArgs(u256(1)));
+ BOOST_CHECK(callContractFunction("f(bool)", false) == encodeArgs(u256(2)));
+}
+
+BOOST_AUTO_TEST_CASE(conditional_expression_storage_memory_2)
+{
+ char const* sourceCode = R"(
+ contract test {
+ bytes2[2] data1;
+ function f(bool cond) returns (uint) {
+ data1[0] = "cc";
+
+ bytes2[2] memory x;
+ bytes2[2] memory y;
+ y[0] = "bb";
+
+ x = cond ? y : data1;
+
+ uint ret = 0;
+ if (x[0] == "bb")
+ {
+ ret = 1;
+ }
+
+ if (x[0] == "cc")
+ {
+ ret = 2;
+ }
+
+ return ret;
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callContractFunction("f(bool)", true) == encodeArgs(u256(1)));
+ BOOST_CHECK(callContractFunction("f(bool)", false) == encodeArgs(u256(2)));
+}
+
+BOOST_AUTO_TEST_CASE(conditional_expression_different_types)
+{
+ char const* sourceCode = R"(
+ contract test {
+ function f(bool cond) returns (uint) {
+ uint8 x = 0xcd;
+ uint16 y = 0xabab;
+ return cond ? x : y;
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callContractFunction("f(bool)", true) == encodeArgs(u256(0xcd)));
+ BOOST_CHECK(callContractFunction("f(bool)", false) == encodeArgs(u256(0xabab)));
+}
+
+/* let's add this back when I figure out the correct type conversion.
+BOOST_AUTO_TEST_CASE(conditional_expression_string_literal)
+{
+ char const* sourceCode = R"(
+ contract test {
+ function f(bool cond) returns (bytes32) {
+ return cond ? "true" : "false";
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callContractFunction("f(bool)", true) == encodeArgs(string("true", 4)));
+ BOOST_CHECK(callContractFunction("f(bool)", false) == encodeArgs(string("false", 5)));
+}
+*/
+
+BOOST_AUTO_TEST_CASE(conditional_expression_tuples)
+{
+ char const* sourceCode = R"(
+ contract test {
+ function f(bool cond) returns (uint, uint) {
+ return cond ? (1, 2) : (3, 4);
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callContractFunction("f(bool)", true) == encodeArgs(u256(1), u256(2)));
+ BOOST_CHECK(callContractFunction("f(bool)", false) == encodeArgs(u256(3), u256(4)));
+}
+
+BOOST_AUTO_TEST_CASE(conditional_expression_functions)
+{
+ char const* sourceCode = R"(
+ contract test {
+ function x() returns (uint) { return 1; }
+ function y() returns (uint) { return 2; }
+
+ function f(bool cond) returns (uint) {
+ var z = cond ? x : y;
+ return z();
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callContractFunction("f(bool)", true) == encodeArgs(u256(1)));
+ BOOST_CHECK(callContractFunction("f(bool)", false) == encodeArgs(u256(2)));
+}
+
BOOST_AUTO_TEST_CASE(recursive_calls)
{
char const* sourceCode = "contract test {\n"
diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp
index c8e901e4..820fd7d0 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -2960,6 +2960,182 @@ BOOST_AUTO_TEST_CASE(continue_not_in_loop_2)
BOOST_CHECK(expectError(text) == Error::Type::SyntaxError);
}
+BOOST_AUTO_TEST_CASE(invalid_different_types_for_conditional_expression)
+{
+ char const* text = R"(
+ contract C {
+ function f() {
+ true ? true : 2;
+ }
+ }
+ )";
+ BOOST_CHECK(expectError(text) == Error::Type::TypeError);
+}
+
+BOOST_AUTO_TEST_CASE(left_value_in_conditional_expression_not_supported_yet)
+{
+ char const* text = R"(
+ contract C {
+ function f() {
+ uint x;
+ uint y;
+ (true ? x : y) = 1;
+ }
+ }
+ )";
+ BOOST_CHECK(expectError(text) == Error::Type::TypeError);
+}
+
+BOOST_AUTO_TEST_CASE(conditional_expression_with_different_struct)
+{
+ char const* text = R"(
+ contract C {
+ struct s1 {
+ uint x;
+ }
+ struct s2 {
+ uint x;
+ }
+ function f() {
+ s1 x;
+ s2 y;
+ true ? x : y;
+ }
+ }
+ )";
+ BOOST_CHECK(expectError(text) == Error::Type::TypeError);
+}
+
+BOOST_AUTO_TEST_CASE(conditional_expression_with_different_function_type)
+{
+ char const* text = R"(
+ contract C {
+ function x(bool) {}
+ function y() {}
+
+ function f() {
+ true ? x : y;
+ }
+ }
+ )";
+ BOOST_CHECK(expectError(text) == Error::Type::TypeError);
+}
+
+BOOST_AUTO_TEST_CASE(conditional_expression_with_different_enum)
+{
+ char const* text = R"(
+ contract C {
+ enum small { A, B, C, D }
+ enum big { A, B, C, D }
+
+ function f() {
+ small x;
+ big y;
+
+ true ? x : y;
+ }
+ }
+ )";
+ BOOST_CHECK(expectError(text) == Error::Type::TypeError);
+}
+
+BOOST_AUTO_TEST_CASE(conditional_expression_with_different_mapping)
+{
+ char const* text = R"(
+ contract C {
+ mapping(uint8 => uint8) table1;
+ mapping(uint32 => uint8) table2;
+
+ function f() {
+ true ? table1 : table2;
+ }
+ }
+ )";
+ BOOST_CHECK(expectError(text) == Error::Type::TypeError);
+}
+
+BOOST_AUTO_TEST_CASE(conditional_with_all_types)
+{
+ char const* text = R"(
+ contract C {
+ struct s1 {
+ uint x;
+ }
+ s1 struct_x;
+ s1 struct_y;
+
+ function fun_x() {}
+ function fun_y() {}
+
+ enum small { A, B, C, D }
+
+ mapping(uint8 => uint8) table1;
+ mapping(uint8 => uint8) table2;
+
+ function f() {
+ // integers
+ uint x;
+ uint y;
+ true ? x : y;
+
+ // integer constants
+ true ? 1 : 3;
+
+ // string literal
+ true ? "hello" : "world";
+
+ // bool
+ true ? true : false;
+
+ // real is not there yet.
+
+ // array
+ byte[2] memory a;
+ byte[2] memory b;
+ true ? a : b;
+
+ bytes memory e;
+ bytes memory f;
+ true ? e : f;
+
+ // fixed bytes
+ bytes2 c;
+ bytes2 d;
+ true ? c : d;
+
+ // contract doesn't fit in here
+
+ // struct
+ true ? struct_x : struct_y;
+
+ // function
+ true ? fun_x : fun_y;
+
+ // enum
+ small enum_x;
+ small enum_y;
+ true ? enum_x : enum_y;
+
+ // tuple
+ true ? (1, 2) : (3, 4);
+
+ // mapping
+ true ? table1 : table2;
+
+ // typetype
+ true ? uint32(1) : uint32(2);
+
+ // modifier doesn't fit in here
+
+ // magic doesn't fit in here
+
+ // module doesn't fit in here
+ }
+ }
+ )";
+ BOOST_CHECK(success(text));
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/SolidityParser.cpp b/test/libsolidity/SolidityParser.cpp
index 8e0bf77e..055fae49 100644
--- a/test/libsolidity/SolidityParser.cpp
+++ b/test/libsolidity/SolidityParser.cpp
@@ -1111,6 +1111,73 @@ BOOST_AUTO_TEST_CASE(inline_array_empty_cells_check_without_lvalue)
BOOST_CHECK(!successParse(text));
}
+BOOST_AUTO_TEST_CASE(conditional_true_false_literal)
+{
+ char const* text = R"(
+ contract A {
+ function f() {
+ uint x = true ? 1 : 0;
+ uint y = false ? 0 : 1;
+ }
+ }
+ )";
+ BOOST_CHECK(successParse(text));
+}
+
+BOOST_AUTO_TEST_CASE(conditional_with_constants)
+{
+ char const* text = R"(
+ contract A {
+ function f() {
+ uint x = 3 > 0 ? 3 : 0;
+ uint y = (3 > 0) ? 3 : 0;
+ }
+ }
+ )";
+ BOOST_CHECK(successParse(text));
+}
+
+BOOST_AUTO_TEST_CASE(conditional_with_variables)
+{
+ char const* text = R"(
+ contract A {
+ function f() {
+ uint x = 3;
+ uint y = 1;
+ uint z = (x > y) ? x : y;
+ uint w = x > y ? x : y;
+ }
+ }
+ )";
+ BOOST_CHECK(successParse(text));
+}
+
+BOOST_AUTO_TEST_CASE(conditional_multiple)
+{
+ char const* text = R"(
+ contract A {
+ function f() {
+ uint x = 3 < 0 ? 2 > 1 ? 2 : 1 : 7 > 2 ? 7 : 6;
+ }
+ }
+ )";
+ BOOST_CHECK(successParse(text));
+}
+
+BOOST_AUTO_TEST_CASE(conditional_with_assignment)
+{
+ char const* text = R"(
+ contract A {
+ function f() {
+ uint y = 1;
+ uint x = 3 < 0 ? x = 3 : 6;
+ true ? x = 3 : 4;
+ }
+ }
+ )";
+ BOOST_CHECK(successParse(text));
+}
+
BOOST_AUTO_TEST_SUITE_END()
}