diff --git a/Changelog.md b/Changelog.md index 96f3a1444..f269e049f 100644 --- a/Changelog.md +++ b/Changelog.md @@ -10,6 +10,7 @@ Compiler Features: Bugfixes: * Inline Assembly: Fix internal error when accessing invalid constant variables. * Reference Resolver: Fix internal error when accessing invalid struct members. + * Type Checker: Fix internal errors when assigning nested tuples. * Inheritance: Allow public state variables to override functions with dynamic memory types in their return values. * JSON AST: Always add pointer suffix for memory reference types. diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 1345fbf90..784701d22 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -1317,11 +1317,11 @@ void TypeChecker::checkExpressionAssignment(Type const& _type, Expression const& if (auto const* tupleExpression = dynamic_cast(&_expression)) { auto const* tupleType = dynamic_cast(&_type); - auto const& types = tupleType ? tupleType->components() : vector { &_type }; + auto const& types = tupleType && tupleExpression->components().size() > 1 ? tupleType->components() : vector { &_type }; solAssert( tupleExpression->components().size() == types.size() || m_errorReporter.hasErrors(), - "Array sizes don't match or no errors generated." + "Array sizes don't match and no errors generated." ); for (size_t i = 0; i < min(tupleExpression->components().size(), types.size()); i++) diff --git a/test/libsolidity/semanticTests/types/tuple_in_tuple.sol b/test/libsolidity/semanticTests/types/tuple_in_tuple.sol new file mode 100644 index 000000000..d9737a807 --- /dev/null +++ b/test/libsolidity/semanticTests/types/tuple_in_tuple.sol @@ -0,0 +1,24 @@ +contract test { + function f0() public returns(int, bool) { + int a; + bool b; + ((a, b)) = (2, true); + return (a, b); + } + function f1() public returns(int) { + int a; + (((a, ), )) = ((1, 2) ,3); + return a; + } + function f2() public returns(int) { + int a; + (((, a),)) = ((1, 2), 3); + return a; + } +} +// ==== +// compileViaYul: also +// ---- +// f0() -> 2, true +// f1() -> 1 +// f2() -> 2 diff --git a/test/libsolidity/syntaxTests/tupleAssignments/tuple_in_tuple_long.sol b/test/libsolidity/syntaxTests/tupleAssignments/tuple_in_tuple_long.sol new file mode 100644 index 000000000..2fa48cfb1 --- /dev/null +++ b/test/libsolidity/syntaxTests/tupleAssignments/tuple_in_tuple_long.sol @@ -0,0 +1,12 @@ +contract C { + function f() { + (((((((((((,2),)),)),),))=4))); + } +} +// ---- +// SyntaxError: (15-69): No visibility specified. Did you intend to add "public"? +// TypeError: (46-47): Expression has to be an lvalue. +// TypeError: (60-61): Type int_const 4 is not implicitly convertible to expected type tuple(tuple(tuple(tuple(tuple(,int_const 2),),),),). +// TypeError: (37-61): Tuple component cannot be empty. +// TypeError: (36-62): Tuple component cannot be empty. +// TypeError: (35-63): Tuple component cannot be empty. diff --git a/test/libsolidity/syntaxTests/tupleAssignments/tuple_in_tuple_short.sol b/test/libsolidity/syntaxTests/tupleAssignments/tuple_in_tuple_short.sol new file mode 100644 index 000000000..2a5d62752 --- /dev/null +++ b/test/libsolidity/syntaxTests/tupleAssignments/tuple_in_tuple_short.sol @@ -0,0 +1,6 @@ +contract C { + function f() public pure { + int a; + (((a,),)) = ((1,2),3); + } +}