diff --git a/.circleci/config.yml b/.circleci/config.yml index 0319ca152..ac1dda7dd 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -122,6 +122,10 @@ defaults: name: command line tests command: ./test/cmdlineTests.sh + - run_docs_version_pragma_check: &run_docs_version_pragma_check + name: docs version pragma check + command: ./scripts/docs_version_pragma_check.sh + - test_ubuntu1604_clang: &test_ubuntu1604_clang docker: - image: ethereum/solidity-buildpack-deps:ubuntu1604-clang-ossfuzz-<< pipeline.parameters.ubuntu-1604-clang-ossfuzz-docker-image-rev >> @@ -303,6 +307,18 @@ jobs: name: Linting Python Scripts command: ./scripts/pylint_all.py + chk_antlr_grammar: + docker: + - image: buildpack-deps:eoan + steps: + - checkout + - run: + name: Install Java + command: apt -q update && apt install -y openjdk-14-jdk + - run: + name: Run tests + command: ./scripts/test_antlr_grammar.sh + chk_buglist: docker: - image: circleci/node @@ -605,6 +621,7 @@ jobs: - attach_workspace: at: build - run: *run_cmdline_tests + - run: *run_docs_version_pragma_check - store_test_results: *store_test_results - store_artifacts: *artifacts_test_results @@ -768,6 +785,7 @@ workflows: - chk_buglist: *workflow_trigger_on_tags - chk_proofs: *workflow_trigger_on_tags - chk_pylint: *workflow_trigger_on_tags + - chk_antlr_grammar: *workflow_trigger_on_tags # build-only - b_docs: *workflow_trigger_on_tags diff --git a/.clang-format b/.clang-format index f9953c17b..edd5de4d2 100644 --- a/.clang-format +++ b/.clang-format @@ -6,26 +6,35 @@ # Note that clang-format cannot express the style that closing parentheses # behave similar to closing curly braces in a multi-line setting in that # they have to be on a line of their own at the same indentation level -# as the opening part. +# as the opening part (aka "dangling parenthesis", see https://reviews.llvm.org/D33029). Language: Cpp BasedOnStyle: LLVM +AccessModifierOffset: -4 +AlignAfterOpenBracket: AlwaysBreak AlignEscapedNewlinesLeft: true AlwaysBreakAfterReturnType: None +AlwaysBreakTemplateDeclarations: Yes BinPackArguments: false BinPackParameters: false BreakBeforeBinaryOperators: All BreakBeforeBraces: Allman ColumnLimit: 120 ContinuationIndentWidth: 4 +FixNamespaceComments: false IndentWidth: 4 KeepEmptyLinesAtTheStartOfBlocks: false MaxEmptyLinesToKeep: 2 PenaltyBreakBeforeFirstCallParameter: 2000 +PointerAlignment: Left SpaceAfterCStyleCast: true +SpaceAfterTemplateKeyword: false +SpaceBeforeCtorInitializerColon: false +SpaceBeforeInheritanceColon: false SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: false TabWidth: 4 -UseTab: ForIndentation +UseTab: Always # Local Variables: # mode: yaml diff --git a/CODING_STYLE.md b/CODING_STYLE.md index 6bdb48fba..78b2ab310 100644 --- a/CODING_STYLE.md +++ b/CODING_STYLE.md @@ -141,7 +141,7 @@ struct MeanSigma double const d = 0; int i = 0; int j = 0; -char* s; +char* s = nullptr; MeanAndSigma ms meanAndSigma(std::vector const& _v, Accuracy _a); Derived* x = dynamic_cast(base); for (auto i = x->begin(); i != x->end(); ++i) {} diff --git a/Changelog.md b/Changelog.md index 9bd949d5d..de4596433 100644 --- a/Changelog.md +++ b/Changelog.md @@ -18,7 +18,9 @@ Compiler Features: Bugfixes: - * Metadata: Added support for IPFS hashes of large files that need to be split in multiple chunks. + * Inline Assembly: Fix internal error when accessing incorrect constant variables. + * 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. ### 0.6.4 (2020-03-10) @@ -143,6 +145,12 @@ Compiler Features: * ABIEncoderV2: Do not warn about enabled ABIEncoderV2 anymore (the pragma is still needed, though). +### 0.5.17 (2020-03-17) + +Bugfixes: + * Type Checker: Disallow overriding of private functions. + + ### 0.5.16 (2020-01-02) Backported Bugfixes: diff --git a/docs/050-breaking-changes.rst b/docs/050-breaking-changes.rst index e45ec6c21..743057032 100644 --- a/docs/050-breaking-changes.rst +++ b/docs/050-breaking-changes.rst @@ -292,8 +292,9 @@ Consider you have the following pre-0.5.0 contract already deployed: :: - // This will not compile with the current version of the compiler pragma solidity ^0.4.25; + // This will report a warning until version 0.4.25 of the compiler + // This will not compile after 0.5.0 contract OldContract { function someOldFunction(uint8 a) { //... @@ -369,8 +370,8 @@ Old version: :: - // This will not compile pragma solidity ^0.4.25; + // This will not compile after 0.5.0 contract OtherContract { uint x; @@ -396,7 +397,7 @@ Old version: // Throw is fine in this version. if (x > 100) throw; - bytes b = new bytes(x); + bytes memory b = new bytes(x); y = -3 >> 1; // y == -1 (wrong, should be -2) do { @@ -431,14 +432,15 @@ New version: :: - pragma solidity >=0.5.0 <0.8.0; + pragma solidity >=0.5.0 <0.5.99; + // This will not compile after 0.6.0 contract OtherContract { uint x; function f(uint y) external { x = y; } - receive() payable external {} + function() payable external {} } contract New { diff --git a/docs/Solidity.g4 b/docs/Solidity.g4 new file mode 100644 index 000000000..8721f47a4 --- /dev/null +++ b/docs/Solidity.g4 @@ -0,0 +1,482 @@ +// Copyright 2020 Gonçalo Sá +// Copyright 2016-2019 Federico Bond +// Licensed under the MIT license. See LICENSE file in the project root for details. + +// This grammar is much less strict than what Solidity currently parses +// to allow this to pass with older versions of Solidity. + +grammar Solidity; + +sourceUnit + : (pragmaDirective | importDirective | structDefinition | enumDefinition | contractDefinition)* EOF ; + +pragmaDirective + : 'pragma' pragmaName pragmaValue ';' ; + +pragmaName + : identifier ; + +pragmaValue + : version | expression ; + +version + : versionConstraint versionConstraint? ; + +versionConstraint + : versionOperator? VersionLiteral ; + +versionOperator + : '^' | '~' | '>=' | '>' | '<' | '<=' | '=' ; + +importDirective + : 'import' StringLiteralFragment ('as' identifier)? ';' + | 'import' ('*' | identifier) ('as' identifier)? 'from' StringLiteralFragment ';' + | 'import' '{' importDeclaration ( ',' importDeclaration )* '}' 'from' StringLiteralFragment ';' ; + +importDeclaration + : identifier ('as' identifier)? ; + +contractDefinition + : 'abstract'? ( 'contract' | 'interface' | 'library' ) identifier + ( 'is' inheritanceSpecifier (',' inheritanceSpecifier )* )? + '{' contractPart* '}' ; + +inheritanceSpecifier + : userDefinedTypeName ( '(' expressionList? ')' )? ; + +contractPart + : stateVariableDeclaration + | usingForDeclaration + | structDefinition + | modifierDefinition + | functionDefinition + | eventDefinition + | enumDefinition ; + +stateVariableDeclaration + : typeName + ( PublicKeyword | InternalKeyword | PrivateKeyword | ConstantKeyword | ImmutableKeyword | overrideSpecifier )* + identifier ('=' expression)? ';' ; + +overrideSpecifier : 'override' ( '(' userDefinedTypeName (',' userDefinedTypeName)* ')' )? ; + +usingForDeclaration + : 'using' identifier 'for' ('*' | typeName) ';' ; + +structDefinition + : 'struct' identifier + '{' ( variableDeclaration ';' (variableDeclaration ';')* )? '}' ; + +modifierDefinition + : 'modifier' identifier parameterList? ( VirtualKeyword | overrideSpecifier )* block ; + +functionDefinition + : functionDescriptor parameterList modifierList returnParameters? ( ';' | block ) ; + +functionDescriptor + : 'function' ( identifier | ReceiveKeyword | FallbackKeyword )? + | ConstructorKeyword + | FallbackKeyword + | ReceiveKeyword ; + +returnParameters + : 'returns' parameterList ; + +modifierList + : ( modifierInvocation | stateMutability | ExternalKeyword + | PublicKeyword | InternalKeyword | PrivateKeyword | VirtualKeyword | overrideSpecifier )* ; + +modifierInvocation + : identifier ( '(' expressionList? ')' )? ; + +eventDefinition + : 'event' identifier eventParameterList AnonymousKeyword? ';' ; + +enumDefinition + : 'enum' identifier '{' enumValue? (',' enumValue)* '}' ; + +enumValue + : identifier ; + +parameterList + : '(' ( parameter (',' parameter)* )? ')' ; + +parameter + : typeName storageLocation? identifier? ; + +eventParameterList + : '(' ( eventParameter (',' eventParameter)* )? ')' ; + +eventParameter + : typeName IndexedKeyword? identifier? ; + +variableDeclaration + : typeName storageLocation? identifier ; + +typeName + : elementaryTypeName + | userDefinedTypeName + | mapping + | typeName '[' expression? ']' + | functionTypeName ; + +userDefinedTypeName + : identifier ( '.' identifier )* ; + +mapping + : 'mapping' '(' (elementaryTypeName | userDefinedTypeName) '=>' typeName ')' ; + +functionTypeName + : 'function' parameterList modifierList returnParameters? ; + +storageLocation + : 'memory' | 'storage' | 'calldata'; + +stateMutability + : PureKeyword | ConstantKeyword | ViewKeyword | PayableKeyword ; + +block + : '{' statement* '}' ; + +statement + : ifStatement + | tryStatement + | whileStatement + | forStatement + | block + | inlineAssemblyStatement + | doWhileStatement + | continueStatement + | breakStatement + | returnStatement + | throwStatement + | emitStatement + | simpleStatement ; + +expressionStatement + : expression ';' ; + +ifStatement + : 'if' '(' expression ')' statement ( 'else' statement )? ; + +tryStatement : 'try' expression returnParameters? block catchClause+ ; + +// In reality catch clauses still are not processed as below +// the identifier can only be a set string: "Error". But plans +// of the Solidity team include possible expansion so we'll +// leave this as is, befitting with the Solidity docs. +catchClause : 'catch' ( identifier? parameterList )? block ; + +whileStatement + : 'while' '(' expression ')' statement ; + +forStatement + : 'for' '(' ( simpleStatement | ';' ) ( expressionStatement | ';' ) expression? ')' statement ; + +simpleStatement + : ( variableDeclarationStatement | expressionStatement ) ; + +inlineAssemblyStatement + : 'assembly' StringLiteralFragment? assemblyBlock ; + +doWhileStatement + : 'do' statement 'while' '(' expression ')' ';' ; + +continueStatement + : 'continue' ';' ; + +breakStatement + : 'break' ';' ; + +returnStatement + : 'return' expression? ';' ; + +// throw is no longer supported by latest Solidity. +throwStatement + : 'throw' ';' ; + +emitStatement + : 'emit' functionCall ';' ; + +// 'var' is no longer supported by latest Solidity. +variableDeclarationStatement + : ( 'var' identifierList | variableDeclaration | '(' variableDeclarationList ')' ) ( '=' expression )? ';'; + +variableDeclarationList + : variableDeclaration? (',' variableDeclaration? )* ; + +identifierList + : '(' ( identifier? ',' )* identifier? ')' ; + +elementaryTypeName + : 'address' PayableKeyword? | 'bool' | 'string' | 'var' | Int | Uint | 'byte' | Byte | Fixed | Ufixed ; + +Int + : 'int' | 'int8' | 'int16' | 'int24' | 'int32' | 'int40' | 'int48' | 'int56' | 'int64' | 'int72' | 'int80' | 'int88' | 'int96' | 'int104' | 'int112' | 'int120' | 'int128' | 'int136' | 'int144' | 'int152' | 'int160' | 'int168' | 'int176' | 'int184' | 'int192' | 'int200' | 'int208' | 'int216' | 'int224' | 'int232' | 'int240' | 'int248' | 'int256' ; + +Uint + : 'uint' | 'uint8' | 'uint16' | 'uint24' | 'uint32' | 'uint40' | 'uint48' | 'uint56' | 'uint64' | 'uint72' | 'uint80' | 'uint88' | 'uint96' | 'uint104' | 'uint112' | 'uint120' | 'uint128' | 'uint136' | 'uint144' | 'uint152' | 'uint160' | 'uint168' | 'uint176' | 'uint184' | 'uint192' | 'uint200' | 'uint208' | 'uint216' | 'uint224' | 'uint232' | 'uint240' | 'uint248' | 'uint256' ; + +Byte + : 'bytes' | 'bytes1' | 'bytes2' | 'bytes3' | 'bytes4' | 'bytes5' | 'bytes6' | 'bytes7' | 'bytes8' | 'bytes9' | 'bytes10' | 'bytes11' | 'bytes12' | 'bytes13' | 'bytes14' | 'bytes15' | 'bytes16' | 'bytes17' | 'bytes18' | 'bytes19' | 'bytes20' | 'bytes21' | 'bytes22' | 'bytes23' | 'bytes24' | 'bytes25' | 'bytes26' | 'bytes27' | 'bytes28' | 'bytes29' | 'bytes30' | 'bytes31' | 'bytes32' ; + +Fixed + : 'fixed' | ( 'fixed' [0-9]+ 'x' [0-9]+ ) ; + +Ufixed + : 'ufixed' | ( 'ufixed' [0-9]+ 'x' [0-9]+ ) ; + +expression + : expression ('++' | '--') + | 'new' typeName + | expression '[' expression? ']' + | expression '[' expression? ':' expression? ']' + | expression '.' identifier + | expression '{' nameValueList '}' + | expression '(' functionCallArguments ')' + | PayableKeyword '(' expression ')' + | '(' expression ')' + | ('++' | '--') expression + | ('+' | '-') expression + | ('after' | 'delete') expression + | '!' expression + | '~' expression + | expression '**' expression + | expression ('*' | '/' | '%') expression + | expression ('+' | '-') expression + | expression ('<<' | '>>') expression + | expression '&' expression + | expression '^' expression + | expression '|' expression + | expression ('<' | '>' | '<=' | '>=') expression + | expression ('==' | '!=') expression + | expression '&&' expression + | expression '||' expression + | expression '?' expression ':' expression + | expression ('=' | '|=' | '^=' | '&=' | '<<=' | '>>=' | '+=' | '-=' | '*=' | '/=' | '%=') expression + | primaryExpression ; + +primaryExpression + : BooleanLiteral + | numberLiteral + | hexLiteral + | stringLiteral + | identifier ('[' ']')? + | TypeKeyword + | tupleExpression + | typeNameExpression ('[' ']')? ; + +expressionList + : expression (',' expression)* ; + +nameValueList + : nameValue (',' nameValue)* ','? ; + +nameValue + : identifier ':' expression ; + +functionCallArguments + : '{' nameValueList? '}' + | expressionList? ; + +functionCall + : expression '(' functionCallArguments ')' ; + +tupleExpression + : '(' ( expression? ( ',' expression? )* ) ')' + | '[' ( expression ( ',' expression )* )? ']' ; + +typeNameExpression + : elementaryTypeName + | userDefinedTypeName ; + +assemblyItem + : identifier + | assemblyBlock + | assemblyExpression + | assemblyLocalDefinition + | assemblyAssignment + | assemblyStackAssignment + | labelDefinition + | assemblySwitch + | assemblyFunctionDefinition + | assemblyFor + | assemblyIf + | BreakKeyword + | ContinueKeyword + | LeaveKeyword + | subAssembly + | numberLiteral + | stringLiteral + | hexLiteral ; + +assemblyBlock + : '{' assemblyItem* '}' ; + +assemblyExpression + : assemblyCall | assemblyLiteral ; + +assemblyCall + : ( 'return' | 'address' | 'byte' | identifier ) ( '(' assemblyExpression? ( ',' assemblyExpression )* ')' )? ; + +assemblyLocalDefinition + : 'let' assemblyIdentifierList ( ':=' assemblyExpression )? ; + +assemblyAssignment + : assemblyIdentifierList ':=' assemblyExpression ; + +assemblyIdentifierList + : identifier ( ',' identifier )* ; + +assemblyStackAssignment + : '=:' identifier ; + +labelDefinition + : identifier ':' ; + +assemblySwitch + : 'switch' assemblyExpression assemblyCase* ; + +assemblyCase + : 'case' assemblyLiteral assemblyType? assemblyBlock + | 'default' assemblyBlock ; + +assemblyFunctionDefinition + : 'function' identifier '(' assemblyTypedVariableList? ')' + assemblyFunctionReturns? assemblyBlock ; + +assemblyFunctionReturns + : ( '-' '>' assemblyTypedVariableList ) ; + +assemblyFor + : 'for' assemblyBlock assemblyExpression assemblyBlock assemblyBlock ; + +assemblyIf + : 'if' assemblyExpression assemblyBlock ; + +assemblyLiteral + : ( stringLiteral | DecimalNumber | HexNumber | hexLiteral | BooleanLiteral ) assemblyType? ; + +assemblyTypedVariableList + : identifier assemblyType? ( ',' assemblyTypedVariableList )? ; + +assemblyType + : ':' identifier ; + +subAssembly + : 'assembly' identifier assemblyBlock ; + +numberLiteral + : (DecimalNumber | HexNumber) NumberUnit? ; + +identifier + : ('from' | 'calldata' | 'address' | Identifier) ; + +BooleanLiteral + : 'true' | 'false' ; + +DecimalNumber + : ( DecimalDigits | (DecimalDigits? '.' DecimalDigits) ) ( [eE] '-'? DecimalDigits )? ; + +fragment +DecimalDigits + : [0-9] ( '_'? [0-9] )* ; + +HexNumber + : '0' [xX] HexDigits ; + +fragment +HexDigits + : HexCharacter ( '_'? HexCharacter )* ; + +NumberUnit + : 'wei' | 'szabo' | 'finney' | 'ether' + | 'seconds' | 'minutes' | 'hours' | 'days' | 'weeks' | 'years' ; + +HexLiteralFragment + : 'hex' (('"' HexDigits? '"') | ('\'' HexDigits? '\'')) ; + +hexLiteral : HexLiteralFragment+ ; + +fragment +HexPair + : HexCharacter HexCharacter ; + +fragment +HexCharacter + : [0-9A-Fa-f] ; + +ReservedKeyword + : 'after' + | 'case' + | 'default' + | 'final' + | 'in' + | 'inline' + | 'let' + | 'match' + | 'null' + | 'of' + | 'relocatable' + | 'static' + | 'switch' + | 'typeof' ; + +AnonymousKeyword : 'anonymous' ; +BreakKeyword : 'break' ; +ConstantKeyword : 'constant' ; +ImmutableKeyword : 'immutable' ; +ContinueKeyword : 'continue' ; +LeaveKeyword : 'leave' ; +ExternalKeyword : 'external' ; +IndexedKeyword : 'indexed' ; +InternalKeyword : 'internal' ; +PayableKeyword : 'payable' ; +PrivateKeyword : 'private' ; +PublicKeyword : 'public' ; +VirtualKeyword : 'virtual' ; +PureKeyword : 'pure' ; +TypeKeyword : 'type' ; +ViewKeyword : 'view' ; + +ConstructorKeyword : 'constructor' ; +FallbackKeyword : 'fallback' ; +ReceiveKeyword : 'receive' ; + +Identifier + : IdentifierStart IdentifierPart* ; + +fragment +IdentifierStart + : [a-zA-Z$_] ; + +fragment +IdentifierPart + : [a-zA-Z0-9$_] ; + +stringLiteral + : StringLiteralFragment+ ; + +StringLiteralFragment + : '"' DoubleQuotedStringCharacter* '"' + | '\'' SingleQuotedStringCharacter* '\'' ; + +fragment +DoubleQuotedStringCharacter + : ~["\r\n\\] | ('\\' .) ; + +fragment +SingleQuotedStringCharacter + : ~['\r\n\\] | ('\\' .) ; + +VersionLiteral + : [0-9]+ '.' [0-9]+ ('.' [0-9]+)? ; + +WS + : [ \t\r\n\u000C]+ -> skip ; + +COMMENT + : '/*' .*? '*/' -> channel(HIDDEN) ; + +LINE_COMMENT + : '//' ~[\r\n]* -> channel(HIDDEN) ; diff --git a/docs/abi-spec.rst b/docs/abi-spec.rst index f4bfc6b70..053b6dad4 100644 --- a/docs/abi-spec.rst +++ b/docs/abi-spec.rst @@ -234,7 +234,6 @@ Given the contract: pragma solidity >=0.4.16 <0.8.0; - contract Foo { function bar(bytes3[2] memory) public pure {} function baz(uint32 x, bool y) public pure returns (bool r) { r = x > 32 || y; } @@ -583,12 +582,11 @@ As an example, the code pragma solidity >=0.4.19 <0.8.0; pragma experimental ABIEncoderV2; - contract Test { struct S { uint a; uint[] b; T[] c; } struct T { uint x; uint y; } - function f(S memory s, T memory t, uint a) public {} - function g() public returns (S memory s, T memory t, uint a) {} + function f(S memory, T memory, uint) public pure {} + function g() public pure returns (S memory, T memory, uint) {} } would result in the JSON: diff --git a/docs/assembly.rst b/docs/assembly.rst index c92229e92..c280e0d32 100644 --- a/docs/assembly.rst +++ b/docs/assembly.rst @@ -41,7 +41,7 @@ without a compiler change. .. code:: - pragma solidity >=0.4.0 <0.8.0; + pragma solidity >=0.4.16 <0.8.0; library GetCode { function at(address _addr) public view returns (bytes memory o_code) { @@ -136,7 +136,7 @@ Local Solidity variables are available for assignments, for example: .. code:: - pragma solidity >=0.4.11 <0.8.0; + pragma solidity >=0.4.16 <0.8.0; contract C { uint b; diff --git a/docs/bugs.json b/docs/bugs.json index 66f1808ab..388bd4b56 100644 --- a/docs/bugs.json +++ b/docs/bugs.json @@ -10,6 +10,14 @@ "yulOptimizer": true } }, + { + "name": "privateCanBeOverridden", + "summary": "Private methods can be overridden by inheriting contracts.", + "description": "While private methods of base contracts are not visible and cannot be called directly from the derived contract, it is still possible to declare a function of the same name and type and thus change the behaviour of the base contract's function.", + "introduced": "0.3.0", + "fixed": "0.5.17", + "severity": "low" + }, { "name": "YulOptimizerRedundantAssignmentBreakContinue0.5", "summary": "The Yul optimizer can remove essential assignments to variables declared inside for loops when Yul's continue or break statement is used. You are unlikely to be affected if you do not use inline assembly with for loops and continue and break statements.", diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json index dc32e2687..d8daf565e 100644 --- a/docs/bugs_by_version.json +++ b/docs/bugs_by_version.json @@ -211,6 +211,7 @@ }, "0.3.0": { "bugs": [ + "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", "NestedArrayFunctionCallDecoder", @@ -232,6 +233,7 @@ }, "0.3.1": { "bugs": [ + "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", "NestedArrayFunctionCallDecoder", @@ -252,6 +254,7 @@ }, "0.3.2": { "bugs": [ + "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", "NestedArrayFunctionCallDecoder", @@ -272,6 +275,7 @@ }, "0.3.3": { "bugs": [ + "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", "NestedArrayFunctionCallDecoder", @@ -291,6 +295,7 @@ }, "0.3.4": { "bugs": [ + "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", "NestedArrayFunctionCallDecoder", @@ -310,6 +315,7 @@ }, "0.3.5": { "bugs": [ + "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", "NestedArrayFunctionCallDecoder", @@ -329,6 +335,7 @@ }, "0.3.6": { "bugs": [ + "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", "NestedArrayFunctionCallDecoder", @@ -346,6 +353,7 @@ }, "0.4.0": { "bugs": [ + "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", "NestedArrayFunctionCallDecoder", @@ -363,6 +371,7 @@ }, "0.4.1": { "bugs": [ + "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", "NestedArrayFunctionCallDecoder", @@ -380,6 +389,7 @@ }, "0.4.10": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "UninitializedFunctionPointerInConstructor_0.4.x", "IncorrectEventSignatureInLibraries_0.4.x", @@ -395,6 +405,7 @@ }, "0.4.11": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "UninitializedFunctionPointerInConstructor_0.4.x", "IncorrectEventSignatureInLibraries_0.4.x", @@ -409,6 +420,7 @@ }, "0.4.12": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "UninitializedFunctionPointerInConstructor_0.4.x", "IncorrectEventSignatureInLibraries_0.4.x", @@ -422,6 +434,7 @@ }, "0.4.13": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "UninitializedFunctionPointerInConstructor_0.4.x", "IncorrectEventSignatureInLibraries_0.4.x", @@ -435,6 +448,7 @@ }, "0.4.14": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "UninitializedFunctionPointerInConstructor_0.4.x", "IncorrectEventSignatureInLibraries_0.4.x", @@ -447,6 +461,7 @@ }, "0.4.15": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "UninitializedFunctionPointerInConstructor_0.4.x", "IncorrectEventSignatureInLibraries_0.4.x", @@ -458,6 +473,7 @@ }, "0.4.16": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", "DynamicConstructorArgumentsClippedABIV2", @@ -471,6 +487,7 @@ }, "0.4.17": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", "DynamicConstructorArgumentsClippedABIV2", @@ -485,6 +502,7 @@ }, "0.4.18": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", "DynamicConstructorArgumentsClippedABIV2", @@ -498,6 +516,7 @@ }, "0.4.19": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", "DynamicConstructorArgumentsClippedABIV2", @@ -512,6 +531,7 @@ }, "0.4.2": { "bugs": [ + "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", "NestedArrayFunctionCallDecoder", @@ -528,6 +548,7 @@ }, "0.4.20": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", "DynamicConstructorArgumentsClippedABIV2", @@ -542,6 +563,7 @@ }, "0.4.21": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", "DynamicConstructorArgumentsClippedABIV2", @@ -556,6 +578,7 @@ }, "0.4.22": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", "DynamicConstructorArgumentsClippedABIV2", @@ -570,6 +593,7 @@ }, "0.4.23": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", "DynamicConstructorArgumentsClippedABIV2", @@ -583,6 +607,7 @@ }, "0.4.24": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", "DynamicConstructorArgumentsClippedABIV2", @@ -596,6 +621,7 @@ }, "0.4.25": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", "DynamicConstructorArgumentsClippedABIV2", @@ -607,6 +633,7 @@ }, "0.4.26": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", "DynamicConstructorArgumentsClippedABIV2" @@ -615,6 +642,7 @@ }, "0.4.3": { "bugs": [ + "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", "NestedArrayFunctionCallDecoder", @@ -630,6 +658,7 @@ }, "0.4.4": { "bugs": [ + "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", "NestedArrayFunctionCallDecoder", @@ -644,6 +673,7 @@ }, "0.4.5": { "bugs": [ + "privateCanBeOverridden", "UninitializedFunctionPointerInConstructor_0.4.x", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", @@ -660,6 +690,7 @@ }, "0.4.6": { "bugs": [ + "privateCanBeOverridden", "UninitializedFunctionPointerInConstructor_0.4.x", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", @@ -675,6 +706,7 @@ }, "0.4.7": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "UninitializedFunctionPointerInConstructor_0.4.x", "IncorrectEventSignatureInLibraries_0.4.x", @@ -690,6 +722,7 @@ }, "0.4.8": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "UninitializedFunctionPointerInConstructor_0.4.x", "IncorrectEventSignatureInLibraries_0.4.x", @@ -705,6 +738,7 @@ }, "0.4.9": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "UninitializedFunctionPointerInConstructor_0.4.x", "IncorrectEventSignatureInLibraries_0.4.x", @@ -720,6 +754,7 @@ }, "0.5.0": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", "DynamicConstructorArgumentsClippedABIV2", @@ -731,6 +766,7 @@ }, "0.5.1": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", "DynamicConstructorArgumentsClippedABIV2", @@ -742,6 +778,7 @@ }, "0.5.10": { "bugs": [ + "privateCanBeOverridden", "YulOptimizerRedundantAssignmentBreakContinue0.5", "ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers" ], @@ -749,24 +786,28 @@ }, "0.5.11": { "bugs": [ + "privateCanBeOverridden", "YulOptimizerRedundantAssignmentBreakContinue0.5" ], "released": "2019-08-12" }, "0.5.12": { "bugs": [ + "privateCanBeOverridden", "YulOptimizerRedundantAssignmentBreakContinue0.5" ], "released": "2019-10-01" }, "0.5.13": { "bugs": [ + "privateCanBeOverridden", "YulOptimizerRedundantAssignmentBreakContinue0.5" ], "released": "2019-11-14" }, "0.5.14": { "bugs": [ + "privateCanBeOverridden", "YulOptimizerRedundantAssignmentBreakContinue0.5", "ABIEncoderV2LoopYulOptimizer" ], @@ -774,16 +815,24 @@ }, "0.5.15": { "bugs": [ + "privateCanBeOverridden", "YulOptimizerRedundantAssignmentBreakContinue0.5" ], "released": "2019-12-17" }, "0.5.16": { - "bugs": [], + "bugs": [ + "privateCanBeOverridden" + ], "released": "2020-01-02" }, + "0.5.17": { + "bugs": [], + "released": "2020-03-17" + }, "0.5.2": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", "DynamicConstructorArgumentsClippedABIV2", @@ -795,6 +844,7 @@ }, "0.5.3": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", "DynamicConstructorArgumentsClippedABIV2", @@ -806,6 +856,7 @@ }, "0.5.4": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", "DynamicConstructorArgumentsClippedABIV2", @@ -817,6 +868,7 @@ }, "0.5.5": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", "DynamicConstructorArgumentsClippedABIV2", @@ -830,6 +882,7 @@ }, "0.5.6": { "bugs": [ + "privateCanBeOverridden", "ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", @@ -843,6 +896,7 @@ }, "0.5.7": { "bugs": [ + "privateCanBeOverridden", "ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", @@ -854,6 +908,7 @@ }, "0.5.8": { "bugs": [ + "privateCanBeOverridden", "YulOptimizerRedundantAssignmentBreakContinue0.5", "ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers", "SignedArrayStorageCopy", @@ -864,6 +919,7 @@ }, "0.5.9": { "bugs": [ + "privateCanBeOverridden", "YulOptimizerRedundantAssignmentBreakContinue0.5", "ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers", "SignedArrayStorageCopy", diff --git a/docs/contracts/abstract-contracts.rst b/docs/contracts/abstract-contracts.rst index b23cc9e8c..8e7faad32 100644 --- a/docs/contracts/abstract-contracts.rst +++ b/docs/contracts/abstract-contracts.rst @@ -13,7 +13,7 @@ This can be done by using the ``abstract`` keyword as shown in the following exa defined as abstract, because the function ``utterance()`` was defined, but no implementation was provided (no implementation body ``{ }`` was given).:: - pragma solidity >=0.4.0 <0.8.0; + pragma solidity >=0.6.0 <0.8.0; abstract contract Feline { function utterance() public virtual returns (bytes32); diff --git a/docs/contracts/functions.rst b/docs/contracts/functions.rst index 8100d1ec2..3195b5a40 100644 --- a/docs/contracts/functions.rst +++ b/docs/contracts/functions.rst @@ -335,7 +335,7 @@ operations as long as there is enough gas passed on to it. :: - pragma solidity >0.6.1 <0.8.0; + pragma solidity >=0.6.2 <0.8.0; contract Test { // This function is called for all messages sent to diff --git a/docs/contracts/inheritance.rst b/docs/contracts/inheritance.rst index c073310d0..761d20cad 100644 --- a/docs/contracts/inheritance.rst +++ b/docs/contracts/inheritance.rst @@ -154,7 +154,7 @@ A call to ``Final.destroy()`` will call ``Base2.destroy`` because we specify it explicitly in the final override, but this function will bypass ``Base1.destroy``. The way around this is to use ``super``:: - pragma solidity >=0.4.22 <0.8.0; + pragma solidity >=0.6.0 <0.8.0; contract owned { constructor() public { owner = msg.sender; } @@ -204,7 +204,7 @@ use the ``override`` keyword in the function header as shown in this example: :: - pragma solidity >=0.5.0 <0.8.0; + pragma solidity >=0.6.0 <0.8.0; contract Base { @@ -227,7 +227,7 @@ bases, it has to explicitly override it: :: - pragma solidity >=0.5.0 <0.8.0; + pragma solidity >=0.6.0 <0.8.0; contract Base1 { @@ -253,7 +253,7 @@ that already overrides all other functions. :: - pragma solidity >=0.5.0 <0.8.0; + pragma solidity >=0.6.0 <0.8.0; contract A { function f() public pure{} } contract B is A {} @@ -293,7 +293,7 @@ of the variable: :: - pragma solidity >=0.5.0 <0.8.0; + pragma solidity >=0.6.0 <0.8.0; contract A { @@ -324,7 +324,7 @@ and the ``override`` keyword must be used in the overriding modifier: :: - pragma solidity >=0.5.0 <0.8.0; + pragma solidity >=0.6.0 <0.8.0; contract Base { @@ -342,7 +342,7 @@ explicitly: :: - pragma solidity >=0.5.0 <0.8.0; + pragma solidity >=0.6.0 <0.8.0; contract Base1 { @@ -498,7 +498,7 @@ One area where inheritance linearization is especially important and perhaps not :: - pragma solidity >=0.4.0 <0.8.0; + pragma solidity >=0.4.22 <0.8.0; contract Base1 { constructor() public {} diff --git a/docs/contracts/interfaces.rst b/docs/contracts/interfaces.rst index 1b69aba4c..9265a50cb 100644 --- a/docs/contracts/interfaces.rst +++ b/docs/contracts/interfaces.rst @@ -22,7 +22,7 @@ Interfaces are denoted by their own keyword: :: - pragma solidity >=0.5.0 <0.8.0; + pragma solidity >=0.6.2 <0.8.0; interface Token { enum TokenType { Fungible, NonFungible } @@ -42,7 +42,7 @@ inheritance. :: - pragma solidity >0.6.1 <0.8.0; + pragma solidity >=0.6.2 <0.8.0; interface ParentA { function test() external returns (uint256); diff --git a/docs/contracts/libraries.rst b/docs/contracts/libraries.rst index f1d48855f..df4ce59ae 100644 --- a/docs/contracts/libraries.rst +++ b/docs/contracts/libraries.rst @@ -47,12 +47,14 @@ more advanced example to implement a set). :: - pragma solidity >=0.4.22 <0.8.0; + pragma solidity >=0.6.0 <0.8.0; // We define a new struct datatype that will be used to // hold its data in the calling contract. - struct Data { mapping(uint => bool) flags; } + struct Data { + mapping(uint => bool) flags; + } library Set { // Note that the first parameter is of type "storage @@ -123,7 +125,7 @@ custom types without the overhead of external function calls: :: - pragma solidity >=0.4.16 <0.8.0; + pragma solidity >=0.6.0 <0.8.0; struct bigint { uint[] limbs; @@ -237,7 +239,7 @@ Its value can be obtained from Solidity using the ``.selector`` member as follow :: - pragma solidity >0.5.13 <0.8.0; + pragma solidity >=0.5.14 <0.8.0; library L { function f(uint256) external {} diff --git a/docs/contracts/using-for.rst b/docs/contracts/using-for.rst index 151ad3b72..e68eeb3b6 100644 --- a/docs/contracts/using-for.rst +++ b/docs/contracts/using-for.rst @@ -29,7 +29,7 @@ may only be used inside a contract, not inside any of its functions. Let us rewrite the set example from the :ref:`libraries` in this way:: - pragma solidity >=0.4.16 <0.8.0; + pragma solidity >=0.6.0 <0.8.0; // This is the same code as before, just without comments diff --git a/docs/contracts/visibility-and-getters.rst b/docs/contracts/visibility-and-getters.rst index bf37bc5da..2a6869adf 100644 --- a/docs/contracts/visibility-and-getters.rst +++ b/docs/contracts/visibility-and-getters.rst @@ -68,7 +68,7 @@ In the following example, ``D``, can call ``c.getData()`` to retrieve the value :: - pragma solidity >=0.4.0 <0.8.0; + pragma solidity >=0.4.16 <0.8.0; contract C { uint private data; @@ -112,7 +112,7 @@ when they are declared. :: - pragma solidity >=0.4.0 <0.8.0; + pragma solidity >=0.4.16 <0.8.0; contract C { uint public data = 42; @@ -151,7 +151,7 @@ to write a function, for example: :: - pragma solidity >=0.4.0 <0.8.0; + pragma solidity >=0.4.16 <0.8.0; contract arrayExample { // public state variable diff --git a/docs/control-structures.rst b/docs/control-structures.rst index 491370e72..a633b9b96 100644 --- a/docs/control-structures.rst +++ b/docs/control-structures.rst @@ -41,7 +41,7 @@ Internal Function Calls Functions of the current contract can be called directly ("internally"), also recursively, as seen in this nonsensical example:: - pragma solidity >=0.4.16 <0.8.0; + pragma solidity >=0.4.22 <0.8.0; contract C { function g(uint a) public pure returns (uint ret) { return a + f(); } @@ -82,7 +82,7 @@ to the total balance of that contract: :: - pragma solidity >=0.4.0 <0.8.0; + pragma solidity >=0.6.2 <0.8.0; contract InfoFeed { function info() public payable returns (uint ret) { return 42; } @@ -160,7 +160,7 @@ Those parameters will still be present on the stack, but they are inaccessible. :: - pragma solidity >=0.4.16 <0.8.0; + pragma solidity >=0.4.22 <0.8.0; contract C { // omitted name for parameter @@ -183,7 +183,7 @@ is compiled so recursive creation-dependencies are not possible. :: - pragma solidity >=0.5.0 <0.8.0; + pragma solidity >=0.6.2 <0.8.0; contract D { uint public x; @@ -238,7 +238,7 @@ which only need to be created if there is a dispute. :: - pragma solidity >0.6.1 <0.8.0; + pragma solidity >=0.6.2 <0.8.0; contract D { uint public x; @@ -307,7 +307,7 @@ groupings of expressions. :: - pragma solidity >0.4.23 <0.8.0; + pragma solidity >=0.5.0 <0.8.0; contract C { uint index; @@ -352,7 +352,7 @@ because only a reference and not a copy is passed. :: - pragma solidity >=0.4.16 <0.8.0; + pragma solidity >=0.4.22 <0.8.0; contract C { uint[20] x; diff --git a/docs/examples/blind-auction.rst b/docs/examples/blind-auction.rst index 185b1a342..bff397ee3 100644 --- a/docs/examples/blind-auction.rst +++ b/docs/examples/blind-auction.rst @@ -24,7 +24,7 @@ to receive their money - contracts cannot activate themselves. :: - pragma solidity >=0.4.22 <0.8.0; + pragma solidity >=0.5.0 <0.8.0; contract SimpleAuction { // Parameters of the auction. Times are either diff --git a/docs/examples/micropayment.rst b/docs/examples/micropayment.rst index 38402f43a..8d3b2e1f3 100644 --- a/docs/examples/micropayment.rst +++ b/docs/examples/micropayment.rst @@ -338,7 +338,7 @@ The full contract :: - pragma solidity >=0.4.24 <0.8.0; + pragma solidity >=0.5.0 <0.8.0; contract SimplePaymentChannel { address payable public sender; // The account sending payments. diff --git a/docs/examples/modular.rst b/docs/examples/modular.rst index 0e2dcb106..1f7a725b9 100644 --- a/docs/examples/modular.rst +++ b/docs/examples/modular.rst @@ -19,7 +19,7 @@ and the sum of all balances is an invariant across the lifetime of the contract. :: - pragma solidity >=0.4.22 <0.8.0; + pragma solidity >=0.5.0 <0.8.0; library Balances { function move(mapping(address => uint256) storage balances, address from, address to, uint amount) internal { diff --git a/docs/examples/safe-remote.rst b/docs/examples/safe-remote.rst index 84a7aace4..d6f27bf8a 100644 --- a/docs/examples/safe-remote.rst +++ b/docs/examples/safe-remote.rst @@ -25,7 +25,7 @@ you can use state machine-like constructs inside a contract. :: - pragma solidity >=0.4.22 <0.8.0; + pragma solidity >=0.5.0 <0.8.0; contract Purchase { uint public value; diff --git a/docs/introduction-to-smart-contracts.rst b/docs/introduction-to-smart-contracts.rst index 1f337bae6..17740fcda 100644 --- a/docs/introduction-to-smart-contracts.rst +++ b/docs/introduction-to-smart-contracts.rst @@ -17,7 +17,7 @@ Storage Example :: - pragma solidity >=0.4.0 <0.8.0; + pragma solidity >=0.4.16 <0.8.0; contract SimpleStorage { uint storedData; diff --git a/docs/layout-of-source-files.rst b/docs/layout-of-source-files.rst index dc9bc8287..6b6772d74 100644 --- a/docs/layout-of-source-files.rst +++ b/docs/layout-of-source-files.rst @@ -284,7 +284,7 @@ for the two function parameters and two return variables. :: - pragma solidity >=0.4.0 <0.8.0; + pragma solidity >=0.4.21 <0.8.0; /** @title Shape calculator. */ contract ShapeCalculator { diff --git a/docs/security-considerations.rst b/docs/security-considerations.rst index 85e81d7bb..58c3848d4 100644 --- a/docs/security-considerations.rst +++ b/docs/security-considerations.rst @@ -81,7 +81,7 @@ as it uses ``call`` which forwards all remaining gas by default: :: - pragma solidity >=0.4.0 <0.8.0; + pragma solidity >=0.6.2 <0.8.0; // THIS CONTRACT CONTAINS A BUG - DO NOT USE contract Fund { @@ -277,7 +277,7 @@ field of a ``struct`` that is the base type of a dynamic storage array. The :: - pragma solidity >=0.5.0 <0.8.0; + pragma solidity >=0.6.0 <0.8.0; contract Map { mapping (uint => uint)[] array; diff --git a/docs/style-guide.rst b/docs/style-guide.rst index c083dc102..2b0bfee34 100644 --- a/docs/style-guide.rst +++ b/docs/style-guide.rst @@ -109,7 +109,7 @@ Yes:: No:: - pragma solidity >=0.4.0 <0.8.0; + pragma solidity >=0.6.0 <0.8.0; abstract contract A { function spam() virtual pure public; @@ -326,7 +326,7 @@ Yes:: No:: - pragma solidity >=0.4.0 <0.8.0; + pragma solidity >=0.6.0 <0.8.0; contract A { @@ -745,7 +745,7 @@ manner as modifiers if the function declaration is long or hard to read. Yes:: - pragma solidity >=0.4.0 <0.8.0; + pragma solidity >=0.4.22 <0.8.0; // Base contracts just to make this compile contract B { @@ -777,7 +777,7 @@ Yes:: No:: - pragma solidity >=0.4.0 <0.8.0; + pragma solidity >=0.4.22 <0.8.0; // Base contracts just to make this compile @@ -1000,7 +1000,7 @@ As shown in the example below, if the contract name is `Congress` and the librar Yes:: - pragma solidity >=0.4.0 <0.8.0; + pragma solidity >=0.4.22 <0.8.0; // Owned.sol @@ -1034,7 +1034,7 @@ and in ``Congress.sol``:: No:: - pragma solidity >=0.4.0 <0.8.0; + pragma solidity >=0.4.22 <0.8.0; // owned.sol @@ -1138,7 +1138,7 @@ multiline comment starting with `/**` and ending with `*/`. For example, the contract from `a simple smart contract `_ with the comments added looks like the one below:: - pragma solidity >=0.4.0 <0.8.0; + pragma solidity >=0.4.16 <0.8.0; /// @author The Solidity Team diff --git a/docs/types/mapping-types.rst b/docs/types/mapping-types.rst index 605929a1f..65f060ead 100644 --- a/docs/types/mapping-types.rst +++ b/docs/types/mapping-types.rst @@ -66,7 +66,7 @@ The example below uses ``_allowances`` to record the amount someone else is allo :: - pragma solidity >=0.4.0 <0.8.0; + pragma solidity >=0.4.22 <0.8.0; contract MappingExample { @@ -120,7 +120,7 @@ the ``sum`` function iterates over to sum all the values. :: - pragma solidity >=0.5.99 <0.8.0; + pragma solidity >=0.6.0 <0.8.0; struct IndexValue { uint keyIndex; uint value; } struct KeyFlag { uint key; bool deleted; } diff --git a/docs/types/reference-types.rst b/docs/types/reference-types.rst index ce9ef9b3a..8796396df 100644 --- a/docs/types/reference-types.rst +++ b/docs/types/reference-types.rst @@ -57,7 +57,7 @@ Data locations are not only relevant for persistency of data, but also for the s :: - pragma solidity >=0.4.0 <0.8.0; + pragma solidity >=0.5.0 <0.8.0; contract C { // The data location of x is storage. @@ -268,7 +268,7 @@ Array Members :: - pragma solidity >=0.4.16 <0.8.0; + pragma solidity >=0.6.0 <0.8.0; contract ArrayContract { uint[2**20] m_aLotOfIntegers; @@ -400,7 +400,7 @@ Array slices are useful to ABI-decode secondary data passed in function paramete :: - pragma solidity >=0.4.99 <0.8.0; + pragma solidity >=0.6.0 <0.8.0; contract Proxy { /// Address of the client contract managed by proxy i.e., this contract @@ -437,7 +437,7 @@ shown in the following example: :: - pragma solidity >=0.4.11 <0.8.0; + pragma solidity >=0.6.0 <0.8.0; // Defines a new type with two fields. // Declaring a struct outside of a contract allows diff --git a/docs/types/value-types.rst b/docs/types/value-types.rst index 595075907..98c3336c4 100644 --- a/docs/types/value-types.rst +++ b/docs/types/value-types.rst @@ -300,6 +300,11 @@ All three functions ``call``, ``delegatecall`` and ``staticcall`` are very low-l The ``gas`` option is available on all three methods, while the ``value`` option is not supported for ``delegatecall``. +.. note:: + It is best to avoid relying on hardcoded gas values in your smart contract code, + regardless of whether state is read from or written to, as this can have many pitfalls. + Also, access to gas might change in the future. + .. note:: All contracts can be converted to ``address`` type, so it is possible to query the balance of the current contract using ``address(this).balance``. @@ -645,7 +650,7 @@ External (or public) functions have the following members: Example that shows how to use the members:: - pragma solidity >=0.4.16 <0.8.0; + pragma solidity >=0.6.0 <0.8.0; // This will report a warning contract Example { @@ -665,7 +670,6 @@ Example that shows how to use internal function types:: pragma solidity >=0.4.16 <0.8.0; - library ArrayUtils { // internal functions can be used in internal library functions because // they will be part of the same code context diff --git a/docs/using-the-compiler.rst b/docs/using-the-compiler.rst index eb4ddf0c6..12fe4b3f9 100644 --- a/docs/using-the-compiler.rst +++ b/docs/using-the-compiler.rst @@ -687,7 +687,7 @@ The command above applies all changes as shown below. Please review them careful .. code-block:: none - pragma solidity >0.4.23; + pragma solidity >=0.6.0 <0.7.0; abstract contract Updateable { function run() public view virtual returns (bool); diff --git a/docs/yul.rst b/docs/yul.rst index 93bfe48a9..c6fb28986 100644 --- a/docs/yul.rst +++ b/docs/yul.rst @@ -111,7 +111,7 @@ Stand-Alone Usage ================= You can use Yul in its stand-alone form in the EVM dialect using the Solidity compiler. -This will use the `Yul object notation `_ so that it is possible to refer +This will use the :ref:`Yul object notation ` so that it is possible to refer to code as data to deploy contracts. This Yul mode is available for the commandline compiler (use ``--strict-assembly``) and for the :ref:`standard-json interface `: @@ -146,7 +146,7 @@ so you can e.g. use ``//`` and ``/* */`` to denote comments. There is one exception: Identifiers in Yul can contain dots: ``.``. Yul can specify "objects" that consist of code, data and sub-objects. -Please see `Yul Objects `_ below for details on that. +Please see :ref:`Yul Objects ` below for details on that. In this section, we are only concerned with the code part of such an object. This code part always consists of a curly-braces delimited block. Most tools support specifying just a code block diff --git a/libsolidity/analysis/DocStringAnalyser.cpp b/libsolidity/analysis/DocStringAnalyser.cpp index e802c4204..ee0a39163 100644 --- a/libsolidity/analysis/DocStringAnalyser.cpp +++ b/libsolidity/analysis/DocStringAnalyser.cpp @@ -153,7 +153,7 @@ void DocStringAnalyser::parseDocStrings( appendError( _node.documentation()->location(), "Documentation tag \"@" + docTag.first + " " + docTag.second.content + "\"" + - " exceedes the number of return parameters." + " exceeds the number of return parameters." ); else { diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index 6867f049c..8ea07f182 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -328,6 +328,8 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable) if (_variable.isConstant() && !_variable.isStateVariable()) m_errorReporter.declarationError(_variable.location(), "The \"constant\" keyword can only be used for state variables."); + if (_variable.immutable() && !_variable.isStateVariable()) + m_errorReporter.declarationError(_variable.location(), "The \"immutable\" keyword can only be used for state variables."); if (!_variable.typeName()) { @@ -394,7 +396,7 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable) else if (_variable.isStateVariable()) { solAssert(varLoc == Location::Unspecified, ""); - typeLoc = _variable.isConstant() ? DataLocation::Memory : DataLocation::Storage; + typeLoc = (_variable.isConstant() || _variable.immutable()) ? DataLocation::Memory : DataLocation::Storage; } else if ( dynamic_cast(_variable.scope()) || diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 5cf003bed..1345fbf90 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -480,6 +480,10 @@ bool TypeChecker::visit(VariableDeclaration const& _variable) "Initial value for constant variable has to be compile-time constant." ); } + else if (_variable.immutable()) + if (!_variable.type()->isValueType()) + m_errorReporter.typeError(_variable.location(), "Immutable variables cannot have a non-value type."); + if (!_variable.isStateVariable()) { if (varType->dataStoredIn(DataLocation::Memory) || varType->dataStoredIn(DataLocation::CallData)) @@ -641,16 +645,21 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) if (auto var = dynamic_cast(declaration)) { solAssert(var->type(), "Expected variable type!"); + if (var->immutable()) + { + m_errorReporter.typeError(_identifier.location, "Assembly access to immutable variables is not supported."); + return size_t(-1); + } if (var->isConstant()) { - var = rootVariableDeclaration(*var); + var = rootConstVariableDeclaration(*var); - if (!var->value()) + if (var && !var->value()) { m_errorReporter.typeError(_identifier.location, "Constant has no value."); return size_t(-1); } - else if (!type(*var)->isValueType() || ( + else if (!var || !type(*var)->isValueType() || ( dynamic_cast(var->value().get()) == nullptr && type(*var->value())->category() != Type::Category::RationalNumber )) diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index 6b03c7b58..a76e6e274 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -508,8 +508,6 @@ set VariableDeclaration::allowedDataLocations() c if (!hasReferenceOrMappingType() || isStateVariable() || isEventParameter()) return set{ Location::Unspecified }; - else if (isStateVariable() && isConstant()) - return set{ Location::Memory }; else if (isExternalCallableParameter()) { set locations{ Location::CallData }; diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index adb957cfe..052970bc8 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -879,6 +879,7 @@ public: bool isStateVariable() const { return m_isStateVariable; } bool isIndexed() const { return m_isIndexed; } bool isConstant() const { return m_constantness == Constantness::Constant; } + bool immutable() const { return m_constantness == Constantness::Immutable; } ASTPointer const& overrides() const { return m_overrides; } Location referenceLocation() const { return m_location; } /// @returns a set of allowed storage locations for the variable. diff --git a/libsolidity/ast/ASTUtils.cpp b/libsolidity/ast/ASTUtils.cpp index d903a1b4b..483b75301 100644 --- a/libsolidity/ast/ASTUtils.cpp +++ b/libsolidity/ast/ASTUtils.cpp @@ -21,7 +21,7 @@ namespace solidity::frontend { -VariableDeclaration const* rootVariableDeclaration(VariableDeclaration const& _varDecl) +VariableDeclaration const* rootConstVariableDeclaration(VariableDeclaration const& _varDecl) { solAssert(_varDecl.isConstant(), "Constant variable expected"); @@ -30,7 +30,8 @@ VariableDeclaration const* rootVariableDeclaration(VariableDeclaration const& _v while ((identifier = dynamic_cast(rootDecl->value().get()))) { auto referencedVarDecl = dynamic_cast(identifier->annotation().referencedDeclaration); - solAssert(referencedVarDecl && referencedVarDecl->isConstant(), "Identifier is not referencing a variable declaration"); + if (!referencedVarDecl || !referencedVarDecl->isConstant()) + return nullptr; rootDecl = referencedVarDecl; } return rootDecl; diff --git a/libsolidity/ast/ASTUtils.h b/libsolidity/ast/ASTUtils.h index 7624080a9..af77b60f1 100644 --- a/libsolidity/ast/ASTUtils.h +++ b/libsolidity/ast/ASTUtils.h @@ -22,8 +22,9 @@ namespace solidity::frontend class VariableDeclaration; -/// Find the topmost referenced variable declaration when the given variable +/// Find the topmost referenced constant variable declaration when the given variable /// declaration value is an identifier. Works only for constant variable declarations. -VariableDeclaration const* rootVariableDeclaration(VariableDeclaration const& _varDecl); +/// Returns nullptr if an identifier in the chain is not referencing a constant variable declaration. +VariableDeclaration const* rootConstVariableDeclaration(VariableDeclaration const& _varDecl); } diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 3f54fccc6..9ed35e694 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -1487,11 +1487,19 @@ TypeResult ReferenceType::unaryOperatorResult(Token _operator) const case DataLocation::Memory: return TypeProvider::emptyTuple(); case DataLocation::Storage: - return m_isPointer ? nullptr : TypeProvider::emptyTuple(); + return isPointer() ? nullptr : TypeProvider::emptyTuple(); } return nullptr; } +bool ReferenceType::isPointer() const +{ + if (m_location == DataLocation::Storage) + return m_isPointer; + else + return true; +} + TypePointer ReferenceType::copyForLocationIfReference(Type const* _type) const { return TypeProvider::withLocationIfReference(m_location, _type); @@ -1502,7 +1510,7 @@ string ReferenceType::stringForReferencePart() const switch (m_location) { case DataLocation::Storage: - return string("storage ") + (m_isPointer ? "pointer" : "ref"); + return string("storage ") + (isPointer() ? "pointer" : "ref"); case DataLocation::CallData: return "calldata"; case DataLocation::Memory: @@ -1868,7 +1876,8 @@ u256 ArrayType::memoryDataSize() const std::unique_ptr ArrayType::copyForLocation(DataLocation _location, bool _isPointer) const { auto copy = make_unique(_location); - copy->m_isPointer = _isPointer; + if (_location == DataLocation::Storage) + copy->m_isPointer = _isPointer; copy->m_arrayKind = m_arrayKind; copy->m_baseType = copy->copyForLocationIfReference(m_baseType); copy->m_hasDynamicLength = m_hasDynamicLength; @@ -1988,7 +1997,7 @@ vector> ContractType::stateVar vector variables; for (ContractDefinition const* contract: boost::adaptors::reverse(m_contract.annotation().linearizedBaseContracts)) for (VariableDeclaration const* variable: contract->stateVariables()) - if (!variable->isConstant()) + if (!(variable->isConstant() || variable->immutable())) variables.push_back(variable); TypePointers types; for (auto variable: variables) @@ -2247,7 +2256,8 @@ TypeResult StructType::interfaceType(bool _inLibrary) const std::unique_ptr StructType::copyForLocation(DataLocation _location, bool _isPointer) const { auto copy = make_unique(m_struct, _location); - copy->m_isPointer = _isPointer; + if (_location == DataLocation::Storage) + copy->m_isPointer = _isPointer; return copy; } @@ -2954,7 +2964,7 @@ vector> FunctionType::makeStackItems() const if (m_valueSet) slots.emplace_back("value", TypeProvider::uint256()); if (m_saltSet) - slots.emplace_back("salt", TypeProvider::uint256()); + slots.emplace_back("salt", TypeProvider::fixedBytes(32)); if (bound()) for (auto const& [boundName, boundType]: m_parameterTypes.front()->stackItems()) slots.emplace_back("self_" + boundName, boundType); diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 5aada86c3..73943b18a 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -701,7 +701,9 @@ public: /// pointer type, state variables are bound references. Assignments to pointers or deleting /// them will not modify storage (that will only change the pointer). Assignment from /// non-storage objects to a variable of storage pointer type is not possible. - bool isPointer() const { return m_isPointer; } + /// For anything other than storage, this always returns true because assignments + /// never change the contents of the original value. + bool isPointer() const; bool operator==(ReferenceType const& _other) const { diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 8b9061af3..6fffbd5b5 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -525,7 +525,7 @@ void ContractCompiler::initializeStateVariables(ContractDefinition const& _contr { solAssert(!_contract.isLibrary(), "Tried to initialize state variables of library."); for (VariableDeclaration const* variable: _contract.stateVariables()) - if (variable->value() && !variable->isConstant()) + if (variable->value() && !variable->isConstant() && !variable->immutable()) ExpressionCompiler(m_context, m_optimiserSettings.runOrderLiterals).appendStateVariableInitialization(*variable); } @@ -541,6 +541,8 @@ bool ContractCompiler::visit(VariableDeclaration const& _variableDeclaration) if (_variableDeclaration.isConstant()) ExpressionCompiler(m_context, m_optimiserSettings.runOrderLiterals) .appendConstStateVariableAccessor(_variableDeclaration); + else if (_variableDeclaration.immutable()) + solUnimplementedAssert(false, ""); else ExpressionCompiler(m_context, m_optimiserSettings.runOrderLiterals) .appendStateVariableAccessor(_variableDeclaration); @@ -680,9 +682,15 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) } else if (auto variable = dynamic_cast(decl)) { + solAssert(!variable->immutable(), ""); if (variable->isConstant()) { - variable = rootVariableDeclaration(*variable); + variable = rootConstVariableDeclaration(*variable); + // If rootConstVariableDeclaration fails and returns nullptr, + // it should have failed in TypeChecker already, causing a compilation error. + // In such case we should not get here. + solAssert(variable, ""); + u256 value; if (variable->value()->annotation().type->category() == Type::Category::RationalNumber) { diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 0fc24d919..d4f3d460d 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -88,7 +88,7 @@ void ExpressionCompiler::appendConstStateVariableAccessor(VariableDeclaration co void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& _varDecl) { - solAssert(!_varDecl.isConstant(), ""); + solAssert(!_varDecl.isConstant() && !_varDecl.immutable(), ""); CompilerContext::LocationSetter locationSetter(m_context, _varDecl); FunctionType accessorType(_varDecl); @@ -1800,6 +1800,7 @@ bool ExpressionCompiler::visit(IndexRangeAccess const& _indexAccess) { CompilerContext::LocationSetter locationSetter(m_context, _indexAccess); _indexAccess.baseExpression().accept(*this); + // stack: offset length Type const& baseType = *_indexAccess.baseExpression().annotation().type; @@ -1815,27 +1816,21 @@ bool ExpressionCompiler::visit(IndexRangeAccess const& _indexAccess) acceptAndConvert(*_indexAccess.startExpression(), *TypeProvider::uint256()); else m_context << u256(0); + // stack: offset length sliceStart + + m_context << Instruction::SWAP1; + // stack: offset sliceStart length + if (_indexAccess.endExpression()) acceptAndConvert(*_indexAccess.endExpression(), *TypeProvider::uint256()); else - m_context << Instruction::DUP2; + m_context << Instruction::DUP1; + // stack: offset sliceStart length sliceEnd - m_context.appendInlineAssembly( - Whiskers(R"({ - if gt(sliceStart, sliceEnd) { } - if gt(sliceEnd, length) { } + m_context << Instruction::SWAP3; + // stack: sliceEnd sliceStart length offset - offset := add(offset, mul(sliceStart, )) - length := sub(sliceEnd, sliceStart) - })") - ("stride", toString(arrayType->calldataStride())) - ("revertStringStartEnd", m_context.revertReasonIfDebug("Slice starts after end")) - ("revertStringEndLength", m_context.revertReasonIfDebug("Slice is greater than length")) - .render(), - {"offset", "length", "sliceStart", "sliceEnd"} - ); - - m_context << Instruction::POP << Instruction::POP; + m_context.callYulFunction(m_context.utilFunctions().calldataArrayIndexRangeAccess(*arrayType), 4, 2); return false; } @@ -2438,10 +2433,12 @@ void ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType, void ExpressionCompiler::appendVariable(VariableDeclaration const& _variable, Expression const& _expression) { - if (!_variable.isConstant()) - setLValueFromDeclaration(_variable, _expression); - else + if (_variable.isConstant()) acceptAndConvert(*_variable.value(), *_variable.annotation().type); + else if (_variable.immutable()) + solUnimplemented(""); + else + setLValueFromDeclaration(_variable, _expression); } void ExpressionCompiler::setLValueFromDeclaration(Declaration const& _declaration, Expression const& _expression) diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index 046769e43..ba664dbb6 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -933,6 +933,28 @@ string YulUtilFunctions::calldataArrayIndexAccessFunction(ArrayType const& _type }); } +string YulUtilFunctions::calldataArrayIndexRangeAccess(ArrayType const& _type) +{ + solAssert(_type.dataStoredIn(DataLocation::CallData), ""); + solAssert(_type.isDynamicallySized(), ""); + string functionName = "calldata_array_index_range_access_" + _type.identifier(); + return m_functionCollector.createFunction(functionName, [&]() { + return Whiskers(R"( + function (offset, length, startIndex, endIndex) -> offsetOut, lengthOut { + if gt(startIndex, endIndex) { } + if gt(endIndex, length) { } + offsetOut := add(offset, mul(startIndex, )) + lengthOut := sub(endIndex, startIndex) + } + )") + ("functionName", functionName) + ("stride", to_string(_type.calldataStride())) + ("revertSliceStartAfterEnd", revertReasonIfDebug("Slice starts after end")) + ("revertSliceGreaterThanLength", revertReasonIfDebug("Slice is greater than length")) + .render(); + }); +} + string YulUtilFunctions::accessCalldataTailFunction(Type const& _type) { solAssert(_type.isDynamicallyEncoded(), ""); @@ -1365,6 +1387,37 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to) }); } + if (_from.category() == Type::Category::ArraySlice) + { + solAssert(_from.isDynamicallySized(), ""); + solAssert(_from.dataStoredIn(DataLocation::CallData), ""); + solAssert(_to.category() == Type::Category::Array, ""); + + ArraySliceType const& fromType = dynamic_cast(_from); + ArrayType const& targetType = dynamic_cast(_to); + + solAssert( + *fromType.arrayType().baseType() == *targetType.baseType(), + "Converting arrays of different type is not possible" + ); + + string const functionName = + "convert_" + + _from.identifier() + + "_to_" + + _to.identifier(); + return m_functionCollector.createFunction(functionName, [&]() { + return Whiskers(R"( + function (offset, length) -> outOffset, outLength { + outOffset := offset + outLength := length + } + )") + ("functionName", functionName) + .render(); + }); + } + if (_from.sizeOnStack() != 1 || _to.sizeOnStack() != 1) return conversionFunctionSpecial(_from, _to); diff --git a/libsolidity/codegen/YulUtilFunctions.h b/libsolidity/codegen/YulUtilFunctions.h index cf50c785f..8841e98ad 100644 --- a/libsolidity/codegen/YulUtilFunctions.h +++ b/libsolidity/codegen/YulUtilFunctions.h @@ -175,6 +175,11 @@ public: /// signature: (baseRef, index) -> offset[, length] std::string calldataArrayIndexAccessFunction(ArrayType const& _type); + /// @returns the name of a function that returns offset and length for array slice + /// for the given array offset, length and start and end indices for slice + /// signature: (arrayOffset, arrayLength, sliceStart, sliceEnd) -> offset, length + std::string calldataArrayIndexRangeAccess(ArrayType const& _type); + /// @returns the name of a function that follows a calldata tail while performing /// bounds checks. /// signature: (baseRef, tailPointer) -> offset[, length] diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index 8da576055..9c7d9c8ac 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -157,6 +157,7 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl) Type const* type = _varDecl.annotation().type; solAssert(!_varDecl.isConstant(), ""); + solAssert(!_varDecl.immutable(), ""); solAssert(_varDecl.isStateVariable(), ""); if (auto const* mappingType = dynamic_cast(type)) @@ -249,7 +250,7 @@ string IRGenerator::constructorCode(ContractDefinition const& _contract) IRGeneratorForStatements generator{m_context, m_utils}; for (VariableDeclaration const* variable: contract->stateVariables()) - if (!variable->isConstant()) + if (!variable->isConstant() && !variable->immutable()) generator.initializeStateVar(*variable); out << generator.code(); diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 7ce1785b6..1d40c35b1 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -140,6 +140,7 @@ void IRGeneratorForStatements::initializeStateVar(VariableDeclaration const& _va { solAssert(m_context.isStateVariable(_varDecl), "Must be a state variable."); solAssert(!_varDecl.isConstant(), ""); + solAssert(!_varDecl.immutable(), ""); if (_varDecl.value()) { _varDecl.value()->accept(*this); @@ -739,6 +740,25 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) } } +void IRGeneratorForStatements::endVisit(FunctionCallOptions const& _options) +{ + FunctionType const& previousType = dynamic_cast(*_options.expression().annotation().type); + + solUnimplementedAssert(!previousType.bound(), ""); + + // Copy over existing values. + for (auto const& item: previousType.stackItems()) + define(IRVariable(_options).part(get<0>(item)), IRVariable(_options.expression()).part(get<0>(item))); + + for (size_t i = 0; i < _options.names().size(); ++i) + { + string const& name = *_options.names()[i]; + solAssert(name == "salt" || name == "gas" || name == "value", ""); + + define(IRVariable(_options).part(name), *_options.options()[i]); + } +} + void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) { ASTString const& member = _memberAccess.memberName(); @@ -981,9 +1001,16 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess) } }); } - else if (baseType.category() == Type::Category::Array) + else if (baseType.category() == Type::Category::Array || baseType.category() == Type::Category::ArraySlice) { - ArrayType const& arrayType = dynamic_cast(baseType); + ArrayType const& arrayType = + baseType.category() == Type::Category::Array ? + dynamic_cast(baseType) : + dynamic_cast(baseType).arrayType(); + + if (baseType.category() == Type::Category::ArraySlice) + solAssert(arrayType.dataStoredIn(DataLocation::CallData) && arrayType.isDynamicallySized(), ""); + solAssert(_indexAccess.indexExpression(), "Index expression expected."); switch (arrayType.location()) @@ -1066,9 +1093,50 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess) solAssert(false, "Index access only allowed for mappings or arrays."); } -void IRGeneratorForStatements::endVisit(IndexRangeAccess const&) +void IRGeneratorForStatements::endVisit(IndexRangeAccess const& _indexRangeAccess) { - solUnimplementedAssert(false, "Index range accesses not yet implemented."); + Type const& baseType = *_indexRangeAccess.baseExpression().annotation().type; + solAssert( + baseType.category() == Type::Category::Array || baseType.category() == Type::Category::ArraySlice, + "Index range accesses is available only on arrays and array slices." + ); + + ArrayType const& arrayType = + baseType.category() == Type::Category::Array ? + dynamic_cast(baseType) : + dynamic_cast(baseType).arrayType(); + + switch (arrayType.location()) + { + case DataLocation::CallData: + { + solAssert(baseType.isDynamicallySized(), ""); + IRVariable sliceStart{m_context.newYulVariable(), *TypeProvider::uint256()}; + if (_indexRangeAccess.startExpression()) + define(sliceStart, IRVariable{*_indexRangeAccess.startExpression()}); + else + define(sliceStart) << u256(0) << "\n"; + + IRVariable sliceEnd{ + m_context.newYulVariable(), + *TypeProvider::uint256() + }; + if (_indexRangeAccess.endExpression()) + define(sliceEnd, IRVariable{*_indexRangeAccess.endExpression()}); + else + define(sliceEnd, IRVariable{_indexRangeAccess.baseExpression()}.part("length")); + + IRVariable range{_indexRangeAccess}; + define(range) << + m_utils.calldataArrayIndexRangeAccess(arrayType) << "(" << + IRVariable{_indexRangeAccess.baseExpression()}.commaSeparatedList() << ", " << + sliceStart.name() << ", " << + sliceEnd.name() << ")\n"; + break; + } + default: + solUnimplementedAssert(false, "Index range accesses is implemented only on calldata arrays."); + } } void IRGeneratorForStatements::endVisit(Identifier const& _identifier) @@ -1104,6 +1172,7 @@ void IRGeneratorForStatements::endVisit(Identifier const& _identifier) // If the value is visited twice, `defineExpression` is called twice on // the same expression. solUnimplementedAssert(!varDecl->isConstant(), ""); + solUnimplementedAssert(!varDecl->immutable(), ""); if (m_context.isLocalVariable(*varDecl)) setLValue(_identifier, IRLValue{ *varDecl->annotation().type, @@ -1519,7 +1588,7 @@ void IRGeneratorForStatements::writeToLValue(IRLValue const& _lvalue, IRVariable solAssert(dynamic_cast(&_lvalue.type), ""); auto const* valueReferenceType = dynamic_cast(&_value.type()); solAssert(valueReferenceType && valueReferenceType->dataStoredIn(DataLocation::Memory), ""); - m_code << "mstore(" + _memory.address + ", " + _value.name() + ")\n"; + m_code << "mstore(" + _memory.address + ", " + _value.part("mpos").name() + ")\n"; } }, [&](IRLValue::Stack const& _stack) { assign(_stack.variable, _value); }, diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.h b/libsolidity/codegen/ir/IRGeneratorForStatements.h index 785b02e09..39dbb67d7 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.h +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.h @@ -60,6 +60,7 @@ public: void endVisit(UnaryOperation const& _unaryOperation) override; bool visit(BinaryOperation const& _binOp) override; void endVisit(FunctionCall const& _funCall) override; + void endVisit(FunctionCallOptions const& _funCallOptions) override; void endVisit(MemberAccess const& _memberAccess) override; bool visit(InlineAssembly const& _inlineAsm) override; void endVisit(IndexAccess const& _indexAccess) override; diff --git a/libsolidity/interface/DebugSettings.h b/libsolidity/interface/DebugSettings.h index 67c6d8810..34818889c 100644 --- a/libsolidity/interface/DebugSettings.h +++ b/libsolidity/interface/DebugSettings.h @@ -54,7 +54,7 @@ inline std::optional revertStringsFromString(std::string const& _ for (auto i: {RevertStrings::Default, RevertStrings::Strip, RevertStrings::Debug, RevertStrings::VerboseDebug}) if (revertStringsToString(i) == _str) return i; - return {}; + return std::nullopt; } } diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index edf43377f..2f23c8c22 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -730,8 +730,18 @@ ASTPointer Parser::parseVariableDeclaration( { if (_options.allowIndexed && token == Token::Indexed) isIndexed = true; - else if (token == Token::Constant) - constantness = VariableDeclaration::Constantness::Constant; + else if (token == Token::Constant || token == Token::Immutable) + { + if (constantness != VariableDeclaration::Constantness::Mutable) + parserError( + string("Constantness already set to ") + + (constantness == VariableDeclaration::Constantness::Constant ? "\"constant\"" : "\"immutable\"") + ); + else if (token == Token::Constant) + constantness = VariableDeclaration::Constantness::Constant; + else if (token == Token::Immutable) + constantness = VariableDeclaration::Constantness::Immutable; + } else if (_options.allowLocationSpecifier && TokenTraits::isLocationSpecifier(token)) { if (location != VariableDeclaration::Location::Unspecified) diff --git a/libsolutil/vector_ref.h b/libsolutil/vector_ref.h index 3bb71f35e..46901a46e 100644 --- a/libsolutil/vector_ref.h +++ b/libsolutil/vector_ref.h @@ -44,7 +44,6 @@ public: std::vector toBytes() const { return std::vector(reinterpret_cast(m_data), reinterpret_cast(m_data) + m_count * sizeof(T)); } std::string toString() const { return std::string((char const*)m_data, ((char const*)m_data) + m_count * sizeof(T)); } - template explicit operator vector_ref() const { assert(m_count * sizeof(T) / sizeof(T2) * sizeof(T2) / sizeof(T) == m_count); return vector_ref(reinterpret_cast(m_data), m_count * sizeof(T) / sizeof(T2)); } operator vector_ref() const { return vector_ref(m_data, m_count); } T* data() const { return m_data; } diff --git a/libyul/AsmParser.cpp b/libyul/AsmParser.cpp index 708e76339..758b11d92 100644 --- a/libyul/AsmParser.cpp +++ b/libyul/AsmParser.cpp @@ -324,6 +324,7 @@ Parser::ElementaryOperation Parser::parseElementaryOperation() case Token::Byte: case Token::Bool: case Token::Address: + case Token::Var: { YulString literal{currentLiteral()}; if (m_dialect.builtin(literal)) @@ -513,6 +514,7 @@ YulString Parser::expectAsmIdentifier() case Token::Address: case Token::Bool: case Token::Identifier: + case Token::Var: break; default: expectToken(Token::Identifier); diff --git a/scripts/common_cmdline.sh b/scripts/common_cmdline.sh new file mode 100644 index 000000000..1d21fe75c --- /dev/null +++ b/scripts/common_cmdline.sh @@ -0,0 +1,79 @@ +# ------------------------------------------------------------------------------ +# vim:ts=4:et +# This file is part of solidity. +# +# solidity is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# solidity is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with solidity. If not, see +# +# (c) 2016-2019 solidity contributors. +# ------------------------------------------------------------------------------ + +FULLARGS="--optimize --ignore-missing --combined-json abi,asm,ast,bin,bin-runtime,compact-format,devdoc,hashes,interface,metadata,opcodes,srcmap,srcmap-runtime,userdoc" +OLDARGS="--optimize --combined-json abi,asm,ast,bin,bin-runtime,devdoc,interface,metadata,opcodes,srcmap,srcmap-runtime,userdoc" +function compileFull() +{ + local expected_exit_code=0 + local expect_output=0 + if [[ $1 = '-e' ]]; then + expected_exit_code=1 + expect_output=1 + shift; + fi + if [[ $1 = '-w' ]]; then + expect_output=1 + shift; + fi + if [[ $1 = '-o' ]]; then + expect_output=2 + shift; + fi + local args=$FULLARGS + if [[ $1 = '-v' ]]; then + if (echo $2 | grep -Po '(?<=0.4.)\d+' >/dev/null); then + patch=$(echo $2 | grep -Po '(?<=0.4.)\d+') + if (( patch < 22 )); then + args=$OLDARGS + fi + fi + shift 2 + fi + + local files="$*" + local output + + local stderr_path=$(mktemp) + + set +e + "$SOLC" ${args} ${files} >/dev/null 2>"$stderr_path" + local exit_code=$? + local errors=$(grep -v -E 'Warning: This is a pre-release compiler version|Warning: Experimental features are turned on|pragma experimental ABIEncoderV2|^ +--> |^ +\||^[0-9]+ +\|' < "$stderr_path") + set -e + rm "$stderr_path" + + if [[ \ + ("$exit_code" -ne "$expected_exit_code" || \ + ( $expect_output -eq 0 && -n "$errors" ) || \ + ( $expect_output -ne 0 && $expected_exit_code -eq 0 && $expect_output -ne 2 && -z "$errors" )) + ]] + then + printError "Unexpected compilation result:" + printError "Expected failure: $expected_exit_code - Expected warning / error output: $expect_output" + printError "Was failure: $exit_code" + echo "$errors" + printError "While calling:" + echo "\"$SOLC\" $ARGS $files" + printError "Inside directory:" + pwd + false + fi +} diff --git a/scripts/docs_version_pragma_check.sh b/scripts/docs_version_pragma_check.sh new file mode 100755 index 000000000..a66798841 --- /dev/null +++ b/scripts/docs_version_pragma_check.sh @@ -0,0 +1,95 @@ +#!/usr/bin/env bash + +# ------------------------------------------------------------------------------ +# This file is part of solidity. +# +# solidity is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# solidity is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with solidity. If not, see +# +# (c) 2016 solidity contributors. +#------------------------------------------------------------------------------ + +# This script verifies that the examples compile with the oldest version mentioned in the pragma. +# It does not verify that it cannot be compiled with an older version +# and it also does not verify that it can be compiled with the newest version compatible with the pragma. + +set -e + +## GLOBAL VARIABLES + +REPO_ROOT=$(cd $(dirname "$0")/.. && pwd) +SOLIDITY_BUILD_DIR=${SOLIDITY_BUILD_DIR:-build} +source "${REPO_ROOT}/scripts/common.sh" +source "${REPO_ROOT}/scripts/common_cmdline.sh" + +printTask "Verifying that all examples from the documentation have the correct version range..." +SOLTMPDIR=$(mktemp -d) +( + set -e + cd "$SOLTMPDIR" + "$REPO_ROOT"/scripts/isolate_tests.py "$REPO_ROOT"/docs/ docs + + for f in *.sol + do + # The contributors guide uses syntax tests, but we cannot + # really handle them here. + if grep -E 'DeclarationError:|// ----' "$f" >/dev/null + then + continue + fi + echo "$f" + + opts='' + # We expect errors if explicitly stated, or if imports + # are used (in the style guide) + if ( ! grep -E "This will not compile after" "$f" >/dev/null && \ + grep -E "This will not compile|import \"" "$f" >/dev/null ) + then + opts="-e" + fi + + # ignore warnings in this case + opts="$opts -o" + + # Get minimum compiler version defined by pragma + if (grep -Po '(?<=pragma solidity >=)\d+.\d+.\d+' "$f" >/dev/null); then + version="$(grep -Po '(?<=pragma solidity >=)\d+.\d+.\d+' "$f")" + if (echo $version | grep -Po '(?<=0.4.)\d+' >/dev/null); then + patch=$(echo $version | grep -Po '(?<=0.4.)\d+') + if (( patch < 11 )); then + version="0.4.11" # first available release on github + fi + fi + elif (grep -Po '(?<=pragma solidity \^)\d+.\d+.\d+' "$f" >/dev/null); then + version="$(grep -Po '(?<=pragma solidity \^)\d+.\d+.\d+' "$f")" + fi + + opts="$opts -v $version" + + solc_bin="solc-$version" + echo "$solc_bin" + if [[ ! -f "$solc_bin" ]]; then + echo "Downloading release from github..." + wget https://github.com/ethereum/solidity/releases/download/v$version/solc-static-linux + mv solc-static-linux $solc_bin + fi + + ln -sf "$solc_bin" "solc" + chmod a+x solc + + SOLC="$SOLTMPDIR/solc" + compileFull $opts "$SOLTMPDIR/$f" + done +) +rm -rf "$SOLTMPDIR" +echo "Done." \ No newline at end of file diff --git a/scripts/endToEndExtraction/create_traces.sh b/scripts/endToEndExtraction/create_traces.sh new file mode 100755 index 000000000..f167fee5e --- /dev/null +++ b/scripts/endToEndExtraction/create_traces.sh @@ -0,0 +1,22 @@ +BASE_PATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 || exit ; pwd -P )" + +mkdir -p build +cd build || exit +cmake ../../../ +make soltest +cd test/ || exit +echo "running soltest on 'semanticTests/extracted'..." +./soltest --color_output=false --log_level=test_suite -t semanticTests/extracted/ -- --testpath ${BASE_PATH}/../../test --no-smt --evmonepath /Users/alex/evmone/lib/libevmone.dylib --show-messages --show-metadata > ${BASE_PATH}/extracted-tests.trace +echo "running soltest on 'semanticTests/extracted'... done" + +cd $BASE_PATH || exit +git clone git@github.com:ethereum/solidity.git solidity-develop +cd solidity-develop || exit +mkdir -p build +cd build || exit +cmake .. +make soltest +cd test/ || exit +echo "running soltest on 'SolidityEndToEndTest'..." +./soltest --color_output=false --log_level=test_suite -t SolidityEndToEndTest/ -- --testpath ${BASE_PATH}/solidity-develop/test --no-smt --evmonepath /Users/alex/evmone/lib/libevmone.dylib --show-messages --show-metadata > ${BASE_PATH}/endToEndExtraction-tests.trace +echo "running soltest on 'SolidityEndToEndTest'... done" diff --git a/scripts/endToEndExtraction/remove-testcases.py b/scripts/endToEndExtraction/remove-testcases.py new file mode 100755 index 000000000..89f50d0e1 --- /dev/null +++ b/scripts/endToEndExtraction/remove-testcases.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python3 +# pylint: disable=consider-using-enumerate, import-error + +import re +import os +import sys +import getopt +import tempfile +from getkey import getkey + + +def parse_call(call): + function = '' + arguments = "" + results = "" + search = re.search(r'// (.*):(.*)\s->\s(.*)', call, re.MULTILINE | re.DOTALL) + if search: + function = search.group(1) + arguments = search.group(2) + results = search.group(3) + if results.find("#") != -1: + results = results[:results.find("#")] + else: + search = re.search(r'// (.*)(.*)\s->\s(.*)', call, re.MULTILINE | re.DOTALL) + if search: + function = search.group(1) + arguments = search.group(2) + results = search.group(3) + if results.find("#") != -1: + results = results[:results.find("#")] + if function.find("wei") >= 0: + function = function[:function.find(",")] + return function.strip(), arguments.strip(), results.strip() + + +def colorize(left, right, id): + red = "\x1b[31m" + yellow = "\x1b[33m" + reset = "\x1b[0m" + colors = [red, yellow] + color = colors[id % len(colors)] + function, arguments, results = parse_call(right) + left = left.replace("compileAndRun", color + "compileAndRun" + reset) + right = right.replace("constructor", color + "constructor" + reset) + if function: + left = left.replace(function, color + function + reset) + right = right.replace(function, color + function + reset) + if left.find(function): + bottom = " " * (left.find(function) - 4) + right + else: + bottom = " " + right + return " " + left + "\n" + bottom # " {:<90} {:<90}\n{}".format(left, right, bottom) + + +def get_checks(content, sol_file_path): + constructors = [] + checks = [] + for line in content.split("\n"): + line = line.strip() + if line.startswith("compileAndRun"): + constructors.append(line) + if line.startswith("ABI_CHECK") or line.startswith("BOOST_REQUIRE"): + checks.append(line) + sol_file = open(sol_file_path, "r") + sol_constructors = [] + sol_checks = [] + inside_expectations = False + for line in sol_file.readlines(): + if line.startswith("// constructor()"): + sol_constructors.append(line) + elif inside_expectations and line.startswith("// "): + sol_checks.append(line) + if line.startswith("// ----"): + inside_expectations = True + sol_file.close() + if len(constructors) == len(sol_constructors) == 1: + checks.insert(0, constructors[0]) + sol_checks.insert(0, sol_constructors[0]) + return checks, sol_checks + + +def show_test(name, content, sol_file_path, current_test, test_count): + cpp_file = tempfile.NamedTemporaryFile(delete=False) + cpp_file.write(content.encode()) + cpp_file.close() + + os.system("clear") + print(str(current_test) + " / " + str(test_count) + " - " + name + "\n") + diff_env = os.getenv('DIFF', "/usr/local/bin/colordiff -a -d -w -y -W 200 ") + os.system(diff_env + " " + cpp_file.name + " " + sol_file_path) + os.unlink(cpp_file.name) + print("\n") + + checks, sol_checks = get_checks(content, sol_file_path) + + if len(checks) == len(sol_checks): + for i in range(0, len(checks)): + print(colorize(checks[i].strip(), sol_checks[i].strip(), i)) + else: + print("warning: check count not matching. this should not happen!") + + what = "" + print("\nContinue? (ENTER) Abort? (ANY OTHER KEY)") + while what != '\n': + what = getkey() + if what != '\n': + sys.exit(0) + print() + + +def get_tests(e2e_path): + tests = [] + for f in os.listdir(e2e_path): + if f.endswith(".sol"): + tests.append(f.replace(".sol", "")) + return tests + + +def process_input_file(e2e_path, input_file, interactive): + tests = get_tests(e2e_path) + cpp_file = open(input_file, "r") + inside_test = False + test_name = "" + inside_extracted_test = False + new_lines = 0 + count = 0 + test_content = "" + for line in cpp_file.readlines(): + test = re.search(r'BOOST_AUTO_TEST_CASE\((.*)\)', line, re.M | re.I) + if test: + test_name = test.group(1) + inside_test = True + inside_extracted_test = inside_test & (test_name in tests) + if inside_extracted_test: + count = count + 1 + + if interactive and inside_extracted_test: + test_content = test_content + line + + if not inside_extracted_test: + if line == "\n": + new_lines = new_lines + 1 + else: + new_lines = 0 + if not interactive and new_lines <= 1: + sys.stdout.write(line) + + if line == "}\n": + if interactive and inside_extracted_test: + show_test(test_name, test_content.strip(), e2e_path + "/" + test_name + ".sol", count, len(tests)) + test_content = "" + inside_test = False + cpp_file.close() + sys.stdout.flush() + + +def main(argv): + interactive = False + input_file = None + try: + opts, args = getopt.getopt(argv, "if:") + except getopt.GetoptError: + print("./remove-testcases.py [-i] [-f ]") + sys.exit(1) + + for opt, arg in opts: + if opt == '-i': + interactive = True + elif opt in '-f': + input_file = arg + + base_path = os.path.dirname(__file__) + + if not input_file: + input_file = base_path + "/../../test/libsolidity/SolidityEndToEndTest.cpp" + + e2e_path = base_path + "/../../test/libsolidity/semanticTests/extracted" + + process_input_file(e2e_path, input_file, interactive) + + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/scripts/endToEndExtraction/verify-testcases.py b/scripts/endToEndExtraction/verify-testcases.py new file mode 100755 index 000000000..87dc309d8 --- /dev/null +++ b/scripts/endToEndExtraction/verify-testcases.py @@ -0,0 +1,215 @@ +#!/usr/bin/env python3 +# +# - SolidityEndToEndTest.trace was created with soltest with the following command on +# ./soltest --color_output=false --log_level=test_suite -t SolidityEndToEndTest/ -- --no-smt +# --evmonepath /Users/alex/evmone/lib/libevmone.dylib --show-messages > SolidityEndToEndTest.trace +# - a trace of the semantic tests can be created by using +# ./soltest --color_output=false --log_level=test_suite -t semanticTests/extracted/ -- --no-smt +# --evmonepath /Users/alex/evmone/lib/libevmone.dylib --show-messages > semanticTests.trace +# +# verify-testcases.py will compare both traces. If these traces are identical, the extracted tests where +# identical with the tests specified in SolidityEndToEndTest.cpp. +# +# pylint: disable=too-many-instance-attributes + +import re +import os +import sys +import getopt +import json + + +class Trace: + def __init__(self, kind, parameter): + self.kind = kind + self.parameter = parameter + self._input = "" + self._output = "" + self.value = "" + self.result = "" + self.gas = "" + + def get_input(self): + return self._input + + def set_input(self, input): + if self.kind == "create": + # remove cbor encoded metadata from bytecode + length = int(input[-4:], 16) * 2 + self._input = input[:len(input) - length - 4] + + def get_output(self): + return self._output + + def set_output(self, output): + if self.kind == "create": + # remove cbor encoded metadata from bytecode + length = int(output[-4:], 16) * 2 + self._output = output[:len(output) - length - 4] + + def __str__(self): + # we ignore the used gas + result = str( + "kind='" + self.kind + "' parameter='" + self.parameter + "' input='" + self._input + + "' output='" + self._output + "' value='" + self.value + "' result='" + self.result + "'" + ) + return result + + +class TestCase: + def __init__(self, name): + self.name = name + self.metadata = None + self.traces = [] + + def add_trace(self, kind, parameter): + trace = Trace(kind, parameter) + self.traces.append(trace) + return trace + + +class TraceAnalyser: + def __init__(self, file): + self.file = file + self.tests = {} + self.ready = False + + def analyse(self): + trace_file = open(self.file, "r") + trace = None + test_case = None + for line in trace_file.readlines(): + test = re.search(r'Entering test case "(.*)"', line, re.M | re.I) + if test: + test_name = test.group(1) + test_case = TestCase(test_name) + self.tests[test_name] = test_case + + metadata = re.search(r'\s*metadata:\s*(.*)$', line, re.M | re.I) + if metadata: + test_case.metadata = json.loads(metadata.group(1)) + del test_case.metadata["sources"] + del test_case.metadata["compiler"]["version"] + + create = re.search(r'CREATE\s*([a-fA-F0-9]*):', line, re.M | re.I) + if create: + trace = test_case.add_trace("create", create.group(1)) + + call = re.search(r'CALL\s*([a-fA-F0-9]*)\s*->\s*([a-fA-F0-9]*):', line, re.M | re.I) + if call: + trace = test_case.add_trace("call", call.group(1)) # + "->" + call.group(2)) + + if not create and not call: + self.parse_parameters(line, trace) + + trace_file.close() + + print(self.file + ":", len(self.tests), "test-cases.") + + self.ready = True + + @staticmethod + def parse_parameters(line, trace): + input = re.search(r'\s*in:\s*([a-fA-F0-9]*)', line, re.M | re.I) + if input: + trace.input = input.group(1) + output = re.search(r'\s*out:\s*([a-fA-F0-9]*)', line, re.M | re.I) + if output: + trace.output = output.group(1) + result = re.search(r'\s*result:\s*([a-fA-F0-9]*)', line, re.M | re.I) + if result: + trace.result = result.group(1) + gas_used = re.search(r'\s*gas\sused:\s*([a-fA-F0-9]*)', line, re.M | re.I) + if gas_used: + trace.gas = gas_used.group(1) + value = re.search(r'\s*value:\s*([a-fA-F0-9]*)', line, re.M | re.I) + if value: + trace.value = value.group(1) + + def diff(self, analyser): + if not self.ready: + self.analyse() + if not analyser.ready: + analyser.analyse() + + intersection = set(self.tests.keys()) & set(analyser.tests.keys()) + mismatches = set() + + for test_name in intersection: + left = self.tests[test_name] + right = analyser.tests[test_name] + if json.dumps(left.metadata) != json.dumps(right.metadata): + mismatches.add( + (test_name, "metadata where different: " + json.dumps(left.metadata) + " != " + json.dumps( + right.metadata))) + if len(left.traces) != len(right.traces): + mismatches.add((test_name, "trace count are different: " + str(len(left.traces)) + + " != " + str(len(right.traces)))) + else: + self.check_traces(test_name, left, right, mismatches) + + for mismatch in mismatches: + print(mismatch[0]) + print(mismatch[1]) + + print(len(intersection), "test-cases - ", len(mismatches), " mismatche(s)") + + def check_traces(self, test_name, left, right, mismatches): + for trace_id in range(0, len(left.traces)): + left_trace = left.traces[trace_id] + right_trace = right.traces[trace_id] + assert (left_trace.kind == right_trace.kind) + if str(left_trace) != str(right_trace): + mismatch_info = " " + str(left_trace) + "\n" + mismatch_info += " " + str(right_trace) + "\n" + mismatch_info += " " + for ch in range(0, len(str(left_trace))): + if ch < len(str(left_trace)) and ch < len(str(right_trace)): + if str(left_trace)[ch] != str(right_trace)[ch]: + mismatch_info += "|" + else: + mismatch_info += " " + else: + mismatch_info += "|" + mismatch_info += "\n" + mismatches.add((test_name, mismatch_info)) + + +def main(argv): + extracted_tests_trace_file = None + end_to_end_trace_file = None + try: + opts, args = getopt.getopt(argv, "s:e:") + except getopt.GetoptError: + print("verify-testcases.py [-s ] [-e ]") + sys.exit(2) + + for opt, arg in opts: + if opt in '-s': + extracted_tests_trace_file = arg + elif opt in '-e': + end_to_end_trace_file = arg + + base_path = os.path.dirname(__file__) + if not extracted_tests_trace_file: + extracted_tests_trace_file = base_path + "/extracted-tests.trace" + if not end_to_end_trace_file: + end_to_end_trace_file = base_path + "/endToEndExtraction-tests.trace" + + for f in [extracted_tests_trace_file, end_to_end_trace_file]: + if not os.path.isfile(f): + print("trace file '" + f + "' not found. aborting.") + sys.exit(1) + + if not os.path.isfile(extracted_tests_trace_file): + print("semantic trace file '" + extracted_tests_trace_file + "' not found. aborting.") + sys.exit(1) + + semantic_trace = TraceAnalyser(extracted_tests_trace_file) + end_to_end_trace = TraceAnalyser(end_to_end_trace_file) + + semantic_trace.diff(end_to_end_trace) + + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/scripts/test_antlr_grammar.sh b/scripts/test_antlr_grammar.sh new file mode 100755 index 000000000..97cbe4ab4 --- /dev/null +++ b/scripts/test_antlr_grammar.sh @@ -0,0 +1,101 @@ +#!/usr/bin/env bash + +set -e + +ROOT_DIR="$(dirname "$0")"/.. +WORKDIR="${ROOT_DIR}/build/antlr" +ANTLR_JAR="${ROOT_DIR}/build/deps/antlr4.jar" +ANTLR_JAR_URI="https://www.antlr.org/download/antlr-4.7.2-complete.jar" +GRAMMAR_FILE="$(readlink -f "${ROOT_DIR}/docs/Solidity.g4")" + +SGR_RESET="\033[0m" +SGR_BOLD="\033[1m" +SGR_GREEN="\033[32m" +SGR_RED="\033[31m" +SGR_BLUE="\033[34m" + +vt_cursor_up() { echo -ne "\033[A"; } +vt_cursor_begin_of_line() { echo -ne "\r"; } + +download_antlr4() +{ + if [[ ! -e "$ANTLR_JAR" ]] + then + curl -o "${ANTLR_JAR}" "${ANTLR_JAR_URI}" + fi +} + +prepare_workdir() +{ + mkdir -p "${ROOT_DIR}/build/deps" + mkdir -p "${WORKDIR}" + mkdir -p "${WORKDIR}/src" + mkdir -p "${WORKDIR}/target" +} + +prepare_workdir +download_antlr4 + +if [[ ! -f "${WORKDIR}/target/SolidityParser.class" ]] || \ + [ "${GRAMMAR_FILE}" -nt "${WORKDIR}/target/SolidityParser.class" ] +then + echo "Creating parser" + # Create lexer/parser from grammar + java -jar "${ANTLR_JAR}" "${GRAMMAR_FILE}" -o "${WORKDIR}/src/" + + # Compile lexer/parser sources + javac -classpath "${ANTLR_JAR}" "${WORKDIR}/src/"*.java -d "${WORKDIR}/target/" +fi + +# Run tests +failed_count=0 +test_file() +{ + local SOL_FILE + SOL_FILE="$(readlink -m "${1}")" + local cur=${2} + local max=${3} + + echo -e "${SGR_BLUE}[${cur}/${max}] Testing ${SOL_FILE}${SGR_RESET} ..." + local output + output=$( + java \ + -classpath "${ANTLR_JAR}:${WORKDIR}/target/" \ + "org.antlr.v4.gui.TestRig" \ + Solidity \ + sourceUnit <"${SOL_FILE}" 2>&1 + ) + vt_cursor_up + vt_cursor_begin_of_line + if [[ "${output}" == "" ]] + then + echo -e "${SGR_BLUE}[${cur}/${max}] Testing ${SOL_FILE}${SGR_RESET} ${SGR_BOLD}${SGR_GREEN}OK${SGR_RESET}" + else + echo -e "${SGR_BLUE}[${cur}/${max}] Testing ${SOL_FILE}${SGR_RESET} ${SGR_BOLD}${SGR_RED}FAILED${SGR_RESET}" + echo "${output}" + failed_count=$((failed_count + 1)) + exit 1 + fi +} + +# we only want to use files that do not contain errors or multi-source files. +SOL_FILES=() +while IFS='' read -r line +do + SOL_FILES+=("$line") +done < <( + grep -riL -E \ + "^\/\/ (Syntax|Type|Parser|Declaration)Error|^==== Source:" \ + "${ROOT_DIR}/test/libsolidity/syntaxTests" \ + "${ROOT_DIR}/test/libsolidity/semanticTests" \ +) + +test_count=0 +for SOL_FILE in "${SOL_FILES[@]}" +do + test_count=$((test_count + 1)) + test_file "${SOL_FILE}" ${test_count} ${#SOL_FILES[*]} +done + +echo "Summary: ${failed_count} of ${#SOL_FILES[*]} sources failed." +exit ${failed_count} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3ea080686..181a0fbcf 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -13,6 +13,8 @@ set(sources Metadata.h TestCase.cpp TestCase.h + TestCaseReader.cpp + TestCaseReader.h ) detect_stray_source_files("${sources}" ".") @@ -139,12 +141,17 @@ set(libyul_sources detect_stray_source_files("${libyul_sources}" "libyul/") set(yul_phaser_sources - yulPhaser/Common.h + yulPhaser/TestHelpers.h + yulPhaser/TestHelpers.cpp + yulPhaser/TestHelpersTest.cpp yulPhaser/Common.cpp - yulPhaser/CommonTest.cpp yulPhaser/Chromosome.cpp yulPhaser/FitnessMetrics.cpp + yulPhaser/AlgorithmRunner.cpp yulPhaser/GeneticAlgorithms.cpp + yulPhaser/Mutations.cpp + yulPhaser/PairSelections.cpp + yulPhaser/Phaser.cpp yulPhaser/Population.cpp yulPhaser/Program.cpp yulPhaser/Selections.cpp @@ -153,9 +160,14 @@ set(yul_phaser_sources # FIXME: yul-phaser is not a library so I can't just add it to target_link_libraries(). # My current workaround is just to include its source files here but this introduces # unnecessary duplication. Create a library or find a way to reuse the list in both places. + ../tools/yulPhaser/AlgorithmRunner.cpp + ../tools/yulPhaser/Common.cpp ../tools/yulPhaser/Chromosome.cpp ../tools/yulPhaser/FitnessMetrics.cpp ../tools/yulPhaser/GeneticAlgorithms.cpp + ../tools/yulPhaser/Mutations.cpp + ../tools/yulPhaser/PairSelections.cpp + ../tools/yulPhaser/Phaser.cpp ../tools/yulPhaser/Population.cpp ../tools/yulPhaser/Program.cpp ../tools/yulPhaser/Selections.cpp diff --git a/test/Common.cpp b/test/Common.cpp index 709840bbc..0ed7c9881 100644 --- a/test/Common.cpp +++ b/test/Common.cpp @@ -96,7 +96,8 @@ CommonOptions::CommonOptions(std::string _caption): ("optimize", po::bool_switch(&optimize), "enables optimization") ("optimize-yul", po::bool_switch(&optimizeYul), "enables Yul optimization") ("abiencoderv2", po::bool_switch(&useABIEncoderV2), "enables abi encoder v2") - ("show-messages", po::bool_switch(&showMessages), "enables message output"); + ("show-messages", po::bool_switch(&showMessages), "enables message output") + ("show-metadata", po::bool_switch(&showMetadata), "enables metadata output"); } void CommonOptions::validate() const diff --git a/test/Common.h b/test/Common.h index 63437da13..a65c95539 100644 --- a/test/Common.h +++ b/test/Common.h @@ -50,6 +50,7 @@ struct CommonOptions: boost::noncopyable bool disableSMT = false; bool useABIEncoderV2 = false; bool showMessages = false; + bool showMetadata = false; langutil::EVMVersion evmVersion() const; diff --git a/test/CommonSyntaxTest.cpp b/test/CommonSyntaxTest.cpp index 6d72ce010..e3edc3fb0 100644 --- a/test/CommonSyntaxTest.cpp +++ b/test/CommonSyntaxTest.cpp @@ -56,37 +56,37 @@ int parseUnsignedInteger(string::iterator& _it, string::iterator _end) } -CommonSyntaxTest::CommonSyntaxTest(string const& _filename, langutil::EVMVersion _evmVersion): m_evmVersion(_evmVersion) +CommonSyntaxTest::CommonSyntaxTest(string const& _filename, langutil::EVMVersion _evmVersion): + EVMVersionRestrictedTestCase(_filename), + m_evmVersion(_evmVersion) { - ifstream file(_filename); - if (!file) - BOOST_THROW_EXCEPTION(runtime_error("Cannot open test contract: \"" + _filename + "\".")); - file.exceptions(ios::badbit); - - m_sources = parseSourcesAndSettings(file); - - m_expectations = parseExpectations(file); + m_sources = m_reader.sources(); + m_expectations = parseExpectations(m_reader.stream()); } TestCase::TestResult CommonSyntaxTest::run(ostream& _stream, string const& _linePrefix, bool _formatted) { parseAndAnalyze(); - return printExpectationAndError(_stream, _linePrefix, _formatted) ? TestResult::Success : TestResult::Failure; + return conclude(_stream, _linePrefix, _formatted); } -bool CommonSyntaxTest::printExpectationAndError(ostream& _stream, string const& _linePrefix, bool _formatted) +TestCase::TestResult CommonSyntaxTest::conclude(ostream& _stream, string const& _linePrefix, bool _formatted) { - if (m_expectations != m_errorList) - { - string nextIndentLevel = _linePrefix + " "; - AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Expected result:" << endl; - printErrorList(_stream, m_expectations, nextIndentLevel, _formatted); - AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Obtained result:" << endl; - printErrorList(_stream, m_errorList, nextIndentLevel, _formatted); - return false; - } - return true; + if (m_expectations == m_errorList) + return TestResult::Success; + + printExpectationAndError(_stream, _linePrefix, _formatted); + return TestResult::Failure; +} + +void CommonSyntaxTest::printExpectationAndError(ostream& _stream, string const& _linePrefix, bool _formatted) +{ + string nextIndentLevel = _linePrefix + " "; + AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Expected result:" << endl; + printErrorList(_stream, m_expectations, nextIndentLevel, _formatted); + AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Obtained result:" << endl; + printErrorList(_stream, m_errorList, nextIndentLevel, _formatted); } void CommonSyntaxTest::printSource(ostream& _stream, string const& _linePrefix, bool _formatted) const diff --git a/test/CommonSyntaxTest.h b/test/CommonSyntaxTest.h index 22acd5413..e761e1487 100644 --- a/test/CommonSyntaxTest.h +++ b/test/CommonSyntaxTest.h @@ -73,7 +73,8 @@ protected: bool _formatted = false ); - virtual bool printExpectationAndError(std::ostream& _stream, std::string const& _linePrefix = "", bool _formatted = false); + TestResult conclude(std::ostream& _stream, std::string const& _linePrefix = "", bool _formatted = false); + void printExpectationAndError(std::ostream& _stream, std::string const& _linePrefix = "", bool _formatted = false); static std::vector parseExpectations(std::istream& _stream); diff --git a/test/TestCase.cpp b/test/TestCase.cpp index 6b0a16e27..f952e40bd 100644 --- a/test/TestCase.cpp +++ b/test/TestCase.cpp @@ -18,16 +18,9 @@ #include #include -#include - -#include -#include #include -#include -#include #include - #include using namespace std; @@ -35,13 +28,14 @@ using namespace solidity; using namespace solidity::frontend; using namespace solidity::frontend::test; -void TestCase::printUpdatedSettings(ostream& _stream, const string& _linePrefix, const bool) +void TestCase::printSettings(ostream& _stream, const string& _linePrefix, const bool) { - if (m_validatedSettings.empty()) + auto& settings = m_reader.settings(); + if (settings.empty()) return; _stream << _linePrefix << "// ====" << endl; - for (auto const& setting: m_validatedSettings) + for (auto const& setting: settings) _stream << _linePrefix << "// " << setting.first << ": " << setting.second << endl; } @@ -53,108 +47,12 @@ bool TestCase::isTestFilename(boost::filesystem::path const& _filename) !boost::starts_with(_filename.string(), "."); } -void TestCase::validateSettings() -{ - if (!m_settings.empty()) - throw runtime_error( - "Unknown setting(s): " + - util::joinHumanReadable(m_settings | boost::adaptors::map_keys) - ); -} - bool TestCase::shouldRun() { + m_reader.ensureAllSettingsRead(); return m_shouldRun; } -pair, size_t> TestCase::parseSourcesAndSettingsWithLineNumbers(istream& _stream) -{ - map sources; - string currentSourceName; - string currentSource; - string line; - size_t lineNumber = 1; - static string const sourceDelimiterStart("==== Source:"); - static string const sourceDelimiterEnd("===="); - static string const comment("// "); - static string const settingsDelimiter("// ===="); - static string const delimiter("// ----"); - bool sourcePart = true; - while (getline(_stream, line)) - { - lineNumber++; - - if (boost::algorithm::starts_with(line, delimiter)) - break; - else if (boost::algorithm::starts_with(line, settingsDelimiter)) - sourcePart = false; - else if (sourcePart) - { - if (boost::algorithm::starts_with(line, sourceDelimiterStart) && boost::algorithm::ends_with(line, sourceDelimiterEnd)) - { - if (!(currentSourceName.empty() && currentSource.empty())) - sources[currentSourceName] = std::move(currentSource); - currentSource = {}; - currentSourceName = boost::trim_copy(line.substr( - sourceDelimiterStart.size(), - line.size() - sourceDelimiterEnd.size() - sourceDelimiterStart.size() - )); - if (sources.count(currentSourceName)) - throw runtime_error("Multiple definitions of test source \"" + currentSourceName + "\"."); - } - else - currentSource += line + "\n"; - } - else if (boost::algorithm::starts_with(line, comment)) - { - size_t colon = line.find(':'); - if (colon == string::npos) - throw runtime_error(string("Expected \":\" inside setting.")); - string key = line.substr(comment.size(), colon - comment.size()); - string value = line.substr(colon + 1); - boost::algorithm::trim(key); - boost::algorithm::trim(value); - m_settings[key] = value; - } - else - throw runtime_error(string("Expected \"//\" or \"// ---\" to terminate settings and source.")); - } - sources[currentSourceName] = currentSource; - return {sources, lineNumber}; -} - -map TestCase::parseSourcesAndSettings(istream& _stream) -{ - return get<0>(parseSourcesAndSettingsWithLineNumbers(_stream)); -} - -pair TestCase::parseSourceAndSettingsWithLineNumbers(istream& _stream) -{ - auto [sourceMap, lineOffset] = parseSourcesAndSettingsWithLineNumbers(_stream); - if (sourceMap.size() != 1) - BOOST_THROW_EXCEPTION(runtime_error("Expected single source definition, but got multiple sources.")); - return {std::move(sourceMap.begin()->second), lineOffset}; -} - -string TestCase::parseSourceAndSettings(istream& _stream) -{ - return parseSourceAndSettingsWithLineNumbers(_stream).first; -} - -string TestCase::parseSimpleExpectations(std::istream& _file) -{ - string result; - string line; - while (getline(_file, line)) - if (boost::algorithm::starts_with(line, "// ")) - result += line.substr(3) + "\n"; - else if (line == "//") - result += "\n"; - else - BOOST_THROW_EXCEPTION(runtime_error("Test expectations must start with \"// \".")); - return result; -} - void TestCase::expect(string::iterator& _it, string::iterator _end, string::value_type _c) { if (_it == _end || *_it != _c) @@ -162,18 +60,11 @@ void TestCase::expect(string::iterator& _it, string::iterator _end, string::valu ++_it; } -void EVMVersionRestrictedTestCase::validateSettings() +EVMVersionRestrictedTestCase::EVMVersionRestrictedTestCase(string const& _filename): + TestCase(_filename) { - if (!m_settings.count("EVMVersion")) - return; - - string versionString = m_settings["EVMVersion"]; - m_validatedSettings["EVMVersion"] = versionString; - m_settings.erase("EVMVersion"); - - TestCase::validateSettings(); - - if (versionString.empty()) + string versionString = m_reader.stringSetting("EVMVersion", "any"); + if (versionString == "any") return; string comparator; diff --git a/test/TestCase.h b/test/TestCase.h index d6afff8b8..0add6947b 100644 --- a/test/TestCase.h +++ b/test/TestCase.h @@ -17,16 +17,13 @@ #pragma once +#include + #include #include -#include -#include -#include #include -#include -#include namespace solidity::frontend::test { @@ -60,31 +57,27 @@ public: /// If @arg _formatted is true, color-coding may be used to indicate /// error locations in the contract, if applicable. virtual void printSource(std::ostream &_stream, std::string const &_linePrefix = "", bool const _formatted = false) const = 0; - /// Outputs the updated settings. - virtual void printUpdatedSettings(std::ostream &_stream, std::string const &_linePrefix = "", bool const _formatted = false); + /// Outputs settings. + virtual void printSettings(std::ostream &_stream, std::string const &_linePrefix = "", bool const _formatted = false); /// Outputs test expectations to @arg _stream that match the actual results of the test. /// Each line of output is prefixed with @arg _linePrefix. virtual void printUpdatedExpectations(std::ostream& _stream, std::string const& _linePrefix) const = 0; static bool isTestFilename(boost::filesystem::path const& _filename); - /// Validates the settings, i.e. moves them from m_settings to m_validatedSettings. - /// Throws a runtime exception if any setting is left at this class (i.e. unknown setting). - virtual void validateSettings(); - /// Returns true, if the test case is supported in the current environment and false /// otherwise which causes this test to be skipped. /// This might check e.g. for restrictions on the EVM version. + /// The function throws an exception if there are unread settings. bool shouldRun(); protected: - std::pair, std::size_t> parseSourcesAndSettingsWithLineNumbers(std::istream& _file); - std::map parseSourcesAndSettings(std::istream& _file); - std::pair parseSourceAndSettingsWithLineNumbers(std::istream& _file); - std::string parseSourceAndSettings(std::istream& _file); - static void expect(std::string::iterator& _it, std::string::iterator _end, std::string::value_type _c); + // Used by ASTJSONTest, the only TestCase class with a custom parser of the test files. + TestCase() = default; - static std::string parseSimpleExpectations(std::istream& _file); + TestCase(std::string const& _filename): m_reader(_filename) {} + + static void expect(std::string::iterator& _it, std::string::iterator _end, std::string::value_type _c); template static void skipWhitespace(IteratorType& _it, IteratorType _end) @@ -100,18 +93,14 @@ protected: ++_it; } - /// Parsed settings. - std::map m_settings; - /// Updated settings after validation. - std::map m_validatedSettings; - + TestCaseReader m_reader; bool m_shouldRun = true; }; class EVMVersionRestrictedTestCase: public TestCase { -public: - void validateSettings() override; +protected: + EVMVersionRestrictedTestCase(std::string const& _filename); }; } diff --git a/test/TestCaseReader.cpp b/test/TestCaseReader.cpp new file mode 100644 index 000000000..0f49a6401 --- /dev/null +++ b/test/TestCaseReader.cpp @@ -0,0 +1,164 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ + +#include + +#include + +#include +#include +#include + +using namespace std; +using namespace solidity::frontend::test; + +TestCaseReader::TestCaseReader(string const& _filename): + m_file(_filename) +{ + if (!m_file) + BOOST_THROW_EXCEPTION(runtime_error("Cannot open file: \"" + _filename + "\".")); + m_file.exceptions(ios::badbit); + + tie(m_sources, m_lineNumber) = parseSourcesAndSettingsWithLineNumber(m_file); + m_unreadSettings = m_settings; +} + +string const& TestCaseReader::source() +{ + if (m_sources.size() != 1) + BOOST_THROW_EXCEPTION(runtime_error("Expected single source definition, but got multiple sources.")); + return m_sources.begin()->second; +} + +string TestCaseReader::simpleExpectations() +{ + return parseSimpleExpectations(m_file); +} + +bool TestCaseReader::boolSetting(std::string const& _name, bool _defaultValue) +{ + if (m_settings.count(_name) == 0) + return _defaultValue; + + m_unreadSettings.erase(_name); + string value = m_settings.at(_name); + if (value == "false") + return false; + if (value == "true") + return true; + + BOOST_THROW_EXCEPTION(runtime_error("Invalid Boolean value: " + value + ".")); +} + +size_t TestCaseReader::sizetSetting(std::string const& _name, size_t _defaultValue) +{ + if (m_settings.count(_name) == 0) + return _defaultValue; + + m_unreadSettings.erase(_name); + + static_assert(sizeof(unsigned long) <= sizeof(size_t)); + return stoul(m_settings.at(_name)); +} + +string TestCaseReader::stringSetting(string const& _name, string const& _defaultValue) +{ + if (m_settings.count(_name) == 0) + return _defaultValue; + + m_unreadSettings.erase(_name); + return m_settings.at(_name); +} + +void TestCaseReader::ensureAllSettingsRead() const +{ + if (!m_unreadSettings.empty()) + throw runtime_error( + "Unknown setting(s): " + + util::joinHumanReadable(m_unreadSettings | boost::adaptors::map_keys) + ); +} + +pair, size_t> TestCaseReader::parseSourcesAndSettingsWithLineNumber(istream& _stream) +{ + map sources; + string currentSourceName; + string currentSource; + string line; + size_t lineNumber = 1; + static string const sourceDelimiterStart("==== Source:"); + static string const sourceDelimiterEnd("===="); + static string const comment("// "); + static string const settingsDelimiter("// ===="); + static string const delimiter("// ----"); + bool sourcePart = true; + while (getline(_stream, line)) + { + lineNumber++; + + if (boost::algorithm::starts_with(line, delimiter)) + break; + else if (boost::algorithm::starts_with(line, settingsDelimiter)) + sourcePart = false; + else if (sourcePart) + { + if (boost::algorithm::starts_with(line, sourceDelimiterStart) && boost::algorithm::ends_with(line, sourceDelimiterEnd)) + { + if (!(currentSourceName.empty() && currentSource.empty())) + sources[currentSourceName] = std::move(currentSource); + currentSource = {}; + currentSourceName = boost::trim_copy(line.substr( + sourceDelimiterStart.size(), + line.size() - sourceDelimiterEnd.size() - sourceDelimiterStart.size() + )); + if (sources.count(currentSourceName)) + throw runtime_error("Multiple definitions of test source \"" + currentSourceName + "\"."); + } + else + currentSource += line + "\n"; + } + else if (boost::algorithm::starts_with(line, comment)) + { + size_t colon = line.find(':'); + if (colon == string::npos) + throw runtime_error(string("Expected \":\" inside setting.")); + string key = line.substr(comment.size(), colon - comment.size()); + string value = line.substr(colon + 1); + boost::algorithm::trim(key); + boost::algorithm::trim(value); + m_settings[key] = value; + } + else + throw runtime_error(string("Expected \"//\" or \"// ---\" to terminate settings and source.")); + } + sources[currentSourceName] = currentSource; + return { sources, lineNumber }; +} + +string TestCaseReader::parseSimpleExpectations(istream& _file) +{ + string result; + string line; + while (getline(_file, line)) + if (boost::algorithm::starts_with(line, "// ")) + result += line.substr(3) + "\n"; + else if (line == "//") + result += "\n"; + else + BOOST_THROW_EXCEPTION(runtime_error("Test expectations must start with \"// \".")); + return result; +} diff --git a/test/TestCaseReader.h b/test/TestCaseReader.h new file mode 100644 index 000000000..5ab226826 --- /dev/null +++ b/test/TestCaseReader.h @@ -0,0 +1,59 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ + +#include +#include +#include + +#pragma once + +namespace solidity::frontend::test +{ +/** + * A reader for test case data file, which parses source, settings and (optionally) simple expectations. + */ +class TestCaseReader +{ +public: + TestCaseReader() = default; + explicit TestCaseReader(std::string const& _filename); + + std::map const& sources() { return m_sources; } + std::string const& source(); + std::size_t lineNumber() { return m_lineNumber; } + std::map const& settings() { return m_settings; } + std::ifstream& stream() { return m_file; } + + std::string simpleExpectations(); + + bool boolSetting(std::string const& _name, bool _defaultValue); + size_t sizetSetting(std::string const& _name, size_t _defaultValue); + std::string stringSetting(std::string const& _name, std::string const& _defaultValue); + + void ensureAllSettingsRead() const; + +private: + std::pair, std::size_t> parseSourcesAndSettingsWithLineNumber(std::istream& _file); + static std::string parseSimpleExpectations(std::istream& _file); + + std::ifstream m_file; + std::map m_sources; + std::size_t m_lineNumber = 0; + std::map m_settings; + std::map m_unreadSettings; ///< tracks which settings are left unread +}; +} diff --git a/test/boostTest.cpp b/test/boostTest.cpp index 3137a5085..5a76a3f18 100644 --- a/test/boostTest.cpp +++ b/test/boostTest.cpp @@ -94,7 +94,6 @@ int registerTests( { stringstream errorStream; auto testCase = _testCaseCreator(config); - testCase->validateSettings(); if (testCase->shouldRun()) switch (testCase->run(errorStream)) { diff --git a/test/cmdlineTests.sh b/test/cmdlineTests.sh index ece4e581c..9001c02f4 100755 --- a/test/cmdlineTests.sh +++ b/test/cmdlineTests.sh @@ -33,6 +33,7 @@ set -e REPO_ROOT=$(cd $(dirname "$0")/.. && pwd) SOLIDITY_BUILD_DIR=${SOLIDITY_BUILD_DIR:-build} source "${REPO_ROOT}/scripts/common.sh" +source "${REPO_ROOT}/scripts/common_cmdline.sh" case "$OSTYPE" in msys) @@ -45,6 +46,7 @@ case "$OSTYPE" in SOLC="$REPO_ROOT/${SOLIDITY_BUILD_DIR}/solc/solc" ;; esac +echo "${SOLC}" INTERACTIVE=true if ! tty -s || [ "$CI" ] @@ -52,8 +54,6 @@ then INTERACTIVE="" fi -FULLARGS="--optimize --ignore-missing --combined-json abi,asm,ast,bin,bin-runtime,compact-format,devdoc,hashes,interface,metadata,opcodes,srcmap,srcmap-runtime,userdoc" - # extend stack size in case we run via ASAN if [[ -n "${CIRCLECI}" ]] || [[ -n "$CI" ]]; then ulimit -s 16384 @@ -62,57 +62,6 @@ fi ## FUNCTIONS -function compileFull() -{ - local expected_exit_code=0 - local expect_output=0 - if [[ $1 = '-e' ]] - then - expected_exit_code=1 - expect_output=1 - shift; - fi - if [[ $1 = '-w' ]] - then - expect_output=1 - shift; - fi - if [[ $1 = '-o' ]] - then - expect_output=2 - shift; - fi - - local files="$*" - local output - - local stderr_path=$(mktemp) - - set +e - "$SOLC" $FULLARGS $files >/dev/null 2>"$stderr_path" - local exit_code=$? - local errors=$(grep -v -E 'Warning: This is a pre-release compiler version|Warning: Experimental features are turned on|pragma experimental ABIEncoderV2|^ +--> |^ +\||^[0-9]+ +\|' < "$stderr_path") - set -e - rm "$stderr_path" - - if [[ \ - "$exit_code" -ne "$expected_exit_code" || \ - ( $expect_output -eq 0 && -n "$errors" ) || \ - ( $expect_output -eq 1 && -z "$errors" ) \ - ]] - then - printError "Unexpected compilation result:" - printError "Expected failure: $expected_exit_code - Expected warning / error output: $expect_output" - printError "Was failure: $exit_code" - echo "$errors" - printError "While calling:" - echo "\"$SOLC\" $FULLARGS $files" - printError "Inside directory:" - pwd - false - fi -} - function ask_expectation_update() { if [ $INTERACTIVE ] diff --git a/test/libsolidity/ABIJsonTest.cpp b/test/libsolidity/ABIJsonTest.cpp index 1da0193ab..e7a0cce6d 100644 --- a/test/libsolidity/ABIJsonTest.cpp +++ b/test/libsolidity/ABIJsonTest.cpp @@ -36,15 +36,11 @@ using namespace solidity::util; using namespace solidity::frontend; using namespace solidity::frontend::test; -ABIJsonTest::ABIJsonTest(string const& _filename) +ABIJsonTest::ABIJsonTest(string const& _filename): + TestCase(_filename) { - ifstream file(_filename); - if (!file) - BOOST_THROW_EXCEPTION(runtime_error("Cannot open test contract: \"" + _filename + "\".")); - file.exceptions(ios::badbit); - - m_source = parseSourceAndSettings(file); - m_expectation = parseSimpleExpectations(file); + m_source = m_reader.source(); + m_expectation = m_reader.simpleExpectations(); } TestCase::TestResult ABIJsonTest::run(ostream& _stream, string const& _linePrefix, bool _formatted) diff --git a/test/libsolidity/ASTJSON/short_type_name_ref.json b/test/libsolidity/ASTJSON/short_type_name_ref.json index 0aa3d2984..501184c9c 100644 --- a/test/libsolidity/ASTJSON/short_type_name_ref.json +++ b/test/libsolidity/ASTJSON/short_type_name_ref.json @@ -54,7 +54,7 @@ "storageLocation": "memory", "typeDescriptions": { - "typeIdentifier": "t_array$_t_array$_t_uint256_$dyn_memory_$dyn_memory_ptr", + "typeIdentifier": "t_array$_t_array$_t_uint256_$dyn_memory_ptr_$dyn_memory_ptr", "typeString": "uint256[][]" }, "typeName": diff --git a/test/libsolidity/GasTest.cpp b/test/libsolidity/GasTest.cpp index b1b0d56f2..694839b99 100644 --- a/test/libsolidity/GasTest.cpp +++ b/test/libsolidity/GasTest.cpp @@ -36,35 +36,14 @@ using namespace std; namespace fs = boost::filesystem; using namespace boost::unit_test; -GasTest::GasTest(string const& _filename) +GasTest::GasTest(string const& _filename): + TestCase(_filename) { - ifstream file(_filename); - if (!file) - BOOST_THROW_EXCEPTION(runtime_error("Cannot open test contract: \"" + _filename + "\".")); - file.exceptions(ios::badbit); - - m_source = parseSourceAndSettings(file); - - if (m_settings.count("optimize")) - { - m_optimise = true; - m_validatedSettings["optimize"] = "true"; - m_settings.erase("optimize"); - } - if (m_settings.count("optimize-yul")) - { - m_optimiseYul = true; - m_validatedSettings["optimize-yul"] = "true"; - m_settings.erase("optimize-yul"); - } - if (m_settings.count("optimize-runs")) - { - m_optimiseRuns = stoul(m_settings["optimize-runs"]); - m_validatedSettings["optimize-runs"] = m_settings["optimize-runs"]; - m_settings.erase("optimize-runs"); - } - - parseExpectations(file); + m_source = m_reader.source(); + m_optimise = m_reader.boolSetting("optimize", false); + m_optimiseYul = m_reader.boolSetting("optimize-yul", false); + m_optimiseRuns = m_reader.sizetSetting("optimize-runs", 200); + parseExpectations(m_reader.stream()); } void GasTest::parseExpectations(std::istream& _stream) diff --git a/test/libsolidity/SMTCheckerJSONTest.cpp b/test/libsolidity/SMTCheckerJSONTest.cpp index fad5a127f..a1c23662a 100644 --- a/test/libsolidity/SMTCheckerJSONTest.cpp +++ b/test/libsolidity/SMTCheckerJSONTest.cpp @@ -135,7 +135,7 @@ TestCase::TestResult SMTCheckerJSONTest::run(ostream& _stream, string const& _li } } - return printExpectationAndError(_stream, _linePrefix, _formatted) ? TestResult::Success : TestResult::Failure; + return conclude(_stream, _linePrefix, _formatted); } vector SMTCheckerJSONTest::hashesFromJson(Json::Value const& _jsonObj, string const& _auxInput, string const& _smtlib) diff --git a/test/libsolidity/SMTCheckerTest.cpp b/test/libsolidity/SMTCheckerTest.cpp index 912349182..28c98ffab 100644 --- a/test/libsolidity/SMTCheckerTest.cpp +++ b/test/libsolidity/SMTCheckerTest.cpp @@ -28,22 +28,17 @@ using namespace solidity::frontend::test; SMTCheckerTest::SMTCheckerTest(string const& _filename, langutil::EVMVersion _evmVersion): SyntaxTest(_filename, _evmVersion) { - if (m_settings.count("SMTSolvers")) - { - auto const& choice = m_settings.at("SMTSolvers"); - if (choice == "any") - m_enabledSolvers = smt::SMTSolverChoice::All(); - else if (choice == "z3") - m_enabledSolvers = smt::SMTSolverChoice::Z3(); - else if (choice == "cvc4") - m_enabledSolvers = smt::SMTSolverChoice::CVC4(); - else if (choice == "none") - m_enabledSolvers = smt::SMTSolverChoice::None(); - else - BOOST_THROW_EXCEPTION(runtime_error("Invalid SMT solver choice.")); - } - else + auto const& choice = m_reader.stringSetting("SMTSolvers", "any"); + if (choice == "any") m_enabledSolvers = smt::SMTSolverChoice::All(); + else if (choice == "z3") + m_enabledSolvers = smt::SMTSolverChoice::Z3(); + else if (choice == "cvc4") + m_enabledSolvers = smt::SMTSolverChoice::CVC4(); + else if (choice == "none") + m_enabledSolvers = smt::SMTSolverChoice::None(); + else + BOOST_THROW_EXCEPTION(runtime_error("Invalid SMT solver choice.")); auto available = ModelChecker::availableSolvers(); if (!available.z3) @@ -62,5 +57,5 @@ TestCase::TestResult SMTCheckerTest::run(ostream& _stream, string const& _linePr parseAndAnalyze(); filterObtainedErrors(); - return printExpectationAndError(_stream, _linePrefix, _formatted) ? TestResult::Success : TestResult::Failure; + return conclude(_stream, _linePrefix, _formatted); } diff --git a/test/libsolidity/SemanticTest.cpp b/test/libsolidity/SemanticTest.cpp index 97c83a3e5..ded01f8dd 100644 --- a/test/libsolidity/SemanticTest.cpp +++ b/test/libsolidity/SemanticTest.cpp @@ -37,59 +37,42 @@ namespace fs = boost::filesystem; SemanticTest::SemanticTest(string const& _filename, langutil::EVMVersion _evmVersion): - SolidityExecutionFramework(_evmVersion) + SolidityExecutionFramework(_evmVersion), + EVMVersionRestrictedTestCase(_filename) { - ifstream file(_filename); - soltestAssert(file, "Cannot open test contract: \"" + _filename + "\"."); - file.exceptions(ios::badbit); + m_source = m_reader.source(); + m_lineOffset = m_reader.lineNumber(); - std::tie(m_source, m_lineOffset) = parseSourceAndSettingsWithLineNumbers(file); - - if (m_settings.count("compileViaYul")) + string choice = m_reader.stringSetting("compileViaYul", "false"); + if (choice == "also") { - if (m_settings["compileViaYul"] == "also") - { - m_validatedSettings["compileViaYul"] = m_settings["compileViaYul"]; - m_runWithYul = true; - m_runWithoutYul = true; - } - else - { - m_validatedSettings["compileViaYul"] = "only"; - m_runWithYul = true; - m_runWithoutYul = false; - } - m_settings.erase("compileViaYul"); + m_runWithYul = true; + m_runWithoutYul = true; } - if (m_settings.count("ABIEncoderV1Only")) + else if (choice == "true") { - if (m_settings["ABIEncoderV1Only"] == "true") - { - m_validatedSettings["ABIEncoderV1Only"] = "true"; - m_runWithABIEncoderV1Only = true; - } - m_settings.erase("ABIEncoderV1Only"); + m_runWithYul = true; + m_runWithoutYul = false; } + else if (choice == "false") + { + m_runWithYul = false; + m_runWithoutYul = true; + } + else + BOOST_THROW_EXCEPTION(runtime_error("Invalid compileViaYul value: " + choice + ".")); + m_runWithABIEncoderV1Only = m_reader.boolSetting("ABIEncoderV1Only", false); if (m_runWithABIEncoderV1Only && solidity::test::CommonOptions::get().useABIEncoderV2) m_shouldRun = false; - if (m_settings.count("revertStrings")) - { - auto revertStrings = revertStringsFromString(m_settings["revertStrings"]); - if (revertStrings) - m_revertStrings = *revertStrings; - m_validatedSettings["revertStrings"] = revertStringsToString(m_revertStrings); - m_settings.erase("revertStrings"); - } + auto revertStrings = revertStringsFromString(m_reader.stringSetting("revertStrings", "default")); + soltestAssert(revertStrings, "Invalid revertStrings setting."); + m_revertStrings = revertStrings.value(); - if (m_settings.count("allowNonExistingFunctions")) - { - m_validatedSettings["allowNonExistingFunctions"] = true; - m_settings.erase("allowNonExistingFunctions"); - } + m_allowNonExistingFunctions = m_reader.boolSetting("allowNonExistingFunctions", false); - parseExpectations(file); + parseExpectations(m_reader.stream()); soltestAssert(!m_tests.empty(), "No tests specified in " + _filename); } @@ -152,7 +135,7 @@ TestCase::TestResult SemanticTest::run(ostream& _stream, string const& _linePref else { soltestAssert( - m_validatedSettings.count("allowNonExistingFunctions") || m_compiler.methodIdentifiers(m_compiler.lastContractName()).isMember(test.call().signature), + m_allowNonExistingFunctions || m_compiler.methodIdentifiers(m_compiler.lastContractName()).isMember(test.call().signature), "The function " + test.call().signature + " is not known to the compiler" ); diff --git a/test/libsolidity/SemanticTest.h b/test/libsolidity/SemanticTest.h index 0ea486cad..94c29e193 100644 --- a/test/libsolidity/SemanticTest.h +++ b/test/libsolidity/SemanticTest.h @@ -65,6 +65,7 @@ private: bool m_runWithYul = false; bool m_runWithoutYul = true; bool m_runWithABIEncoderV1Only = false; + bool m_allowNonExistingFunctions = false; }; } diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 2c3dfebac..ae39bec0e 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -154,7 +154,6 @@ BOOST_AUTO_TEST_CASE(while_loop) ) } - BOOST_AUTO_TEST_CASE(do_while_loop) { char const* sourceCode = R"( @@ -1003,22 +1002,6 @@ BOOST_AUTO_TEST_CASE(constructor) ) } -BOOST_AUTO_TEST_CASE(balance) -{ - char const* sourceCode = R"( - contract test { - constructor() public payable {} - function getBalance() public returns (uint256 balance) { - return address(this).balance; - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 23); - ABI_CHECK(callContractFunction("getBalance()"), encodeArgs(23)); - ) -} - BOOST_AUTO_TEST_CASE(blockchain) { char const* sourceCode = R"( @@ -1660,54 +1643,6 @@ BOOST_AUTO_TEST_CASE(fixed_bytes_in_calls) ABI_CHECK(callContractFunction("callHelper(bytes2,bool)", string("\0a", 2), true), encodeArgs(string("\0a\0\0\0", 5))); } -BOOST_AUTO_TEST_CASE(constructor_arguments_internal) -{ - char const* sourceCode = R"( - contract Helper { - bytes3 name; - bool flag; - - constructor(bytes3 x, bool f) public { - name = x; - flag = f; - } - function getName() public returns (bytes3 ret) { return name; } - function getFlag() public returns (bool ret) { return flag; } - } - contract Main { - Helper h; - constructor() public { - h = new Helper("abc", true); - } - function getFlag() public returns (bool ret) { return h.getFlag(); } - function getName() public returns (bytes3 ret) { return h.getName(); } - } - )"; - compileAndRun(sourceCode, 0, "Main"); - ABI_CHECK(callContractFunction("getFlag()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("getName()"), encodeArgs("abc")); -} - -BOOST_AUTO_TEST_CASE(constructor_arguments_external) -{ - char const* sourceCode = R"( - contract Main { - bytes3 name; - bool flag; - - constructor(bytes3 x, bool f) public { - name = x; - flag = f; - } - function getName() public returns (bytes3 ret) { return name; } - function getFlag() public returns (bool ret) { return flag; } - } - )"; - compileAndRun(sourceCode, 0, "Main", encodeArgs("abc", true)); - ABI_CHECK(callContractFunction("getFlag()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("getName()"), encodeArgs("abc")); -} - BOOST_AUTO_TEST_CASE(constructor_with_long_arguments) { char const* sourceCode = R"( @@ -1736,63 +1671,6 @@ BOOST_AUTO_TEST_CASE(constructor_with_long_arguments) ABI_CHECK(callContractFunction("b()"), encodeDyn(b)); } -BOOST_AUTO_TEST_CASE(constructor_static_array_argument) -{ - char const* sourceCode = R"( - contract C { - uint public a; - uint[3] public b; - - constructor(uint _a, uint[3] memory _b) public { - a = _a; - b = _b; - } - } - )"; - compileAndRun(sourceCode, 0, "C", encodeArgs(u256(1), u256(2), u256(3), u256(4))); - ABI_CHECK(callContractFunction("a()"), encodeArgs(u256(1))); - ABI_CHECK(callContractFunction("b(uint256)", u256(0)), encodeArgs(u256(2))); - ABI_CHECK(callContractFunction("b(uint256)", u256(1)), encodeArgs(u256(3))); - ABI_CHECK(callContractFunction("b(uint256)", u256(2)), encodeArgs(u256(4))); -} - -BOOST_AUTO_TEST_CASE(constant_var_as_array_length) -{ - char const* sourceCode = R"( - contract C { - uint constant LEN = 3; - uint[LEN] public a; - - constructor(uint[LEN] memory _a) public { - a = _a; - } - } - )"; - compileAndRun(sourceCode, 0, "C", encodeArgs(u256(1), u256(2), u256(3))); - ABI_CHECK(callContractFunction("a(uint256)", u256(0)), encodeArgs(u256(1))); - ABI_CHECK(callContractFunction("a(uint256)", u256(1)), encodeArgs(u256(2))); - ABI_CHECK(callContractFunction("a(uint256)", u256(2)), encodeArgs(u256(3))); -} - -BOOST_AUTO_TEST_CASE(functions_called_by_constructor) -{ - char const* sourceCode = R"( - contract Test { - bytes3 name; - bool flag; - constructor() public { - setName("abc"); - } - function getName() public returns (bytes3 ret) { return name; } - function setName(bytes3 _name) private { name = _name; } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - BOOST_REQUIRE(callContractFunction("getName()") == encodeArgs("abc")); - ) -} - BOOST_AUTO_TEST_CASE(contracts_as_addresses) { char const* sourceCode = R"( @@ -1813,97 +1691,6 @@ BOOST_AUTO_TEST_CASE(contracts_as_addresses) BOOST_REQUIRE(callContractFunction("getBalance()") == encodeArgs(u256(20 - 5), u256(5))); } -BOOST_AUTO_TEST_CASE(gas_and_value_basic) -{ - char const* sourceCode = R"( - contract helper { - bool flag; - function getBalance() payable public returns (uint256 myBalance) { - return address(this).balance; - } - function setFlag() public { flag = true; } - function getFlag() public returns (bool fl) { return flag; } - } - contract test { - helper h; - constructor() public payable { h = new helper(); } - function sendAmount(uint amount) public payable returns (uint256 bal) { - return h.getBalance.value(amount)(); - } - function outOfGas() public returns (bool ret) { - h.setFlag.gas(2)(); // should fail due to OOG - return true; - } - function checkState() public returns (bool flagAfter, uint myBal) { - flagAfter = h.getFlag(); - myBal = address(this).balance; - } - } - )"; - compileAndRun(sourceCode, 20); - BOOST_REQUIRE(callContractFunction("sendAmount(uint256)", 5) == encodeArgs(5)); - // call to helper should not succeed but amount should be transferred anyway - BOOST_REQUIRE(callContractFunction("outOfGas()") == bytes()); - BOOST_REQUIRE(callContractFunction("checkState()") == encodeArgs(false, 20 - 5)); -} - -BOOST_AUTO_TEST_CASE(gas_and_value_brace_syntax) -{ - char const* sourceCode = R"( - contract helper { - bool flag; - function getBalance() payable public returns (uint256 myBalance) { - return address(this).balance; - } - function setFlag() public { flag = true; } - function getFlag() public returns (bool fl) { return flag; } - } - contract test { - helper h; - constructor() public payable { h = new helper(); } - function sendAmount(uint amount) public payable returns (uint256 bal) { - return h.getBalance{value: amount}(); - } - function outOfGas() public returns (bool ret) { - h.setFlag{gas: 2}(); // should fail due to OOG - return true; - } - function checkState() public returns (bool flagAfter, uint myBal) { - flagAfter = h.getFlag(); - myBal = address(this).balance; - } - } - )"; - compileAndRun(sourceCode, 20); - BOOST_REQUIRE(callContractFunction("sendAmount(uint256)", 5) == encodeArgs(5)); - // call to helper should not succeed but amount should be transferred anyway - BOOST_REQUIRE(callContractFunction("outOfGas()") == bytes()); - BOOST_REQUIRE(callContractFunction("checkState()") == encodeArgs(false, 20 - 5)); -} - -BOOST_AUTO_TEST_CASE(gasleft_decrease) -{ - char const* sourceCode = R"( - contract C { - uint v; - function f() public returns (bool) { - uint startGas = gasleft(); - v++; - assert(startGas > gasleft()); - return true; - } - function g() public returns (bool) { - uint startGas = gasleft(); - assert(startGas > gasleft()); - return true; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("g()"), encodeArgs(true)); -} - BOOST_AUTO_TEST_CASE(gaslimit) { char const* sourceCode = R"( @@ -1966,221 +1753,6 @@ BOOST_AUTO_TEST_CASE(blockhash) ABI_CHECK(callContractFunction("f()"), encodeDyn(hashes)); } -BOOST_AUTO_TEST_CASE(value_complex) -{ - char const* sourceCode = R"( - contract helper { - function getBalance() payable public returns (uint256 myBalance) { - return address(this).balance; - } - } - contract test { - helper h; - constructor() public payable { h = new helper(); } - function sendAmount(uint amount) public payable returns (uint256 bal) { - uint someStackElement = 20; - return h.getBalance.value(amount).gas(1000).value(amount + 3)(); - } - } - )"; - compileAndRun(sourceCode, 20); - BOOST_REQUIRE(callContractFunction("sendAmount(uint256)", 5) == encodeArgs(8)); -} - -BOOST_AUTO_TEST_CASE(value_insane) -{ - char const* sourceCode = R"( - contract helper { - function getBalance() payable public returns (uint256 myBalance) { - return address(this).balance; - } - } - contract test { - helper h; - constructor() public payable { h = new helper(); } - function sendAmount(uint amount) public returns (uint256 bal) { - return h.getBalance.value(amount).gas(1000).value(amount + 3)();// overwrite value - } - } - )"; - compileAndRun(sourceCode, 20); - BOOST_REQUIRE(callContractFunction("sendAmount(uint256)", 5) == encodeArgs(8)); -} - -BOOST_AUTO_TEST_CASE(value_for_constructor) -{ - char const* sourceCode = R"( - contract Helper { - bytes3 name; - bool flag; - constructor(bytes3 x, bool f) public payable { - name = x; - flag = f; - } - function getName() public returns (bytes3 ret) { return name; } - function getFlag() public returns (bool ret) { return flag; } - } - contract Main { - Helper h; - constructor() public payable { - h = (new Helper).value(10)("abc", true); - } - function getFlag() public returns (bool ret) { return h.getFlag(); } - function getName() public returns (bytes3 ret) { return h.getName(); } - function getBalances() public returns (uint me, uint them) { me = address(this).balance; them = address(h).balance;} - } - )"; - compileAndRun(sourceCode, 22, "Main"); - BOOST_REQUIRE(callContractFunction("getFlag()") == encodeArgs(true)); - BOOST_REQUIRE(callContractFunction("getName()") == encodeArgs("abc")); - BOOST_REQUIRE(callContractFunction("getBalances()") == encodeArgs(12, 10)); -} - -BOOST_AUTO_TEST_CASE(virtual_function_calls) -{ - char const* sourceCode = R"( - contract Base { - function f() public returns (uint i) { return g(); } - function g() public virtual returns (uint i) { return 1; } - } - contract Derived is Base { - function g() public override returns (uint i) { return 2; } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "Derived"); - ABI_CHECK(callContractFunction("g()"), encodeArgs(2)); - ABI_CHECK(callContractFunction("f()"), encodeArgs(2)); - ) -} - -BOOST_AUTO_TEST_CASE(access_base_storage) -{ - char const* sourceCode = R"( - contract Base { - uint dataBase; - function getViaBase() public returns (uint i) { return dataBase; } - } - contract Derived is Base { - uint dataDerived; - function setData(uint base, uint derived) public returns (bool r) { - dataBase = base; - dataDerived = derived; - return true; - } - function getViaDerived() public returns (uint base, uint derived) { - base = dataBase; - derived = dataDerived; - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "Derived"); - ABI_CHECK(callContractFunction("setData(uint256,uint256)", 1, 2), encodeArgs(true)); - ABI_CHECK(callContractFunction("getViaBase()"), encodeArgs(1)); - ABI_CHECK(callContractFunction("getViaDerived()"), encodeArgs(1, 2)); - ) -} - -BOOST_AUTO_TEST_CASE(single_copy_with_multiple_inheritance) -{ - char const* sourceCode = R"( - contract Base { - uint data; - function setData(uint i) public { data = i; } - function getViaBase() public returns (uint i) { return data; } - } - contract A is Base { function setViaA(uint i) public { setData(i); } } - contract B is Base { function getViaB() public returns (uint i) { return getViaBase(); } } - contract Derived is Base, B, A { } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "Derived"); - ABI_CHECK(callContractFunction("getViaB()"), encodeArgs(0)); - ABI_CHECK(callContractFunction("setViaA(uint256)", 23), encodeArgs()); - ABI_CHECK(callContractFunction("getViaB()"), encodeArgs(23)); - ) -} - -BOOST_AUTO_TEST_CASE(explicit_base_class) -{ - char const* sourceCode = R"( - contract BaseBase { function g() public virtual returns (uint r) { return 1; } } - contract Base is BaseBase { function g() public virtual override returns (uint r) { return 2; } } - contract Derived is Base { - function f() public returns (uint r) { return BaseBase.g(); } - function g() public override returns (uint r) { return 3; } - } - )"; - compileAndRun(sourceCode, 0, "Derived"); - ABI_CHECK(callContractFunction("g()"), encodeArgs(3)); - ABI_CHECK(callContractFunction("f()"), encodeArgs(1)); -} - -BOOST_AUTO_TEST_CASE(base_constructor_arguments) -{ - char const* sourceCode = R"( - contract BaseBase { - uint m_a; - constructor(uint a) public { - m_a = a; - } - } - contract Base is BaseBase(7) { - constructor() public { - m_a *= m_a; - } - } - contract Derived is Base() { - function getA() public returns (uint r) { return m_a; } - } - )"; - compileAndRun(sourceCode, 0, "Derived"); - ABI_CHECK(callContractFunction("getA()"), encodeArgs(7 * 7)); -} - -BOOST_AUTO_TEST_CASE(function_usage_in_constructor_arguments) -{ - char const* sourceCode = R"( - contract BaseBase { - uint m_a; - constructor(uint a) public { - m_a = a; - } - function g() public returns (uint r) { return 2; } - } - contract Base is BaseBase(BaseBase.g()) { - } - contract Derived is Base() { - function getA() public returns (uint r) { return m_a; } - } - )"; - compileAndRun(sourceCode, 0, "Derived"); - ABI_CHECK(callContractFunction("getA()"), encodeArgs(2)); -} - -BOOST_AUTO_TEST_CASE(virtual_function_usage_in_constructor_arguments) -{ - char const* sourceCode = R"( - contract BaseBase { - uint m_a; - constructor(uint a) public { - m_a = a; - } - function overridden() public virtual returns (uint r) { return 1; } - function g() public returns (uint r) { return overridden(); } - } - contract Base is BaseBase(BaseBase.g()) { - } - contract Derived is Base() { - function getA() public returns (uint r) { return m_a; } - function overridden() public override returns (uint r) { return 2; } - } - )"; - compileAndRun(sourceCode, 0, "Derived"); - ABI_CHECK(callContractFunction("getA()"), encodeArgs(2)); -} - BOOST_AUTO_TEST_CASE(internal_constructor) { char const* sourceCode = R"( @@ -2191,260 +1763,6 @@ BOOST_AUTO_TEST_CASE(internal_constructor) BOOST_CHECK(compileAndRunWithoutCheck(sourceCode, 0, "C").empty()); } -BOOST_AUTO_TEST_CASE(function_modifier) -{ - char const* sourceCode = R"( - contract C { - function getOne() payable nonFree public returns (uint r) { return 1; } - modifier nonFree { if (msg.value > 0) _; } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("getOne()"), encodeArgs(0)); - ABI_CHECK(callContractFunctionWithValue("getOne()", 1), encodeArgs(1)); -} - -BOOST_AUTO_TEST_CASE(function_modifier_local_variables) -{ - char const* sourceCode = R"( - contract C { - modifier mod1 { uint8 a = 1; uint8 b = 2; _; } - modifier mod2(bool a) { if (a) return; else _; } - function f(bool a) mod1 mod2(a) public returns (uint r) { return 3; } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f(bool)", true), encodeArgs(0)); - ABI_CHECK(callContractFunction("f(bool)", false), encodeArgs(3)); -} - -BOOST_AUTO_TEST_CASE(function_modifier_loop) -{ - char const* sourceCode = R"( - contract C { - modifier repeat(uint count) { uint i; for (i = 0; i < count; ++i) _; } - function f() repeat(10) public returns (uint r) { r += 1; } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(10)); -} - -BOOST_AUTO_TEST_CASE(function_modifier_multi_invocation) -{ - char const* sourceCode = R"( - contract C { - modifier repeat(bool twice) { if (twice) _; _; } - function f(bool twice) repeat(twice) public returns (uint r) { r += 1; } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f(bool)", false), encodeArgs(1)); - ABI_CHECK(callContractFunction("f(bool)", true), encodeArgs(2)); -} - -BOOST_AUTO_TEST_CASE(function_modifier_multi_with_return) -{ - // Note that return sets the return variable and jumps to the end of the current function or - // modifier code block. - char const* sourceCode = R"( - contract C { - modifier repeat(bool twice) { if (twice) _; _; } - function f(bool twice) repeat(twice) public returns (uint r) { r += 1; return r; } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f(bool)", false), encodeArgs(1)); - ABI_CHECK(callContractFunction("f(bool)", true), encodeArgs(2)); -} - -BOOST_AUTO_TEST_CASE(function_modifier_overriding) -{ - char const* sourceCode = R"( - contract A { - function f() mod public returns (bool r) { return true; } - modifier mod virtual { _; } - } - contract C is A { - modifier mod override { if (false) _; } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(false)); -} - -BOOST_AUTO_TEST_CASE(function_modifier_calling_functions_in_creation_context) -{ - char const* sourceCode = R"( - contract A { - uint data; - constructor() mod1 public { f1(); } - function f1() mod2 public { data |= 0x1; } - function f2() public { data |= 0x20; } - function f3() public virtual { } - modifier mod1 virtual { f2(); _; } - modifier mod2 { f3(); if (false) _; } - function getData() public returns (uint r) { return data; } - } - contract C is A { - modifier mod1 override { f4(); _; } - function f3() public override { data |= 0x300; } - function f4() public { data |= 0x4000; } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("getData()"), encodeArgs(0x4300)); -} - -BOOST_AUTO_TEST_CASE(function_modifier_for_constructor) -{ - char const* sourceCode = R"( - contract A { - uint data; - constructor() mod1 public { data |= 2; } - modifier mod1 virtual { data |= 1; _; } - function getData() public returns (uint r) { return data; } - } - contract C is A { - modifier mod1 override { data |= 4; _; } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("getData()"), encodeArgs(4 | 2)); -} - -BOOST_AUTO_TEST_CASE(function_modifier_multiple_times) -{ - char const* sourceCode = R"( - contract C { - uint public a; - modifier mod(uint x) { a += x; _; } - function f(uint x) mod(2) mod(5) mod(x) public returns(uint) { return a; } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f(uint256)", u256(3)), encodeArgs(2 + 5 + 3)); - ABI_CHECK(callContractFunction("a()"), encodeArgs(2 + 5 + 3)); -} - -BOOST_AUTO_TEST_CASE(function_modifier_multiple_times_local_vars) -{ - char const* sourceCode = R"( - contract C { - uint public a; - modifier mod(uint x) { uint b = x; a += b; _; a -= b; assert(b == x); } - function f(uint x) mod(2) mod(5) mod(x) public returns(uint) { return a; } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f(uint256)", u256(3)), encodeArgs(2 + 5 + 3)); - ABI_CHECK(callContractFunction("a()"), encodeArgs(0)); -} - -BOOST_AUTO_TEST_CASE(function_modifier_library) -{ - char const* sourceCode = R"( - library L { - struct S { uint v; } - modifier mod(S storage s) { s.v++; _; } - function libFun(S storage s) mod(s) internal { s.v += 0x100; } - } - - contract Test { - using L for *; - L.S s; - - function f() public returns (uint) { - s.libFun(); - L.libFun(s); - return s.v; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(0x202)); -} - -BOOST_AUTO_TEST_CASE(function_modifier_library_inheritance) -{ - // Tests that virtual lookup for modifiers in libraries does not consider - // the current inheritance hierarchy. - - char const* sourceCode = R"( - library L { - struct S { uint v; } - modifier mod(S storage s) { s.v++; _; } - function libFun(S storage s) mod(s) internal { s.v += 0x100; } - } - - contract Test { - using L for *; - L.S s; - modifier mod(L.S storage) { revert(); _; } - - function f() public returns (uint) { - s.libFun(); - L.libFun(s); - return s.v; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(0x202)); -} - -BOOST_AUTO_TEST_CASE(crazy_elementary_typenames_on_stack) -{ - char const* sourceCode = R"( - contract C { - function f() public returns (uint r) { - uint; uint; uint; uint; - int x = -7; - return uint(x); - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(-7))); - ) -} - -BOOST_AUTO_TEST_CASE(super) -{ - char const* sourceCode = R"( - contract A { function f() public virtual returns (uint r) { return 1; } } - contract B is A { function f() public virtual override returns (uint r) { return super.f() | 2; } } - contract C is A { function f() public virtual override returns (uint r) { return super.f() | 4; } } - contract D is B, C { function f() public override(B, C) returns (uint r) { return super.f() | 8; } } - )"; - compileAndRun(sourceCode, 0, "D"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(1 | 2 | 4 | 8)); -} - -BOOST_AUTO_TEST_CASE(super_in_constructor) -{ - char const* sourceCode = R"( - contract A { function f() public virtual returns (uint r) { return 1; } } - contract B is A { function f() public virtual override returns (uint r) { return super.f() | 2; } } - contract C is A { function f() public virtual override returns (uint r) { return super.f() | 4; } } - contract D is B, C { uint data; constructor() public { data = super.f() | 8; } function f() public override (B, C) returns (uint r) { return data; } } - )"; - compileAndRun(sourceCode, 0, "D"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(1 | 2 | 4 | 8)); -} - -BOOST_AUTO_TEST_CASE(super_alone) -{ - char const* sourceCode = R"( - contract A { function f() public { super; } } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "A"); - ABI_CHECK(callContractFunction("f()"), encodeArgs()); - ) -} - BOOST_AUTO_TEST_CASE(default_fallback_throws) { char const* sourceCode = R"YY( @@ -3085,62 +2403,6 @@ BOOST_AUTO_TEST_CASE(empty_name_input_parameter_with_named_one) ) } -BOOST_AUTO_TEST_CASE(empty_name_return_parameter) -{ - char const* sourceCode = R"( - contract test { - function f(uint k) public returns(uint){ - return k; - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f(uint256)", 9), encodeArgs(9)); - ) -} - -BOOST_AUTO_TEST_CASE(sha256_empty) -{ - char const* sourceCode = R"( - contract C { - function f() public returns (bytes32) { - return sha256(""); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), fromHex("0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")); -} - -BOOST_AUTO_TEST_CASE(ripemd160_empty) -{ - char const* sourceCode = R"( - contract C { - function f() public returns (bytes20) { - return ripemd160(""); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), fromHex("0x9c1185a5c5e9fc54612808977ee8f548b2258d31000000000000000000000000")); -} - -BOOST_AUTO_TEST_CASE(keccak256_empty) -{ - char const* sourceCode = R"( - contract C { - function f() public returns (bytes32) { - return keccak256(""); - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), fromHex("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")); - ) -} - BOOST_AUTO_TEST_CASE(keccak256_multiple_arguments) { char const* sourceCode = R"( @@ -3211,24 +2473,6 @@ BOOST_AUTO_TEST_CASE(keccak256_multiple_arguments_with_string_literals) )); } -BOOST_AUTO_TEST_CASE(keccak256_with_bytes) -{ - char const* sourceCode = R"( - contract c { - bytes data; - function foo() public returns (bool) - { - data.push("f"); - data.push("o"); - data.push("o"); - return keccak256(data) == keccak256("foo"); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("foo()"), encodeArgs(true)); -} - BOOST_AUTO_TEST_CASE(iterated_keccak256_with_bytes) { char const* sourceCode = R"ABC( @@ -3414,7 +2658,6 @@ BOOST_AUTO_TEST_CASE(library_call_protection) ABI_CHECK(callContractFunction("pu()"), encodeArgs(2)); } - BOOST_AUTO_TEST_CASE(library_staticcall_delegatecall) { char const* sourceCode = R"( @@ -3439,25 +2682,6 @@ BOOST_AUTO_TEST_CASE(library_staticcall_delegatecall) ABI_CHECK(callContractFunction("f()"), encodeArgs(1)); } -BOOST_AUTO_TEST_CASE(store_bytes) -{ - // this test just checks that the copy loop does not mess up the stack - char const* sourceCode = R"( - contract C { - function save() public returns (uint r) { - r = 23; - savedData = msg.data; - r = 24; - } - bytes savedData; - } - )"; - compileAndRun(sourceCode); - // empty copy loop - ABI_CHECK(callContractFunction("save()"), encodeArgs(24)); - ABI_CHECK(callContractFunction("save()", "abcdefg"), encodeArgs(24)); -} - BOOST_AUTO_TEST_CASE(bytes_from_calldata_to_memory) { char const* sourceCode = R"( @@ -3655,61 +2879,6 @@ BOOST_AUTO_TEST_CASE(bytes_inside_mappings) BOOST_CHECK(storageEmpty(m_contractAddress)); } -BOOST_AUTO_TEST_CASE(bytes_length_member) -{ - char const* sourceCode = R"( - contract c { - function set() public returns (bool) { data = msg.data; return true; } - function getLength() public returns (uint) { return data.length; } - bytes data; - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("getLength()"), encodeArgs(0)); - ABI_CHECK(callContractFunction("set()", 1, 2), encodeArgs(true)); - ABI_CHECK(callContractFunction("getLength()"), encodeArgs(4+32+32)); -} - -BOOST_AUTO_TEST_CASE(struct_copy) -{ - char const* sourceCode = R"( - contract c { - struct Nested { uint x; uint y; } - struct Struct { uint a; mapping(uint => Struct) b; Nested nested; uint c; } - mapping(uint => Struct) data; - function set(uint k) public returns (bool) { - data[k].a = 1; - data[k].nested.x = 3; - data[k].nested.y = 4; - data[k].c = 2; - return true; - } - function copy(uint from, uint to) public returns (bool) { - data[to] = data[from]; - return true; - } - function retrieve(uint k) public returns (uint a, uint x, uint y, uint c) - { - a = data[k].a; - x = data[k].nested.x; - y = data[k].nested.y; - c = data[k].c; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("set(uint256)", 7), encodeArgs(true)); - ABI_CHECK(callContractFunction("retrieve(uint256)", 7), encodeArgs(1, 3, 4, 2)); - ABI_CHECK(callContractFunction("copy(uint256,uint256)", 7, 8), encodeArgs(true)); - ABI_CHECK(callContractFunction("retrieve(uint256)", 7), encodeArgs(1, 3, 4, 2)); - ABI_CHECK(callContractFunction("retrieve(uint256)", 8), encodeArgs(1, 3, 4, 2)); - ABI_CHECK(callContractFunction("copy(uint256,uint256)", 0, 7), encodeArgs(true)); - ABI_CHECK(callContractFunction("retrieve(uint256)", 7), encodeArgs(0, 0, 0, 0)); - ABI_CHECK(callContractFunction("retrieve(uint256)", 8), encodeArgs(1, 3, 4, 2)); - ABI_CHECK(callContractFunction("copy(uint256,uint256)", 7, 8), encodeArgs(true)); - ABI_CHECK(callContractFunction("retrieve(uint256)", 8), encodeArgs(0, 0, 0, 0)); -} - BOOST_AUTO_TEST_CASE(struct_containing_bytes_copy_and_delete) { char const* sourceCode = R"( @@ -3746,84 +2915,6 @@ BOOST_AUTO_TEST_CASE(struct_containing_bytes_copy_and_delete) BOOST_CHECK(storageEmpty(m_contractAddress)); } -BOOST_AUTO_TEST_CASE(struct_copy_via_local) -{ - char const* sourceCode = R"( - contract c { - struct Struct { uint a; uint b; } - Struct data1; - Struct data2; - function test() public returns (bool) { - data1.a = 1; - data1.b = 2; - Struct memory x = data1; - data2 = x; - return data2.a == data1.a && data2.b == data1.b; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(true)); -} - -BOOST_AUTO_TEST_CASE(using_enums) -{ - char const* sourceCode = R"( - contract test { - enum ActionChoices { GoLeft, GoRight, GoStraight, Sit } - constructor() public - { - choices = ActionChoices.GoStraight; - } - function getChoice() public returns (uint d) - { - d = uint256(choices); - } - ActionChoices choices; - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("getChoice()"), encodeArgs(2)); -} - -BOOST_AUTO_TEST_CASE(enum_explicit_overflow) -{ - char const* sourceCode = R"( - contract test { - enum ActionChoices { GoLeft, GoRight, GoStraight } - constructor() public - { - } - function getChoiceExp(uint x) public returns (uint d) - { - choice = ActionChoices(x); - d = uint256(choice); - } - function getChoiceFromSigned(int x) public returns (uint d) - { - choice = ActionChoices(x); - d = uint256(choice); - } - function getChoiceFromNegativeLiteral() public returns (uint d) - { - choice = ActionChoices(-1); - d = uint256(choice); - } - ActionChoices choice; - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - // These should throw - ABI_CHECK(callContractFunction("getChoiceExp(uint256)", 3), encodeArgs()); - ABI_CHECK(callContractFunction("getChoiceFromSigned(int256)", -1), encodeArgs()); - ABI_CHECK(callContractFunction("getChoiceFromNegativeLiteral()"), encodeArgs()); - // These should work - ABI_CHECK(callContractFunction("getChoiceExp(uint256)", 2), encodeArgs(2)); - ABI_CHECK(callContractFunction("getChoiceExp(uint256)", 0), encodeArgs(0)); - ) -} - BOOST_AUTO_TEST_CASE(storing_invalid_boolean) { char const* sourceCode = R"( @@ -3867,75 +2958,6 @@ BOOST_AUTO_TEST_CASE(storing_invalid_boolean) BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Ev(bool)"))); } - -BOOST_AUTO_TEST_CASE(using_contract_enums_with_explicit_contract_name) -{ - char const* sourceCode = R"( - contract test { - enum Choice { A, B, C } - function answer () public returns (test.Choice _ret) - { - _ret = test.Choice.B; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("answer()"), encodeArgs(1)); -} - -BOOST_AUTO_TEST_CASE(using_inherited_enum) -{ - char const* sourceCode = R"( - contract base { - enum Choice { A, B, C } - } - - contract test is base { - function answer () public returns (Choice _ret) - { - _ret = Choice.B; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("answer()"), encodeArgs(1)); -} - -BOOST_AUTO_TEST_CASE(using_inherited_enum_excplicitly) -{ - char const* sourceCode = R"( - contract base { - enum Choice { A, B, C } - } - - contract test is base { - function answer () public returns (base.Choice _ret) - { - _ret = base.Choice.B; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("answer()"), encodeArgs(1)); -} - -BOOST_AUTO_TEST_CASE(constructing_enums_from_ints) -{ - char const* sourceCode = R"( - contract c { - enum Truth { False, True } - function test() public returns (uint) - { - return uint(Truth(uint8(0x701))); - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(1)); - ) -} - BOOST_AUTO_TEST_CASE(struct_referencing) { static char const* sourceCode = R"( @@ -4042,80 +3064,6 @@ BOOST_AUTO_TEST_CASE(enum_referencing) ABI_CHECK(callContractFunction("y()"), encodeArgs(3)); } -BOOST_AUTO_TEST_CASE(inline_member_init) -{ - char const* sourceCode = R"( - contract test { - constructor() public { - m_b = 6; - m_c = 8; - } - uint m_a = 5; - uint m_b; - uint m_c = 7; - function get() public returns (uint a, uint b, uint c){ - a = m_a; - b = m_b; - c = m_c; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("get()"), encodeArgs(5, 6, 8)); -} -BOOST_AUTO_TEST_CASE(inline_member_init_inheritence) -{ - char const* sourceCode = R"( - contract Base { - constructor() public {} - uint m_base = 5; - function getBMember() public returns (uint i) { return m_base; } - } - contract Derived is Base { - constructor() public {} - uint m_derived = 6; - function getDMember() public returns (uint i) { return m_derived; } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("getBMember()"), encodeArgs(5)); - ABI_CHECK(callContractFunction("getDMember()"), encodeArgs(6)); -} - -BOOST_AUTO_TEST_CASE(inline_member_init_inheritence_without_constructor) -{ - char const* sourceCode = R"( - contract Base { - uint m_base = 5; - function getBMember() public returns (uint i) { return m_base; } - } - contract Derived is Base { - uint m_derived = 6; - function getDMember() public returns (uint i) { return m_derived; } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("getBMember()"), encodeArgs(5)); - ABI_CHECK(callContractFunction("getDMember()"), encodeArgs(6)); -} - -BOOST_AUTO_TEST_CASE(external_function) -{ - char const* sourceCode = R"( - contract c { - function f(uint a) public returns (uint) { return a; } - function test(uint a, uint b) external returns (uint r_a, uint r_b) { - r_a = f(a + 7); - r_b = b; - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test(uint256,uint256)", 2, 3), encodeArgs(2+7, 3)); - ) -} - BOOST_AUTO_TEST_CASE(bytes_in_arguments) { char const* sourceCode = R"( @@ -4174,93 +3122,6 @@ BOOST_AUTO_TEST_CASE(fixed_arrays_in_storage) ABI_CHECK(callContractFunction("getLengths()"), encodeArgs(u256(1) << 10, (u256(1) << 10) + 3)); } -BOOST_AUTO_TEST_CASE(dynamic_arrays_in_storage) -{ - char const* sourceCode = R"( - contract c { - struct Data { uint x; uint y; } - Data[] data; - uint[] ids; - function setIDStatic(uint id) public { ids[2] = id; } - function setID(uint index, uint id) public { ids[index] = id; } - function setData(uint index, uint x, uint y) public { data[index].x = x; data[index].y = y; } - function getID(uint index) public returns (uint) { return ids[index]; } - function getData(uint index) public returns (uint x, uint y) { x = data[index].x; y = data[index].y; } - function getLengths() public returns (uint l1, uint l2) { l1 = data.length; l2 = ids.length; } - function setLengths(uint l1, uint l2) public { - while (data.length < l1) - data.push(); - while (ids.length < l2) - ids.push(); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("getLengths()"), encodeArgs(0, 0)); - ABI_CHECK(callContractFunction("setLengths(uint256,uint256)", 48, 49), bytes()); - ABI_CHECK(callContractFunction("getLengths()"), encodeArgs(48, 49)); - ABI_CHECK(callContractFunction("setIDStatic(uint256)", 11), bytes()); - ABI_CHECK(callContractFunction("getID(uint256)", 2), encodeArgs(11)); - ABI_CHECK(callContractFunction("setID(uint256,uint256)", 7, 8), bytes()); - ABI_CHECK(callContractFunction("getID(uint256)", 7), encodeArgs(8)); - ABI_CHECK(callContractFunction("setData(uint256,uint256,uint256)", 7, 8, 9), bytes()); - ABI_CHECK(callContractFunction("setData(uint256,uint256,uint256)", 8, 10, 11), bytes()); - ABI_CHECK(callContractFunction("getData(uint256)", 7), encodeArgs(8, 9)); - ABI_CHECK(callContractFunction("getData(uint256)", 8), encodeArgs(10, 11)); -} - -BOOST_AUTO_TEST_CASE(fixed_out_of_bounds_array_access) -{ - char const* sourceCode = R"( - contract c { - uint[4] data; - function set(uint index, uint value) public returns (bool) { data[index] = value; return true; } - function get(uint index) public returns (uint) { return data[index]; } - function length() public returns (uint) { return data.length; } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("length()"), encodeArgs(4)); - ABI_CHECK(callContractFunction("set(uint256,uint256)", 3, 4), encodeArgs(true)); - ABI_CHECK(callContractFunction("set(uint256,uint256)", 4, 5), bytes()); - ABI_CHECK(callContractFunction("set(uint256,uint256)", 400, 5), bytes()); - ABI_CHECK(callContractFunction("get(uint256)", 3), encodeArgs(4)); - ABI_CHECK(callContractFunction("get(uint256)", 4), bytes()); - ABI_CHECK(callContractFunction("get(uint256)", 400), bytes()); - ABI_CHECK(callContractFunction("length()"), encodeArgs(4)); - ) -} - -BOOST_AUTO_TEST_CASE(dynamic_out_of_bounds_array_access) -{ - char const* sourceCode = R"( - contract c { - uint[] data; - function enlarge(uint amount) public returns (uint) { - while (data.length < amount) - data.push(); - return data.length; - } - function set(uint index, uint value) public returns (bool) { data[index] = value; return true; } - function get(uint index) public returns (uint) { return data[index]; } - function length() public returns (uint) { return data.length; } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("length()"), encodeArgs(0)); - ABI_CHECK(callContractFunction("get(uint256)", 3), bytes()); - ABI_CHECK(callContractFunction("enlarge(uint256)", 4), encodeArgs(4)); - ABI_CHECK(callContractFunction("length()"), encodeArgs(4)); - ABI_CHECK(callContractFunction("set(uint256,uint256)", 3, 4), encodeArgs(true)); - ABI_CHECK(callContractFunction("get(uint256)", 3), encodeArgs(4)); - ABI_CHECK(callContractFunction("length()"), encodeArgs(4)); - ABI_CHECK(callContractFunction("set(uint256,uint256)", 4, 8), bytes()); - ABI_CHECK(callContractFunction("length()"), encodeArgs(4)); - ); -} - BOOST_AUTO_TEST_CASE(fixed_array_cleanup) { char const* sourceCode = R"( @@ -4390,103 +3251,6 @@ BOOST_AUTO_TEST_CASE(array_copy_storage_storage_dyn_dyn) BOOST_CHECK(storageEmpty(m_contractAddress)); } -BOOST_AUTO_TEST_CASE(array_copy_storage_storage_static_static) -{ - char const* sourceCode = R"( - contract c { - uint[40] data1; - uint[20] data2; - function test() public returns (uint x, uint y){ - data1[30] = 4; - data1[2] = 7; - data1[3] = 9; - data2[3] = 8; - data1 = data2; - x = data1[3]; - y = data1[30]; // should be cleared - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(8, 0)); -} - -BOOST_AUTO_TEST_CASE(array_copy_storage_storage_static_dynamic) -{ - char const* sourceCode = R"( - contract c { - uint[9] data1; - uint[] data2; - function test() public returns (uint x, uint y){ - data1[8] = 4; - data2 = data1; - x = data2.length; - y = data2[8]; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(9, 4)); -} - -BOOST_AUTO_TEST_CASE(array_copy_different_packing) -{ - char const* sourceCode = R"( - contract c { - bytes8[] data1; // 4 per slot - bytes10[] data2; // 3 per slot - function test() public returns (bytes10 a, bytes10 b, bytes10 c, bytes10 d, bytes10 e) { - data1 = new bytes8[](9); - for (uint i = 0; i < data1.length; ++i) - data1[i] = bytes8(uint64(i)); - data2 = data1; - a = data2[1]; - b = data2[2]; - c = data2[3]; - d = data2[4]; - e = data2[5]; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs( - asString(fromHex("0000000000000001")), - asString(fromHex("0000000000000002")), - asString(fromHex("0000000000000003")), - asString(fromHex("0000000000000004")), - asString(fromHex("0000000000000005")) - )); -} - -BOOST_AUTO_TEST_CASE(array_copy_target_simple) -{ - char const* sourceCode = R"( - contract c { - bytes8[9] data1; // 4 per slot - bytes17[10] data2; // 1 per slot, no offset counter - function test() public returns (bytes17 a, bytes17 b, bytes17 c, bytes17 d, bytes17 e) { - for (uint i = 0; i < data1.length; ++i) - data1[i] = bytes8(uint64(i)); - data2[8] = data2[9] = bytes8(uint64(2)); - data2 = data1; - a = data2[1]; - b = data2[2]; - c = data2[3]; - d = data2[4]; - e = data2[9]; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs( - asString(fromHex("0000000000000001")), - asString(fromHex("0000000000000002")), - asString(fromHex("0000000000000003")), - asString(fromHex("0000000000000004")), - asString(fromHex("0000000000000000")) - )); -} - BOOST_AUTO_TEST_CASE(array_copy_target_leftover) { // test that leftover elements in the last slot of target are correctly cleared during assignment @@ -4510,41 +3274,7 @@ BOOST_AUTO_TEST_CASE(array_copy_target_leftover) } )"; compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs( - u256("0xffffffff"), - asString(fromHex("0000000000000000""000000000a000900""0800070006000500""0400030002000100")), - asString(fromHex("0000000000000000""0000000000000000""0000000000000000""0000000000000000")) - )); -} - -BOOST_AUTO_TEST_CASE(array_copy_target_leftover2) -{ - // since the copy always copies whole slots, we have to make sure that the source size maxes - // out a whole slot and at the same time there are still elements left in the target at that point - char const* sourceCode = R"( - contract c { - bytes8[4] data1; // fits into one slot - bytes10[6] data2; // 4 elements need two slots - function test() public returns (bytes10 r1, bytes10 r2, bytes10 r3) { - data1[0] = bytes8(uint64(1)); - data1[1] = bytes8(uint64(2)); - data1[2] = bytes8(uint64(3)); - data1[3] = bytes8(uint64(4)); - for (uint i = 0; i < data2.length; ++i) - data2[i] = bytes10(uint80(0xffff00 | (1 + i))); - data2 = data1; - r1 = data2[3]; - r2 = data2[4]; - r3 = data2[5]; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs( - asString(fromHex("0000000000000004")), - asString(fromHex("0000000000000000")), - asString(fromHex("0000000000000000")) - )); + ABI_CHECK(callContractFunction("test()"), encodeArgs(u256("0xffffffff"), asString(fromHex("0000000000000000000000000a00090008000700060005000400030002000100")), asString(fromHex("0000000000000000000000000000000000000000000000000000000000000000")))); } BOOST_AUTO_TEST_CASE(array_copy_storage_storage_struct) @@ -4625,167 +3355,6 @@ BOOST_AUTO_TEST_CASE(array_copy_storage_abi) ); } -BOOST_AUTO_TEST_CASE(array_copy_storage_abi_signed) -{ - // NOTE: This does not really test copying from storage to ABI directly, - // because it will always copy to memory first. - char const* sourceCode = R"( - contract c { - int16[] x; - function test() public returns (int16[] memory) { - x.push(int16(-1)); - x.push(int16(-1)); - x.push(int16(8)); - x.push(int16(-16)); - x.push(int16(-2)); - x.push(int16(6)); - x.push(int16(8)); - x.push(int16(-1)); - return x; - } - } - )"; - compileAndRun(sourceCode); - bytes valueSequence; - ABI_CHECK(callContractFunction("test()"), encodeArgs(0x20, 8, - u256(-1), - u256(-1), - u256(8), - u256(-16), - u256(-2), - u256(6), - u256(8), - u256(-1) - )); -} - -BOOST_AUTO_TEST_CASE(array_push) -{ - char const* sourceCode = R"( - contract c { - uint[] data; - function test() public returns (uint x, uint y, uint z, uint l) { - data.push(5); - x = data[0]; - data.push(4); - y = data[1]; - data.push(3); - l = data.length; - z = data[2]; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(5, 4, 3, 3)); -} - -BOOST_AUTO_TEST_CASE(array_push_struct) -{ - char const* sourceCode = R"( - contract c { - struct S { uint16 a; uint16 b; uint16[3] c; uint16[] d; } - S[] data; - function test() public returns (uint16, uint16, uint16, uint16) { - S memory s; - s.a = 2; - s.b = 3; - s.c[2] = 4; - s.d = new uint16[](4); - s.d[2] = 5; - data.push(s); - return (data[0].a, data[0].b, data[0].c[2], data[0].d[2]); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(2, 3, 4, 5)); -} - -BOOST_AUTO_TEST_CASE(array_push_packed_array) -{ - char const* sourceCode = R"( - contract c { - uint80[] x; - function test() public returns (uint80, uint80, uint80, uint80) { - x.push(1); - x.push(2); - x.push(3); - x.push(4); - x.push(5); - x.pop(); - return (x[0], x[1], x[2], x[3]); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(1, 2, 3, 4)); -} - -BOOST_AUTO_TEST_CASE(byte_array_push) -{ - char const* sourceCode = R"( - contract c { - bytes data; - function test() public returns (bool x) { - data.push(0x05); - if (data.length != 1) return true; - if (data[0] != 0x05) return true; - data.push(0x04); - if (data[1] != 0x04) return true; - data.push(0x03); - uint l = data.length; - if (data[2] != 0x03) return true; - if (l != 0x03) return true; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(false)); -} - -BOOST_AUTO_TEST_CASE(byte_array_push_transition) -{ - // Tests transition between short and long encoding - char const* sourceCode = R"( - contract c { - bytes data; - function test() public returns (uint) { - for (uint8 i = 1; i < 40; i++) - { - data.push(byte(i)); - if (data.length != i) return 0x1000 + i; - if (data[data.length - 1] != byte(i)) return i; - } - for (uint8 i = 1; i < 40; i++) - if (data[i - 1] != byte(i)) return 0x1000000 + i; - return 0; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(0)); -} - -BOOST_AUTO_TEST_CASE(array_pop) -{ - char const* sourceCode = R"( - contract c { - uint[] data; - function test() public returns (uint x, uint l) { - data.push(7); - data.push(3); - x = data.length; - data.pop(); - x = data.length; - data.pop(); - l = data.length; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(1, 0)); -} - BOOST_AUTO_TEST_CASE(array_pop_uint16_transition) { char const* sourceCode = R"( @@ -4872,21 +3441,6 @@ BOOST_AUTO_TEST_CASE(array_pop_array_transition) BOOST_CHECK(storageEmpty(m_contractAddress)); } -BOOST_AUTO_TEST_CASE(array_pop_empty_exception) -{ - char const* sourceCode = R"( - contract c { - uint[] data; - function test() public returns (bool) { - data.pop(); - return true; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs()); -} - BOOST_AUTO_TEST_CASE(array_pop_storage_empty) { char const* sourceCode = R"( @@ -4903,45 +3457,6 @@ BOOST_AUTO_TEST_CASE(array_pop_storage_empty) BOOST_CHECK(storageEmpty(m_contractAddress)); } -BOOST_AUTO_TEST_CASE(byte_array_pop) -{ - char const* sourceCode = R"( - contract c { - bytes data; - function test() public returns (uint x, uint y, uint l) { - data.push(0x07); - data.push(0x03); - x = data.length; - data.pop(); - data.pop(); - data.push(0x02); - y = data.length; - l = data.length; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(2, 1, 1)); -} - -BOOST_AUTO_TEST_CASE(byte_array_pop_empty_exception) -{ - char const* sourceCode = R"( - contract c { - uint256 a; - uint256 b; - uint256 c; - bytes data; - function test() public returns (bool) { - data.pop(); - return true; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs()); -} - BOOST_AUTO_TEST_CASE(byte_array_pop_storage_empty) { char const* sourceCode = R"( @@ -5011,84 +3526,6 @@ BOOST_AUTO_TEST_CASE(byte_array_pop_long_storage_empty_garbage_ref) BOOST_CHECK(storageEmpty(m_contractAddress)); } -BOOST_AUTO_TEST_CASE(byte_array_pop_masking_long) -{ - char const* sourceCode = R"( - contract c { - bytes data; - function test() public returns (bytes memory) { - for (uint i = 0; i < 34; i++) - data.push(0x03); - data.pop(); - return data; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs( - u256(0x20), - u256(33), - asString(fromHex("0303030303030303030303030303030303030303030303030303030303030303")), - asString(fromHex("03")) - )); -} - -BOOST_AUTO_TEST_CASE(byte_array_pop_copy_long) -{ - char const* sourceCode = R"( - contract c { - bytes data; - function test() public returns (bytes memory) { - for (uint i = 0; i < 33; i++) - data.push(0x03); - for (uint j = 0; j < 4; j++) - data.pop(); - return data; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs( - u256(0x20), - u256(29), - asString(fromHex("0303030303030303030303030303030303030303030303030303030303")) - )); -} - -BOOST_AUTO_TEST_CASE(array_pop_isolated) -{ - char const* sourceCode = R"( - // This tests that the compiler knows the correct size of the function on the stack. - contract c { - uint[] data; - function test() public returns (uint x) { - x = 2; - data.pop; - x = 3; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(3)); -} - -BOOST_AUTO_TEST_CASE(byte_array_pop_isolated) -{ - char const* sourceCode = R"( - // This tests that the compiler knows the correct size of the function on the stack. - contract c { - bytes data; - function test() public returns (uint x) { - x = 2; - data.pop; - x = 3; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(3)); -} - BOOST_AUTO_TEST_CASE(external_array_args) { char const* sourceCode = R"( @@ -5149,26 +3586,6 @@ BOOST_AUTO_TEST_CASE(bytes_index_access) ABI_CHECK(callContractFunction("storageWrite()"), encodeArgs(0x193)); } -BOOST_AUTO_TEST_CASE(bytes_delete_element) -{ - char const* sourceCode = R"( - contract c { - bytes data; - function test1() external returns (bool) { - data = new bytes(100); - for (uint i = 0; i < data.length; i++) - data[i] = byte(uint8(i)); - delete data[94]; - delete data[96]; - delete data[98]; - return data[94] == 0 && uint8(data[95]) == 95 && data[96] == 0 && uint8(data[97]) == 97; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test1()"), encodeArgs(true)); -} - BOOST_AUTO_TEST_CASE(array_copy_calldata_storage) { char const* sourceCode = R"( @@ -5194,42 +3611,8 @@ BOOST_AUTO_TEST_CASE(array_copy_calldata_storage) } )"; compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("store(uint256[9],uint8[3][])", encodeArgs( - 21, 22, 23, 24, 25, 26, 27, 28, 29, // a - u256(32 * (9 + 1)), - 4, // size of b - 1, 2, 3, // b[0] - 11, 12, 13, // b[1] - 21, 22, 23, // b[2] - 31, 32, 33 // b[3] - )), encodeArgs(32)); - ABI_CHECK(callContractFunction("retrieve()"), encodeArgs( - 9, 28, 9, 28, - 4, 3, 32)); -} - -BOOST_AUTO_TEST_CASE(array_copy_nested_array) -{ - char const* sourceCode = R"( - contract c { - uint[4][] a; - uint[10][] b; - uint[][] c; - function test(uint[2][] calldata d) external returns (uint) { - a = d; - b = a; - c = b; - return c[1][1] | c[1][2] | c[1][3] | c[1][4]; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test(uint256[2][])", encodeArgs( - 32, 3, - 7, 8, - 9, 10, - 11, 12 - )), encodeArgs(10)); + ABI_CHECK(callContractFunction("store(uint256[9],uint8[3][])", encodeArgs(21, 22, 23, 24, 25, 26, 27, 28, 29, u256(32 * (9 + 1)), 4, 1, 2, 3, 11, 12, 13, 21, 22, 23, 31, 32, 33 )), encodeArgs(32)); + ABI_CHECK(callContractFunction("retrieve()"), encodeArgs(9, 28, 9, 28, 4, 3, 32)); } BOOST_AUTO_TEST_CASE(array_copy_including_mapping) @@ -5279,145 +3662,6 @@ BOOST_AUTO_TEST_CASE(array_copy_including_mapping) BOOST_CHECK(storageEmpty(m_contractAddress)); } -BOOST_AUTO_TEST_CASE(swap_in_storage_overwrite) -{ - // This tests a swap in storage which does not work as one - // might expect because we do not have temporary storage. - // (x, y) = (y, x) is the same as - // y = x; - // x = y; - char const* sourceCode = R"( - contract c { - struct S { uint a; uint b; } - S public x; - S public y; - function set() public { - x.a = 1; x.b = 2; - y.a = 3; y.b = 4; - } - function swap() public { - (x, y) = (y, x); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(0), u256(0))); - ABI_CHECK(callContractFunction("y()"), encodeArgs(u256(0), u256(0))); - ABI_CHECK(callContractFunction("set()"), encodeArgs()); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(1), u256(2))); - ABI_CHECK(callContractFunction("y()"), encodeArgs(u256(3), u256(4))); - ABI_CHECK(callContractFunction("swap()"), encodeArgs()); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(1), u256(2))); - ABI_CHECK(callContractFunction("y()"), encodeArgs(u256(1), u256(2))); -} - -BOOST_AUTO_TEST_CASE(pass_dynamic_arguments_to_the_base) -{ - char const* sourceCode = R"( - contract Base { - constructor(uint i) public - { - m_i = i; - } - uint public m_i; - } - contract Derived is Base { - constructor(uint i) Base(i) public - {} - } - contract Final is Derived(4) { - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("m_i()"), encodeArgs(4)); -} - -BOOST_AUTO_TEST_CASE(pass_dynamic_arguments_to_the_base_base) -{ - char const* sourceCode = R"( - contract Base { - constructor(uint j) public - { - m_i = j; - } - uint public m_i; - } - contract Base1 is Base { - constructor(uint k) Base(k) public {} - } - contract Derived is Base, Base1 { - constructor(uint i) Base1(i) public - {} - } - contract Final is Derived(4) { - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("m_i()"), encodeArgs(4)); -} - -BOOST_AUTO_TEST_CASE(pass_dynamic_arguments_to_the_base_base_with_gap) -{ - char const* sourceCode = R"( - contract Base { - constructor(uint i) public - { - m_i = i; - } - uint public m_i; - } - abstract contract Base1 is Base { - constructor(uint k) public {} - } - contract Derived is Base, Base1 { - constructor(uint i) Base(i) Base1(7) public {} - } - contract Final is Derived(4) { - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("m_i()"), encodeArgs(4)); -} - -BOOST_AUTO_TEST_CASE(simple_constant_variables_test) -{ - char const* sourceCode = R"( - contract Foo { - function getX() public returns (uint r) { return x; } - uint constant x = 56; - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("getX()"), encodeArgs(56)); -} - -BOOST_AUTO_TEST_CASE(constant_variables) -{ - char const* sourceCode = R"( - contract Foo { - uint constant x = 56; - enum ActionChoices { GoLeft, GoRight, GoStraight, Sit } - ActionChoices constant choices = ActionChoices.GoLeft; - bytes32 constant st = "abc\x00\xff__"; - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - ) -} - -BOOST_AUTO_TEST_CASE(assignment_to_const_var_involving_expression) -{ - char const* sourceCode = R"( - contract C { - uint constant x = 0x123 + 0x456; - function f() public returns (uint) { return x + 1; } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(0x123 + 0x456 + 1)); -} - BOOST_AUTO_TEST_CASE(assignment_to_const_var_involving_keccak) { char const* sourceCode = R"( @@ -5458,98 +3702,6 @@ BOOST_AUTO_TEST_CASE(assignment_to_const_var_involving_keccak) // ABI_CHECK(callContractFunction("f()"), encodeArgs(5)); //} -BOOST_AUTO_TEST_CASE(packed_storage_structs_uint) -{ - char const* sourceCode = R"( - contract C { - struct str { uint8 a; uint16 b; uint248 c; } - str data; - function test() public returns (uint) { - data.a = 2; - if (data.a != 2) return 2; - data.b = 0xabcd; - if (data.b != 0xabcd) return 3; - data.c = 0x1234567890; - if (data.c != 0x1234567890) return 4; - if (data.a != 2) return 5; - data.a = 8; - if (data.a != 8) return 6; - if (data.b != 0xabcd) return 7; - data.b = 0xdcab; - if (data.b != 0xdcab) return 8; - if (data.c != 0x1234567890) return 9; - data.c = 0x9876543210; - if (data.c != 0x9876543210) return 10; - return 1; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(1)); -} - -BOOST_AUTO_TEST_CASE(packed_storage_structs_enum) -{ - char const* sourceCode = R"( - contract C { - enum small { A, B, C, D } - enum larger { A, B, C, D, E} - struct str { small a; small b; larger c; larger d; } - str data; - function test() public returns (uint) { - data.a = small.B; - if (data.a != small.B) return 2; - data.b = small.C; - if (data.b != small.C) return 3; - data.c = larger.D; - if (data.c != larger.D) return 4; - if (data.a != small.B) return 5; - data.a = small.C; - if (data.a != small.C) return 6; - if (data.b != small.C) return 7; - data.b = small.D; - if (data.b != small.D) return 8; - if (data.c != larger.D) return 9; - data.c = larger.B; - if (data.c != larger.B) return 10; - return 1; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(1)); -} - -BOOST_AUTO_TEST_CASE(packed_storage_structs_bytes) -{ - char const* sourceCode = R"( - contract C { - struct s1 { byte a; byte b; bytes10 c; bytes9 d; bytes10 e; } - struct s2 { byte a; s1 inner; byte b; byte c; } - byte x; - s2 data; - byte y; - function test() public returns (bool) { - x = 0x01; - data.a = 0x02; - data.inner.a = 0x03; - data.inner.b = 0x04; - data.inner.c = "1234567890"; - data.inner.d = "123456789"; - data.inner.e = "abcdefghij"; - data.b = 0x05; - data.c = byte(0x06); - y = 0x07; - return x == 0x01 && data.a == 0x02 && data.inner.a == 0x03 && data.inner.b == 0x04 && - data.inner.c == "1234567890" && data.inner.d == "123456789" && - data.inner.e == "abcdefghij" && data.b == 0x05 && data.c == byte(0x06) && y == 0x07; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(true)); -} - BOOST_AUTO_TEST_CASE(packed_storage_structs_delete) { char const* sourceCode = R"( @@ -5581,118 +3733,6 @@ BOOST_AUTO_TEST_CASE(packed_storage_structs_delete) BOOST_CHECK(storageEmpty(m_contractAddress)); } -BOOST_AUTO_TEST_CASE(overloaded_function_call_resolve_to_first) -{ - char const* sourceCode = R"( - contract test { - function f(uint k) public returns(uint d) { return k; } - function f(uint a, uint b) public returns(uint d) { return a + b; } - function g() public returns(uint d) { return f(3); } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("g()"), encodeArgs(3)); - ) -} - -BOOST_AUTO_TEST_CASE(overloaded_function_call_resolve_to_second) -{ - char const* sourceCode = R"( - contract test { - function f(uint a, uint b) public returns(uint d) { return a + b; } - function f(uint k) public returns(uint d) { return k; } - function g() public returns(uint d) { return f(3, 7); } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("g()"), encodeArgs(10)); - ) -} - -BOOST_AUTO_TEST_CASE(overloaded_function_call_with_if_else) -{ - char const* sourceCode = R"( - contract test { - function f(uint a, uint b) public returns(uint d) { return a + b; } - function f(uint k) public returns(uint d) { return k; } - function g(bool flag) public returns(uint d) { - if (flag) - return f(3); - else - return f(3, 7); - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("g(bool)", true), encodeArgs(3)); - ABI_CHECK(callContractFunction("g(bool)", false), encodeArgs(10)); - ) -} - -BOOST_AUTO_TEST_CASE(derived_overload_base_function_direct) -{ - char const* sourceCode = R"( - contract B { function f() public returns(uint) { return 10; } } - contract C is B { - function f(uint i) public returns(uint) { return 2 * i; } - function g() public returns(uint) { return f(1); } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("g()"), encodeArgs(2)); - ) -} - -BOOST_AUTO_TEST_CASE(derived_overload_base_function_indirect) -{ - char const* sourceCode = R"( - contract A { function f(uint a) public returns(uint) { return 2 * a; } } - contract B { function f() public returns(uint) { return 10; } } - contract C is A, B { - function g() public returns(uint) { return f(); } - function h() public returns(uint) { return f(1); } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("g()"), encodeArgs(10)); - ABI_CHECK(callContractFunction("h()"), encodeArgs(2)); - ) -} - -BOOST_AUTO_TEST_CASE(super_overload) -{ - char const* sourceCode = R"( - contract A { function f(uint a) public returns(uint) { return 2 * a; } } - contract B { function f(bool b) public returns(uint) { return 10; } } - contract C is A, B { - function g() public returns(uint) { return super.f(true); } - function h() public returns(uint) { return super.f(1); } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("g()"), encodeArgs(10)); - ABI_CHECK(callContractFunction("h()"), encodeArgs(2)); -} - -BOOST_AUTO_TEST_CASE(gasleft_shadow_resolution) -{ - char const* sourceCode = R"( - contract C { - function gasleft() public returns(uint256) { return 0; } - function f() public returns(uint256) { return gasleft(); } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(0)); - ) -} - BOOST_AUTO_TEST_CASE(bool_conversion) { char const* sourceCode = R"( @@ -5722,81 +3762,6 @@ BOOST_AUTO_TEST_CASE(bool_conversion) ABI_CHECK(callContractFunction("g(bool)", 255), v2 ? encodeArgs() : encodeArgs(1)); } -BOOST_AUTO_TEST_CASE(packed_storage_signed) -{ - char const* sourceCode = R"( - contract C { - int8 a; - uint8 b; - int8 c; - uint8 d; - function test() public returns (uint x1, uint x2, uint x3, uint x4) { - a = -2; - b = -uint8(a) * 2; - c = a * int8(120) * int8(121); - x1 = uint(a); - x2 = b; - x3 = uint(c); - x4 = d; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(u256(-2), u256(4), u256(-112), u256(0))); -} - -BOOST_AUTO_TEST_CASE(external_types_in_calls) -{ - char const* sourceCode = R"( - contract C1 { C1 public bla; constructor(C1 x) public { bla = x; } } - contract C { - function test() public returns (C1 x, C1 y) { - C1 c = new C1(C1(9)); - x = c.bla(); - y = this.t1(C1(7)); - } - function t1(C1 a) public returns (C1) { return a; } - function t2() public returns (C1) { return C1(9); } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("test()"), encodeArgs(u256(9), u256(7))); - ABI_CHECK(callContractFunction("t2()"), encodeArgs(u256(9))); -} - -BOOST_AUTO_TEST_CASE(invalid_enum_compared) -{ - char const* sourceCode = R"( - contract C { - enum X { A, B } - - function test_eq() public returns (bool) { - X garbled; - assembly { - garbled := 5 - } - return garbled == garbled; - } - function test_eq_ok() public returns (bool) { - X garbled = X.A; - return garbled == garbled; - } - function test_neq() public returns (bool) { - X garbled; - assembly { - garbled := 5 - } - return garbled != garbled; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("test_eq_ok()"), encodeArgs(u256(1))); - // both should throw - ABI_CHECK(callContractFunction("test_eq()"), encodeArgs()); - ABI_CHECK(callContractFunction("test_neq()"), encodeArgs()); -} - BOOST_AUTO_TEST_CASE(invalid_enum_logged) { char const* sourceCode = R"( @@ -5831,230 +3796,6 @@ BOOST_AUTO_TEST_CASE(invalid_enum_logged) ABI_CHECK(callContractFunction("test_log()"), encodeArgs()); } -BOOST_AUTO_TEST_CASE(invalid_enum_stored) -{ - char const* sourceCode = R"( - contract C { - enum X { A, B } - X public x; - - function test_store() public returns (uint) { - X garbled = X.A; - assembly { - garbled := 5 - } - x = garbled; - return 1; - } - function test_store_ok() public returns (uint) { - x = X.A; - return 1; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("test_store_ok()"), encodeArgs(u256(1))); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(0))); - - // should throw - ABI_CHECK(callContractFunction("test_store()"), encodeArgs()); -} - -BOOST_AUTO_TEST_CASE(invalid_enum_as_external_ret) -{ - char const* sourceCode = R"( - contract C { - enum X { A, B } - - function test_return() public returns (X) { - X garbled; - assembly { - garbled := 5 - } - return garbled; - } - function test_inline_assignment() public returns (X _ret) { - assembly { - _ret := 5 - } - } - function test_assignment() public returns (X _ret) { - X tmp; - assembly { - tmp := 5 - } - _ret = tmp; - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - // both should throw - ABI_CHECK(callContractFunction("test_return()"), encodeArgs()); - ABI_CHECK(callContractFunction("test_inline_assignment()"), encodeArgs()); - ABI_CHECK(callContractFunction("test_assignment()"), encodeArgs()); - ) -} - -BOOST_AUTO_TEST_CASE(invalid_enum_as_external_arg) -{ - char const* sourceCode = R"( - contract C { - enum X { A, B } - - function tested (X x) public returns (uint) { - return 1; - } - - function test() public returns (uint) { - X garbled; - - assembly { - garbled := 5 - } - - return this.tested(garbled); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - // should throw - ABI_CHECK(callContractFunction("test()"), encodeArgs()); -} - -BOOST_AUTO_TEST_CASE(struct_assign_reference_to_struct) -{ - char const* sourceCode = R"( - contract test { - struct testStruct - { - uint m_value; - } - testStruct data1; - testStruct data2; - testStruct data3; - constructor() public - { - data1.m_value = 2; - } - function assign() public returns (uint ret_local, uint ret_global, uint ret_global3, uint ret_global1) - { - testStruct storage x = data1; //x is a reference data1.m_value == 2 as well as x.m_value = 2 - data2 = data1; // should copy data. data2.m_value == 2 - - ret_local = x.m_value; // = 2 - ret_global = data2.m_value; // = 2 - - x.m_value = 3; - data3 = x; //should copy the data. data3.m_value == 3 - ret_global3 = data3.m_value; // = 3 - ret_global1 = data1.m_value; // = 3. Changed due to the assignment to x.m_value - } - } - )"; - compileAndRun(sourceCode, 0, "test"); - ABI_CHECK(callContractFunction("assign()"), encodeArgs(2, 2, 3, 3)); -} - -BOOST_AUTO_TEST_CASE(struct_delete_member) -{ - char const* sourceCode = R"( - contract test { - struct testStruct - { - uint m_value; - } - testStruct data1; - constructor() public - { - data1.m_value = 2; - } - function deleteMember() public returns (uint ret_value) - { - testStruct storage x = data1; //should not copy the data. data1.m_value == 2 but x.m_value = 0 - x.m_value = 4; - delete x.m_value; - ret_value = data1.m_value; - } - } - )"; - compileAndRun(sourceCode, 0, "test"); - ABI_CHECK(callContractFunction("deleteMember()"), encodeArgs(0)); -} - -BOOST_AUTO_TEST_CASE(struct_delete_struct_in_mapping) -{ - char const* sourceCode = R"( - contract test { - struct testStruct - { - uint m_value; - } - mapping (uint => testStruct) campaigns; - - constructor() public - { - campaigns[0].m_value = 2; - } - function deleteIt() public returns (uint) - { - delete campaigns[0]; - return campaigns[0].m_value; - } - } - )"; - compileAndRun(sourceCode, 0, "test"); - ABI_CHECK(callContractFunction("deleteIt()"), encodeArgs(0)); -} - -BOOST_AUTO_TEST_CASE(evm_exceptions_out_of_band_access) -{ - char const* sourceCode = R"( - contract A { - uint[3] arr; - bool public test = false; - function getElement(uint i) public returns (uint) - { - return arr[i]; - } - function testIt() public returns (bool) - { - uint i = this.getElement(5); - test = true; - return true; - } - } - )"; - compileAndRun(sourceCode, 0, "A"); - ABI_CHECK(callContractFunction("test()"), encodeArgs(false)); - ABI_CHECK(callContractFunction("testIt()"), encodeArgs()); - ABI_CHECK(callContractFunction("test()"), encodeArgs(false)); -} - -BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_call_fail) -{ - char const* sourceCode = R"( - contract A { - constructor() public - { - address(this).call("123"); - } - } - contract B { - uint public test = 1; - function testIt() public - { - A a = new A(); - ++test; - } - } - )"; - compileAndRun(sourceCode, 0, "B"); - - ABI_CHECK(callContractFunction("testIt()"), encodeArgs()); - ABI_CHECK(callContractFunction("test()"), encodeArgs(2)); -} - BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_out_of_baund) { char const* sourceCode = R"( @@ -6073,21 +3814,6 @@ BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_out_of_baund) BOOST_CHECK(!m_transactionSuccessful); } -BOOST_AUTO_TEST_CASE(positive_integers_to_signed) -{ - char const* sourceCode = R"( - contract test { - int8 public x = 2; - int8 public y = 127; - int16 public q = 250; - } - )"; - compileAndRun(sourceCode, 0, "test"); - ABI_CHECK(callContractFunction("x()"), encodeArgs(2)); - ABI_CHECK(callContractFunction("y()"), encodeArgs(127)); - ABI_CHECK(callContractFunction("q()"), encodeArgs(250)); -} - BOOST_AUTO_TEST_CASE(failing_send) { char const* sourceCode = R"( @@ -6111,27 +3837,6 @@ BOOST_AUTO_TEST_CASE(failing_send) BOOST_REQUIRE(callContractFunction("callHelper(address)", c_helperAddress) == encodeArgs(true, 20)); } -BOOST_AUTO_TEST_CASE(send_zero_ether) -{ - // Sending zero ether to a contract should still invoke the receive ether function - // (it previously did not because the gas stipend was not provided by the EVM) - char const* sourceCode = R"( - contract Receiver { - receive () external payable { - } - } - contract Main { - constructor() public payable {} - function s() public returns (bool) { - Receiver r = new Receiver(); - return address(r).send(0); - } - } - )"; - compileAndRun(sourceCode, 20, "Main"); - BOOST_REQUIRE(callContractFunction("s()") == encodeArgs(true)); -} - BOOST_AUTO_TEST_CASE(reusing_memory) { // Invoke some features that use memory and test that they do not interfere with each other. @@ -6463,23 +4168,6 @@ BOOST_AUTO_TEST_CASE(arrays_in_constructors) ); } -BOOST_AUTO_TEST_CASE(fixed_arrays_in_constructors) -{ - char const* sourceCode = R"( - contract Creator { - uint public r; - address public ch; - constructor(address[3] memory s, uint x) public { - r = x; - ch = s[2]; - } - } - )"; - compileAndRun(sourceCode, 0, "Creator", encodeArgs(u256(1), u256(2), u256(3), u256(4))); - BOOST_REQUIRE(callContractFunction("r()") == encodeArgs(u256(4))); - BOOST_REQUIRE(callContractFunction("ch()") == encodeArgs(u256(3))); -} - BOOST_AUTO_TEST_CASE(arrays_from_and_to_storage) { char const* sourceCode = R"( @@ -6584,61 +4272,6 @@ BOOST_AUTO_TEST_CASE(bytes_memory_index_access) ); } -BOOST_AUTO_TEST_CASE(storage_array_ref) -{ - char const* sourceCode = R"( - contract BinarySearch { - /// Finds the position of _value in the sorted list _data. - /// Note that "internal" is important here, because storage references only work for internal or private functions - function find(uint[] storage _data, uint _value) internal returns (uint o_position) { - return find(_data, 0, _data.length, _value); - } - function find(uint[] storage _data, uint _begin, uint _len, uint _value) private returns (uint o_position) { - if (_len == 0 || (_len == 1 && _data[_begin] != _value)) - return uint(-1); // failure - uint halfLen = _len / 2; - uint v = _data[_begin + halfLen]; - if (_value < v) - return find(_data, _begin, halfLen, _value); - else if (_value > v) - return find(_data, _begin + halfLen + 1, halfLen - 1, _value); - else - return _begin + halfLen; - } - } - - contract Store is BinarySearch { - uint[] data; - function add(uint v) public { - data.push(0); - data[data.length - 1] = v; - } - function find(uint v) public returns (uint) { - return find(data, v); - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "Store"); - BOOST_REQUIRE(callContractFunction("find(uint256)", u256(7)) == encodeArgs(u256(-1))); - BOOST_REQUIRE(callContractFunction("add(uint256)", u256(7)) == encodeArgs()); - BOOST_REQUIRE(callContractFunction("find(uint256)", u256(7)) == encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("add(uint256)", u256(11)), encodeArgs()); - ABI_CHECK(callContractFunction("add(uint256)", u256(17)), encodeArgs()); - ABI_CHECK(callContractFunction("add(uint256)", u256(27)), encodeArgs()); - ABI_CHECK(callContractFunction("add(uint256)", u256(31)), encodeArgs()); - ABI_CHECK(callContractFunction("add(uint256)", u256(32)), encodeArgs()); - ABI_CHECK(callContractFunction("add(uint256)", u256(66)), encodeArgs()); - ABI_CHECK(callContractFunction("add(uint256)", u256(177)), encodeArgs()); - ABI_CHECK(callContractFunction("find(uint256)", u256(7)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("find(uint256)", u256(27)), encodeArgs(u256(3))); - ABI_CHECK(callContractFunction("find(uint256)", u256(32)), encodeArgs(u256(5))); - ABI_CHECK(callContractFunction("find(uint256)", u256(176)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("find(uint256)", u256(0)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("find(uint256)", u256(400)), encodeArgs(u256(-1))); - ); -} - BOOST_AUTO_TEST_CASE(memory_types_initialisation) { char const* sourceCode = R"( @@ -6738,111 +4371,6 @@ BOOST_AUTO_TEST_CASE(memory_arrays_dynamic_index_access_write) ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0x20), u256(4), data)); } -BOOST_AUTO_TEST_CASE(memory_structs_read_write) -{ - char const* sourceCode = R"( - contract Test { - struct S { uint8 x; uint16 y; uint z; uint8[2] a; } - S[5] data; - function testInit() public returns (uint8 x, uint16 y, uint z, uint8 a, bool flag) { - S[2] memory d; - x = d[0].x; - y = d[0].y; - z = d[0].z; - a = d[0].a[1]; - flag = true; - } - function testCopyRead() public returns (uint8 x, uint16 y, uint z, uint8 a) { - data[2].x = 1; - data[2].y = 2; - data[2].z = 3; - data[2].a[1] = 4; - S memory s = data[2]; - x = s.x; - y = s.y; - z = s.z; - a = s.a[1]; - } - function testAssign() public returns (uint8 x, uint16 y, uint z, uint8 a) { - S memory s; - s.x = 1; - s.y = 2; - s.z = 3; - s.a[1] = 4; - x = s.x; - y = s.y; - z = s.z; - a = s.a[1]; - } - } - )"; - compileAndRun(sourceCode, 0, "Test"); - - ABI_CHECK(callContractFunction("testInit()"), encodeArgs(u256(0), u256(0), u256(0), u256(0), true)); - ABI_CHECK(callContractFunction("testCopyRead()"), encodeArgs(u256(1), u256(2), u256(3), u256(4))); - ABI_CHECK(callContractFunction("testAssign()"), encodeArgs(u256(1), u256(2), u256(3), u256(4))); -} - -BOOST_AUTO_TEST_CASE(memory_structs_as_function_args) -{ - char const* sourceCode = R"( - contract Test { - struct S { uint8 x; uint16 y; uint z; } - function test() public returns (uint x, uint y, uint z) { - S memory data = combine(1, 2, 3); - x = extract(data, 0); - y = extract(data, 1); - z = extract(data, 2); - } - function extract(S memory s, uint which) internal returns (uint x) { - if (which == 0) return s.x; - else if (which == 1) return s.y; - else return s.z; - } - function combine(uint8 x, uint16 y, uint z) internal returns (S memory s) { - s.x = x; - s.y = y; - s.z = z; - } - } - )"; - compileAndRun(sourceCode, 0, "Test"); - - ABI_CHECK(callContractFunction("test()"), encodeArgs(u256(1), u256(2), u256(3))); -} - -BOOST_AUTO_TEST_CASE(memory_structs_nested) -{ - char const* sourceCode = R"( - contract Test { - struct S { uint8 x; uint16 y; uint z; } - struct X { uint8 x; S s; } - function test() public returns (uint a, uint x, uint y, uint z) { - X memory d = combine(1, 2, 3, 4); - a = extract(d, 0); - x = extract(d, 1); - y = extract(d, 2); - z = extract(d, 3); - } - function extract(X memory s, uint which) internal returns (uint x) { - if (which == 0) return s.x; - else if (which == 1) return s.s.x; - else if (which == 2) return s.s.y; - else return s.s.z; - } - function combine(uint8 a, uint8 x, uint16 y, uint z) internal returns (X memory s) { - s.x = a; - s.s.x = x; - s.s.y = y; - s.s.z = z; - } - } - )"; - compileAndRun(sourceCode, 0, "Test"); - - ABI_CHECK(callContractFunction("test()"), encodeArgs(u256(1), u256(2), u256(3), u256(4))); -} - BOOST_AUTO_TEST_CASE(memory_structs_nested_load) { char const* sourceCode = R"( @@ -6917,207 +4445,6 @@ BOOST_AUTO_TEST_CASE(struct_constructor_nested) ABI_CHECK(callContractFunction("get()"), out); } -BOOST_AUTO_TEST_CASE(struct_named_constructor) -{ - char const* sourceCode = R"( - contract C { - struct S { uint a; bool x; } - S public s; - constructor() public { - s = S({a: 1, x: true}); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - ABI_CHECK(callContractFunction("s()"), encodeArgs(u256(1), true)); -} - -BOOST_AUTO_TEST_CASE(calldata_array) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - function f(uint[2] calldata s) external pure returns (uint256 a, uint256 b) { - a = s[0]; - b = s[1]; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - ABI_CHECK(callContractFunction("f(uint256[2])", encodeArgs(u256(42), u256(23))), encodeArgs(u256(42), u256(23))); -} - -BOOST_AUTO_TEST_CASE(calldata_struct) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - struct S { uint256 a; uint256 b; } - function f(S calldata s) external pure returns (uint256 a, uint256 b) { - a = s.a; - b = s.b; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - ABI_CHECK(callContractFunction("f((uint256,uint256))", encodeArgs(u256(42), u256(23))), encodeArgs(u256(42), u256(23))); -} - -BOOST_AUTO_TEST_CASE(calldata_struct_and_ints) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - struct S { uint256 a; uint256 b; } - function f(uint256 a, S calldata s, uint256 b) external pure returns (uint256, uint256, uint256, uint256) { - return (a, s.a, s.b, b); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - ABI_CHECK(callContractFunction("f(uint256,(uint256,uint256),uint256)", encodeArgs(u256(1), u256(2), u256(3), u256(4))), encodeArgs(u256(1), u256(2), u256(3), u256(4))); -} - - -BOOST_AUTO_TEST_CASE(calldata_structs) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - struct S1 { uint256 a; uint256 b; } - struct S2 { uint256 a; } - function f(S1 calldata s1, S2 calldata s2, S1 calldata s3) - external pure returns (uint256 a, uint256 b, uint256 c, uint256 d, uint256 e) { - a = s1.a; - b = s1.b; - c = s2.a; - d = s3.a; - e = s3.b; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - ABI_CHECK(callContractFunction("f((uint256,uint256),(uint256),(uint256,uint256))", encodeArgs(u256(1), u256(2), u256(3), u256(4), u256(5))), encodeArgs(u256(1), u256(2), u256(3), u256(4), u256(5))); -} - -BOOST_AUTO_TEST_CASE(calldata_struct_array_member) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - struct S { uint256 a; uint256[2] b; uint256 c; } - function f(S calldata s) external pure returns (uint256 a, uint256 b0, uint256 b1, uint256 c) { - a = s.a; - b0 = s.b[0]; - b1 = s.b[1]; - c = s.c; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - ABI_CHECK(callContractFunction("f((uint256,uint256[2],uint256))", encodeArgs(u256(42), u256(1), u256(2), u256(23))), encodeArgs(u256(42), u256(1), u256(2), u256(23))); -} - -BOOST_AUTO_TEST_CASE(calldata_array_of_struct) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - struct S { uint256 a; uint256 b; } - function f(S[] calldata s) external pure returns (uint256 l, uint256 a, uint256 b, uint256 c, uint256 d) { - l = s.length; - a = s[0].a; - b = s[0].b; - c = s[1].a; - d = s[1].b; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - ABI_CHECK(callContractFunction("f((uint256,uint256)[])", encodeArgs(u256(0x20), u256(2), u256(1), u256(2), u256(3), u256(4))), encodeArgs(u256(2), u256(1), u256(2), u256(3), u256(4))); -} - -BOOST_AUTO_TEST_CASE(calldata_array_of_struct_to_memory) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - struct S { uint256 a; uint256 b; } - function f(S[] calldata s) external pure returns (uint256 l, uint256 a, uint256 b, uint256 c, uint256 d) { - S[] memory m = s; - l = m.length; - a = m[0].a; - b = m[0].b; - c = m[1].a; - d = m[1].b; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - ABI_CHECK(callContractFunction("f((uint256,uint256)[])", encodeArgs(u256(0x20), u256(2), u256(1), u256(2), u256(3), u256(4))), encodeArgs(u256(2), u256(1), u256(2), u256(3), u256(4))); -} - - -BOOST_AUTO_TEST_CASE(calldata_struct_to_memory) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - struct S { uint256 a; uint256 b; } - function f(S calldata s) external pure returns (uint256, uint256) { - S memory m = s; - return (m.a, m.b); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - ABI_CHECK(callContractFunction("f((uint256,uint256))", encodeArgs(u256(42), u256(23))), encodeArgs(u256(42), u256(23))); -} - -BOOST_AUTO_TEST_CASE(nested_calldata_struct) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - struct S1 { uint256 a; uint256 b; } - struct S2 { uint256 a; uint256 b; S1 s; uint256 c; } - function f(S2 calldata s) external pure returns (uint256 a, uint256 b, uint256 sa, uint256 sb, uint256 c) { - return (s.a, s.b, s.s.a, s.s.b, s.c); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - ABI_CHECK(callContractFunction("f((uint256,uint256,(uint256,uint256),uint256))", encodeArgs(u256(1), u256(2), u256(3), u256(4), u256(5))), encodeArgs(u256(1), u256(2), u256(3), u256(4), u256(5))); -} - -BOOST_AUTO_TEST_CASE(nested_calldata_struct_to_memory) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - struct S1 { uint256 a; uint256 b; } - struct S2 { uint256 a; uint256 b; S1 s; uint256 c; } - function f(S2 calldata s) external pure returns (uint256 a, uint256 b, uint256 sa, uint256 sb, uint256 c) { - S2 memory m = s; - return (m.a, m.b, m.s.a, m.s.b, m.c); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - ABI_CHECK(callContractFunction("f((uint256,uint256,(uint256,uint256),uint256))", encodeArgs(u256(1), u256(2), u256(3), u256(4), u256(5))), encodeArgs(u256(1), u256(2), u256(3), u256(4), u256(5))); -} - BOOST_AUTO_TEST_CASE(calldata_struct_short) { char const* sourceCode = R"( @@ -7238,25 +4565,6 @@ BOOST_AUTO_TEST_CASE(calldata_array_dynamic_bytes) ); } -BOOST_AUTO_TEST_CASE(calldata_dynamic_array_to_memory) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - function f(uint256[][] calldata a) external returns (uint, uint256[] memory) { - uint256[] memory m = a[0]; - return (a.length, m); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - ABI_CHECK( - callContractFunction("f(uint256[][])", 0x20, 1, 0x20, 2, 23, 42), - encodeArgs(1, 0x40, 2, 23, 42) - ); -} - BOOST_AUTO_TEST_CASE(calldata_bytes_array_to_memory) { char const* sourceCode = R"( @@ -7481,70 +4789,6 @@ BOOST_AUTO_TEST_CASE(calldata_array_dynamic_three_dimensional) } } -BOOST_AUTO_TEST_CASE(calldata_array_dynamic_invalid) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - function f(uint256[][] calldata a) external returns (uint) { - return 42; - } - function g(uint256[][] calldata a) external returns (uint) { - a[0]; - return 42; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - // valid access stub - ABI_CHECK(callContractFunction("f(uint256[][])", 0x20, 0), encodeArgs(42)); - // invalid on argument decoding - ABI_CHECK(callContractFunction("f(uint256[][])", 0x20, 1), encodeArgs()); - // invalid on outer access - ABI_CHECK(callContractFunction("f(uint256[][])", 0x20, 1, 0x20), encodeArgs(42)); - ABI_CHECK(callContractFunction("g(uint256[][])", 0x20, 1, 0x20), encodeArgs()); - // invalid on inner access - ABI_CHECK(callContractFunction("f(uint256[][])", 0x20, 1, 0x20, 2, 0x42), encodeArgs(42)); - ABI_CHECK(callContractFunction("g(uint256[][])", 0x20, 1, 0x20, 2, 0x42), encodeArgs()); -} - -BOOST_AUTO_TEST_CASE(calldata_array_dynamic_invalid_static_middle) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - function f(uint256[][1][] calldata a) external returns (uint) { - return 42; - } - function g(uint256[][1][] calldata a) external returns (uint) { - a[0]; - return 42; - } - function h(uint256[][1][] calldata a) external returns (uint) { - a[0][0]; - return 42; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - // valid access stub - ABI_CHECK(callContractFunction("f(uint256[][1][])", 0x20, 0), encodeArgs(42)); - // invalid on argument decoding - ABI_CHECK(callContractFunction("f(uint256[][1][])", 0x20, 1), encodeArgs()); - // invalid on outer access - ABI_CHECK(callContractFunction("f(uint256[][1][])", 0x20, 1, 0x20), encodeArgs(42)); - ABI_CHECK(callContractFunction("g(uint256[][1][])", 0x20, 1, 0x20), encodeArgs()); - // invalid on inner access - ABI_CHECK(callContractFunction("f(uint256[][1][])", 0x20, 1, 0x20, 0x20), encodeArgs(42)); - ABI_CHECK(callContractFunction("g(uint256[][1][])", 0x20, 1, 0x20, 0x20), encodeArgs(42)); - ABI_CHECK(callContractFunction("h(uint256[][1][])", 0x20, 1, 0x20, 0x20), encodeArgs()); - ABI_CHECK(callContractFunction("f(uint256[][1][])", 0x20, 1, 0x20, 0x20, 1), encodeArgs(42)); - ABI_CHECK(callContractFunction("g(uint256[][1][])", 0x20, 1, 0x20, 0x20, 1), encodeArgs(42)); - ABI_CHECK(callContractFunction("h(uint256[][1][])", 0x20, 1, 0x20, 0x20, 1), encodeArgs()); -} - BOOST_AUTO_TEST_CASE(literal_strings) { char const* sourceCode = R"( @@ -7591,29 +4835,6 @@ BOOST_AUTO_TEST_CASE(initialise_string_constant) ABI_CHECK(callContractFunction("short()"), encodeDyn(shortStr)); } -BOOST_AUTO_TEST_CASE(memory_structs_with_mappings) -{ - char const* sourceCode = R"( - contract Test { - struct S { uint8 a; mapping(uint => uint) b; uint8 c; } - S s; - function f() public returns (uint) { - S memory x; - if (x.a != 0 || x.c != 0) return 1; - x.a = 4; x.c = 5; - s = x; - if (s.a != 4 || s.c != 5) return 2; - x = S(2, 3); - if (x.a != 2 || x.c != 3) return 3; - x = s; - if (s.a != 4 || s.c != 5) return 4; - } - } - )"; - compileAndRun(sourceCode, 0, "Test"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0))); -} - BOOST_AUTO_TEST_CASE(string_bytes_conversion) { char const* sourceCode = R"( @@ -7629,13 +4850,7 @@ BOOST_AUTO_TEST_CASE(string_bytes_conversion) } )"; compileAndRun(sourceCode, 0, "Test"); - ABI_CHECK(callContractFunction( - "f(string,uint256)", - u256(0x40), - u256(2), - u256(6), - string("abcdef") - ), encodeArgs("c")); + ABI_CHECK(callContractFunction("f(string,uint256)", u256(0x40), u256(2), u256(6), string("abcdef")), encodeArgs("c")); ABI_CHECK(callContractFunction("l()"), encodeArgs(u256(6))); } @@ -7814,162 +5029,6 @@ BOOST_AUTO_TEST_CASE(nested_mixed_string_as_public_mapping_key) ), encodeArgs(u256(i - 3))); } -BOOST_AUTO_TEST_CASE(accessor_for_state_variable) -{ - char const* sourceCode = R"( - contract Lotto { - uint public ticketPrice = 500; - } - )"; - - ALSO_VIA_YUL( - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("ticketPrice()"), encodeArgs(u256(500))); - ); -} - -BOOST_AUTO_TEST_CASE(accessor_for_const_state_variable) -{ - char const* sourceCode = R"( - contract Lotto{ - uint constant public ticketPrice = 555; - } - )"; - - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("ticketPrice()"), encodeArgs(u256(555))); -} - -BOOST_AUTO_TEST_CASE(state_variable_under_contract_name) -{ - char const* text = R"( - contract Scope { - uint stateVar = 42; - - function getStateVar() public view returns (uint stateVar) { - stateVar = Scope.stateVar; - } - } - )"; - compileAndRun(text); - ABI_CHECK(callContractFunction("getStateVar()"), encodeArgs(u256(42))); -} - -BOOST_AUTO_TEST_CASE(state_variable_local_variable_mixture) -{ - char const* sourceCode = R"( - contract A { - uint x = 1; - uint y = 2; - function a() public returns (uint x) { - x = A.y; - } - } - )"; - - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("a()"), encodeArgs(u256(2))); -} - -BOOST_AUTO_TEST_CASE(inherited_function) { - char const* sourceCode = R"( - contract A { function f() virtual internal returns (uint) { return 1; } } - contract B is A { - function f() internal override returns (uint) { return 2; } - function g() public returns (uint) { - return A.f(); - } - } - )"; - - compileAndRun(sourceCode, 0, "B"); - ABI_CHECK(callContractFunction("g()"), encodeArgs(u256(1))); -} - -BOOST_AUTO_TEST_CASE(inherited_function_calldata_memory) { - char const* sourceCode = R"( - contract A { function f(uint[] calldata a) virtual external returns (uint) { return a[0]; } } - contract B is A { - function f(uint[] memory a) public override returns (uint) { return a[1]; } - function g() public returns (uint) { - uint[] memory m = new uint[](2); - m[0] = 42; - m[1] = 23; - return A(this).f(m); - } - } - )"; - - compileAndRun(sourceCode, 0, "B"); - ABI_CHECK(callContractFunction("g()"), encodeArgs(u256(23))); -} - -BOOST_AUTO_TEST_CASE(inherited_function_calldata_memory_interface) { - char const* sourceCode = R"( - interface I { function f(uint[] calldata a) external returns (uint); } - contract A is I { function f(uint[] memory a) public override returns (uint) { return 42; } } - contract B { - function f(uint[] memory a) public returns (uint) { return a[1]; } - function g() public returns (uint) { - I i = I(new A()); - return i.f(new uint[](2)); - } - } - )"; - - compileAndRun(sourceCode, 0, "B"); - ABI_CHECK(callContractFunction("g()"), encodeArgs(u256(42))); -} - -BOOST_AUTO_TEST_CASE(inherited_function_calldata_calldata_interface) { - char const* sourceCode = R"( - interface I { function f(uint[] calldata a) external returns (uint); } - contract A is I { function f(uint[] calldata a) external override returns (uint) { return 42; } } - contract B { - function f(uint[] memory a) public returns (uint) { return a[1]; } - function g() public returns (uint) { - I i = I(new A()); - return i.f(new uint[](2)); - } - } - )"; - - compileAndRun(sourceCode, 0, "B"); - ABI_CHECK(callContractFunction("g()"), encodeArgs(u256(42))); -} - -BOOST_AUTO_TEST_CASE(inherited_function_from_a_library) { - char const* sourceCode = R"( - library A { function f() internal returns (uint) { return 1; } } - contract B { - function f() internal returns (uint) { return 2; } - function g() public returns (uint) { - return A.f(); - } - } - )"; - - compileAndRun(sourceCode, 0, "B"); - ABI_CHECK(callContractFunction("g()"), encodeArgs(u256(1))); -} - -BOOST_AUTO_TEST_CASE(inherited_constant_state_var) -{ - char const* sourceCode = R"( - contract A { - uint constant x = 7; - } - contract B is A { - function f() public returns (uint) { - return A.x; - } - } - )"; - - compileAndRun(sourceCode, 0, "B"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(7))); -} - BOOST_AUTO_TEST_CASE(constant_string_literal) { char const* sourceCode = R"( @@ -8002,21 +5061,6 @@ BOOST_AUTO_TEST_CASE(constant_string_literal) ABI_CHECK(callContractFunction("unused()"), encodeArgs(2)); } -BOOST_AUTO_TEST_CASE(storage_string_as_mapping_key_without_variable) -{ - char const* sourceCode = R"( - contract Test { - mapping(string => uint) data; - function f() public returns (uint) { - data["abc"] = 2; - return data["abc"]; - } - } - )"; - compileAndRun(sourceCode, 0, "Test"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(2))); -} - BOOST_AUTO_TEST_CASE(library_call) { char const* sourceCode = R"( @@ -8064,39 +5108,6 @@ BOOST_AUTO_TEST_CASE(library_stray_values) ABI_CHECK(callContractFunction("f(uint256)", u256(33)), encodeArgs(u256(42))); } -BOOST_AUTO_TEST_CASE(cross_contract_types) -{ - char const* sourceCode = R"( - contract Lib { struct S {uint a; uint b; } } - contract Test { - function f() public returns (uint r) { - Lib.S memory x = Lib.S({a: 2, b: 3}); - r = x.b; - } - } - )"; - compileAndRun(sourceCode, 0, "Test"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(3))); -} - -BOOST_AUTO_TEST_CASE(simple_throw) -{ - char const* sourceCode = R"( - contract Test { - function f(uint x) public returns (uint) { - if (x > 10) - return x + 10; - else - revert(); - return 2; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f(uint256)", u256(11)), encodeArgs(u256(21))); - ABI_CHECK(callContractFunction("f(uint256)", u256(1)), encodeArgs()); -} - BOOST_AUTO_TEST_CASE(strings_in_struct) { char const* sourceCode = R"( @@ -8139,35 +5150,6 @@ BOOST_AUTO_TEST_CASE(strings_in_struct) ABI_CHECK(callContractFunction("getLast()"), encodeDyn(s)); } -BOOST_AUTO_TEST_CASE(fixed_arrays_as_return_type) -{ - char const* sourceCode = R"( - contract A { - function f(uint16 input) public pure returns (uint16[5] memory arr) - { - arr[0] = input; - arr[1] = ++input; - arr[2] = ++input; - arr[3] = ++input; - arr[4] = ++input; - } - } - contract B { - function f() public returns (uint16[5] memory res, uint16[5] memory res2) - { - A a = new A(); - res = a.f(2); - res2 = a.f(1000); - } - } - )"; - compileAndRun(sourceCode, 0, "B"); - ABI_CHECK(callContractFunction("f()"), encodeArgs( - u256(2), u256(3), u256(4), u256(5), u256(6), // first return argument - u256(1000), u256(1001), u256(1002), u256(1003), u256(1004)) // second return argument - ); -} - BOOST_AUTO_TEST_CASE(internal_types_in_library) { char const* sourceCode = R"( @@ -8470,48 +5452,6 @@ BOOST_AUTO_TEST_CASE(using_library_structs) ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(7), u256(8))); } -BOOST_AUTO_TEST_CASE(library_struct_as_an_expression) -{ - char const* sourceCode = R"( - library Arst { - struct Foo { - int Things; - int Stuff; - } - } - - contract Tsra { - function f() public returns(uint) { - Arst.Foo; - return 1; - } - } - )"; - compileAndRun(sourceCode, 0, "Tsra"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(1))); -} - -BOOST_AUTO_TEST_CASE(library_enum_as_an_expression) -{ - char const* sourceCode = R"( - library Arst { - enum Foo { - Things, - Stuff - } - } - - contract Tsra { - function f() public returns(uint) { - Arst.Foo; - return 1; - } - } - )"; - compileAndRun(sourceCode, 0, "Tsra"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(1))); -} - BOOST_AUTO_TEST_CASE(short_strings) { // This test verifies that the byte array encoding that combines length and data works @@ -8649,16 +5589,6 @@ BOOST_AUTO_TEST_CASE(calldata_offset) ABI_CHECK(callContractFunction("last()", encodeArgs()), encodeDyn(string("nd"))); } -BOOST_AUTO_TEST_CASE(contract_binary_dependencies) -{ - char const* sourceCode = R"( - contract A { function f() public { new B(); } } - contract B { function f() public { } } - contract C { function f() public { new B(); } } - )"; - compileAndRun(sourceCode); -} - BOOST_AUTO_TEST_CASE(reject_ether_sent_to_library) { char const* sourceCode = R"( @@ -8684,234 +5614,6 @@ BOOST_AUTO_TEST_CASE(reject_ether_sent_to_library) BOOST_CHECK_EQUAL(balanceAt(libraryAddress), 0); } -BOOST_AUTO_TEST_CASE(multi_variable_declaration) -{ - char const* sourceCode = R"( - contract C { - function g() public returns (uint a, uint b, uint c) { - a = 1; b = 2; c = 3; - } - function h() public returns (uint a, uint b, uint c, uint d) { - a = 1; b = 2; c = 3; d = 4; - } - function f1() public returns (bool) { - (uint x, uint y, uint z) = g(); - if (x != 1 || y != 2 || z != 3) return false; - (, uint a,) = g(); - if (a != 2) return false; - (uint b, , ) = g(); - if (b != 1) return false; - (, , uint c) = g(); - if (c != 3) return false; - return true; - } - function f2() public returns (bool) { - (uint a1, , uint a3, ) = h(); - if (a1 != 1 || a3 != 3) return false; - (uint b1, uint b2, , ) = h(); - if (b1 != 1 || b2 != 2) return false; - (, uint c2, uint c3, ) = h(); - if (c2 != 2 || c3 != 3) return false; - (, , uint d3, uint d4) = h(); - if (d3 != 3 || d4 != 4) return false; - (uint e1, , uint e3, uint e4) = h(); - if (e1 != 1 || e3 != 3 || e4 != 4) return false; - return true; - } - function f() public returns (bool) { - return f1() && f2(); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()", encodeArgs()), encodeArgs(true)); -} - -BOOST_AUTO_TEST_CASE(typed_multi_variable_declaration) -{ - char const* sourceCode = R"( - contract C { - struct S { uint x; } - S s; - function g() internal returns (uint, S storage, uint) { - s.x = 7; - return (1, s, 2); - } - function f() public returns (bool) { - (uint x1, S storage y1, uint z1) = g(); - if (x1 != 1 || y1.x != 7 || z1 != 2) return false; - (, S storage y2,) = g(); - if (y2.x != 7) return false; - (uint x2,,) = g(); - if (x2 != 1) return false; - (,,uint z2) = g(); - if (z2 != 2) return false; - return true; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()", encodeArgs()), encodeArgs(true)); -} - -BOOST_AUTO_TEST_CASE(tuples) -{ - char const* sourceCode = R"( - contract C { - uint[] data; - uint[] m_c; - function g() internal returns (uint a, uint b, uint[] storage c) { - return (1, 2, data); - } - function h() external returns (uint a, uint b) { - return (5, 6); - } - function f() public returns (uint) { - data.push(3); - uint a; uint b; - (a, b) = this.h(); - if (a != 5 || b != 6) return 1; - uint[] storage c = m_c; - (a, b, c) = g(); - if (a != 1 || b != 2 || c[0] != 3) return 2; - (a, b) = (b, a); - if (a != 2 || b != 1) return 3; - (a, , b, , ) = (8, 9, 10, 11, 12); - if (a != 8 || b != 10) return 4; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0))); -} - -BOOST_AUTO_TEST_CASE(string_tuples) -{ - char const* sourceCode = R"( - contract C { - function f() public returns (string memory, uint) { - return ("abc", 8); - } - function g() public returns (string memory, string memory) { - return (h(), "def"); - } - function h() public returns (string memory) { - return ("abc"); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0x40), u256(8), u256(3), string("abc"))); - ABI_CHECK(callContractFunction("g()"), encodeArgs(u256(0x40), u256(0x80), u256(3), string("abc"), u256(3), string("def"))); -} - -BOOST_AUTO_TEST_CASE(decayed_tuple) -{ - char const* sourceCode = R"( - contract C { - function f() public returns (uint) { - uint x = 1; - (x) = 2; - return x; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(2))); -} - -BOOST_AUTO_TEST_CASE(inline_tuple_with_rational_numbers) -{ - char const* sourceCode = R"( - contract c { - function f() public returns (int8) { - int8[5] memory foo3 = [int8(1), -1, 0, 0, 0]; - return foo3[0]; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(1))); -} - -BOOST_AUTO_TEST_CASE(destructuring_assignment) -{ - char const* sourceCode = R"( - contract C { - uint x = 7; - bytes data; - uint[] y; - uint[] arrayData; - function returnsArray() public returns (uint[] memory) { - arrayData = new uint[](9); - arrayData[2] = 5; - arrayData[7] = 4; - return arrayData; - } - function f(bytes memory s) public returns (uint) { - uint loc; - uint[] memory memArray; - (loc, x, y, data, arrayData[3]) = (8, 4, returnsArray(), s, 2); - if (loc != 8) return 1; - if (x != 4) return 2; - if (y.length != 9) return 3; - if (y[2] != 5) return 4; - if (y[7] != 4) return 5; - if (data.length != s.length) return 6; - if (data[3] != s[3]) return 7; - if (arrayData[3] != 2) return 8; - (memArray, loc) = (arrayData, 3); - if (loc != 3) return 9; - if (memArray.length != arrayData.length) return 10; - bytes memory memBytes; - (x, memBytes, y[2], , ) = (456, s, 789, 101112, 131415); - if (x != 456 || memBytes.length != s.length || y[2] != 789) return 11; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f(bytes)", u256(0x20), u256(5), string("abcde")), encodeArgs(u256(0))); -} - -BOOST_AUTO_TEST_CASE(lone_struct_array_type) -{ - char const* sourceCode = R"( - contract C { - struct s { uint a; uint b;} - function f() public returns (uint) { - s[7][]; // This is only the type, should not have any effect - return 3; - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(3))); - ) -} - -BOOST_AUTO_TEST_CASE(create_memory_array) -{ - char const* sourceCode = R"( - contract C { - struct S { uint[2] a; bytes b; } - function f() public returns (byte, uint, uint, byte) { - bytes memory x = new bytes(200); - x[199] = 'A'; - uint[2][] memory y = new uint[2][](300); - y[203][1] = 8; - S[] memory z = new S[](180); - z[170].a[1] = 4; - z[170].b = new bytes(102); - z[170].b[99] = 'B'; - return (x[199], y[203][1], z[170].a[1], z[170].b[99]); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(string("A"), u256(8), u256(4), string("B"))); -} - BOOST_AUTO_TEST_CASE(create_memory_array_allocation_size) { // Check allocation size of byte array. Should be 32 plus length rounded up to next @@ -8939,145 +5641,6 @@ BOOST_AUTO_TEST_CASE(create_memory_array_allocation_size) } } -BOOST_AUTO_TEST_CASE(memory_arrays_of_various_sizes) -{ - // Computes binomial coefficients the chinese way - char const* sourceCode = R"( - contract C { - function f(uint n, uint k) public returns (uint) { - uint[][] memory rows = new uint[][](n + 1); - for (uint i = 1; i <= n; i++) { - rows[i] = new uint[](i); - rows[i][0] = rows[i][rows[i].length - 1] = 1; - for (uint j = 1; j < i - 1; j++) - rows[i][j] = rows[i - 1][j - 1] + rows[i - 1][j]; - } - return rows[n][k - 1]; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f(uint256,uint256)", encodeArgs(u256(3), u256(1))), encodeArgs(u256(1))); - ABI_CHECK(callContractFunction("f(uint256,uint256)", encodeArgs(u256(9), u256(5))), encodeArgs(u256(70))); -} - -BOOST_AUTO_TEST_CASE(create_multiple_dynamic_arrays) -{ - char const* sourceCode = R"( - contract C { - function f() public returns (uint) { - uint[][] memory x = new uint[][](42); - assert(x[0].length == 0); - x[0] = new uint[](1); - x[0][0] = 1; - assert(x[4].length == 0); - x[4] = new uint[](1); - x[4][0] = 2; - assert(x[10].length == 0); - x[10] = new uint[](1); - x[10][0] = 44; - uint[][] memory y = new uint[][](24); - assert(y[0].length == 0); - y[0] = new uint[](1); - y[0][0] = 1; - assert(y[4].length == 0); - y[4] = new uint[](1); - y[4][0] = 2; - assert(y[10].length == 0); - y[10] = new uint[](1); - y[10][0] = 88; - if ((x[0][0] == y[0][0]) && (x[4][0] == y[4][0]) && (x[10][0] == 44) && (y[10][0] == 88)) - return 7; - return 0; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(7))); -} - -BOOST_AUTO_TEST_CASE(memory_overwrite) -{ - char const* sourceCode = R"( - contract C { - function f() public returns (bytes memory x) { - x = "12345"; - x[3] = 0x61; - x[0] = 0x62; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeDyn(string("b23a5"))); -} - -BOOST_AUTO_TEST_CASE(addmod_mulmod) -{ - char const* sourceCode = R"( - contract C { - function test() public returns (uint) { - // Note that this only works because computation on literals is done using - // unbounded integers. - if ((2**255 + 2**255) % 7 != addmod(2**255, 2**255, 7)) - return 1; - if ((2**255 + 2**255) % 7 != addmod(2**255, 2**255, 7)) - return 2; - return 0; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(u256(0))); -} - -BOOST_AUTO_TEST_CASE(addmod_mulmod_zero) -{ - char const* sourceCode = R"( - contract C { - function f(uint d) public pure returns (uint) { - addmod(1, 2, d); - return 2; - } - function g(uint d) public pure returns (uint) { - mulmod(1, 2, d); - return 2; - } - function h() public pure returns (uint) { - mulmod(0, 1, 2); - mulmod(1, 0, 2); - addmod(0, 1, 2); - addmod(1, 0, 2); - return 2; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f(uint)", 0), encodeArgs()); - ABI_CHECK(callContractFunction("g(uint)", 0), encodeArgs()); - ABI_CHECK(callContractFunction("h()"), encodeArgs(2)); -} - -BOOST_AUTO_TEST_CASE(divisiod_by_zero) -{ - char const* sourceCode = R"( - contract C { - function div(uint a, uint b) public returns (uint) { - return a / b; - } - function mod(uint a, uint b) public returns (uint) { - return a % b; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("div(uint256,uint256)", 7, 2), encodeArgs(u256(3))); - // throws - ABI_CHECK(callContractFunction("div(uint256,uint256)", 7, 0), encodeArgs()); - ABI_CHECK(callContractFunction("mod(uint256,uint256)", 7, 2), encodeArgs(u256(1))); - // throws - ABI_CHECK(callContractFunction("mod(uint256,uint256)", 7, 0), encodeArgs()); -} - BOOST_AUTO_TEST_CASE(string_allocation_bug) { char const* sourceCode = R"( @@ -9096,16 +5659,7 @@ BOOST_AUTO_TEST_CASE(string_allocation_bug) } )"; compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("p(uint256)", 0), encodeArgs( - u256(0xbbbb), - u256(0xcccc), - u256(0x80), - u256(0xc0), - u256(5), - string("hello"), - u256(5), - string("world") - )); + ABI_CHECK(callContractFunction("p(uint256)", 0), encodeArgs(u256(0xbbbb), u256(0xcccc), u256(0x80), u256(0xc0), u256(5), string("hello"), u256(5), string("world"))); } BOOST_AUTO_TEST_CASE(using_for_function_on_int) @@ -9246,119 +5800,6 @@ BOOST_AUTO_TEST_CASE(bound_function_to_string) ABI_CHECK(callContractFunction("g()"), encodeArgs(u256(3))); } -BOOST_AUTO_TEST_CASE(inline_array_storage_to_memory_conversion_strings) -{ - char const* sourceCode = R"( - contract C { - string s = "doh"; - function f() public returns (string memory, string memory) { - string memory t = "ray"; - string[3] memory x = [s, t, "mi"]; - return (x[1], x[2]); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0x40), u256(0x80), u256(3), string("ray"), u256(2), string("mi"))); -} - -BOOST_AUTO_TEST_CASE(inline_array_strings_from_document) -{ - char const* sourceCode = R"( - contract C { - function f(uint i) public returns (string memory) { - string[4] memory x = ["This", "is", "an", "array"]; - return (x[i]); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f(uint256)", u256(0)), encodeArgs(u256(0x20), u256(4), string("This"))); - ABI_CHECK(callContractFunction("f(uint256)", u256(1)), encodeArgs(u256(0x20), u256(2), string("is"))); - ABI_CHECK(callContractFunction("f(uint256)", u256(2)), encodeArgs(u256(0x20), u256(2), string("an"))); - ABI_CHECK(callContractFunction("f(uint256)", u256(3)), encodeArgs(u256(0x20), u256(5), string("array"))); -} - -BOOST_AUTO_TEST_CASE(inline_array_storage_to_memory_conversion_ints) -{ - char const* sourceCode = R"( - contract C { - function f() public returns (uint x, uint y) { - x = 3; - y = 6; - uint[2] memory z = [x, y]; - return (z[0], z[1]); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(3, 6)); -} - -BOOST_AUTO_TEST_CASE(inline_array_index_access_ints) -{ - char const* sourceCode = R"( - contract C { - function f() public returns (uint) { - return ([1, 2, 3, 4][2]); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(3)); -} - -BOOST_AUTO_TEST_CASE(inline_array_index_access_strings) -{ - char const* sourceCode = R"( - contract C { - string public tester; - function f() public returns (string memory) { - return (["abc", "def", "g"][0]); - } - function test() public { - tester = f(); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("test()"), encodeArgs()); - ABI_CHECK(callContractFunction("tester()"), encodeArgs(u256(0x20), u256(3), string("abc"))); -} - -BOOST_AUTO_TEST_CASE(inline_array_return) -{ - char const* sourceCode = R"( - contract C { - uint8[] tester; - function f() public returns (uint8[5] memory) { - return ([1,2,3,4,5]); - } - function test() public returns (uint8, uint8, uint8, uint8, uint8) { - tester = f(); - return (tester[0], tester[1], tester[2], tester[3], tester[4]); - } - - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(1, 2, 3, 4, 5)); -} - -BOOST_AUTO_TEST_CASE(inline_array_singleton) -{ - // This caused a failure since the type was not converted to its mobile type. - char const* sourceCode = R"( - contract C { - function f() public returns (uint) { - return [4][0]; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(4))); -} - BOOST_AUTO_TEST_CASE(inline_long_string_return) { char const* sourceCode = R"( @@ -9395,404 +5836,6 @@ BOOST_AUTO_TEST_CASE(fixed_bytes_index_access) ABI_CHECK(callContractFunction("data(uint256)", u256(1)), encodeArgs("8")); } -BOOST_AUTO_TEST_CASE(fixed_bytes_length_access) -{ - char const* sourceCode = R"( - contract C { - byte a; - function f(bytes32 x) public returns (uint, uint, uint) { - return (x.length, bytes16(uint128(2)).length, a.length + 7); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(bytes32)", "789"), encodeArgs(u256(32), u256(16), u256(8))); -} - -BOOST_AUTO_TEST_CASE(byte_optimization_bug) -{ - char const* sourceCode = R"( - contract C { - function f(uint x) public returns (uint a) { - assembly { - a := byte(x, 31) - } - } - function g(uint x) public returns (uint a) { - assembly { - a := byte(31, x) - } - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint256)", u256(2)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("g(uint256)", u256(2)), encodeArgs(u256(2))); - ) -} - -BOOST_AUTO_TEST_CASE(inline_assembly_write_to_stack) -{ - char const* sourceCode = R"( - contract C { - function f() public returns (uint r, bytes32 r2) { - assembly { r := 7 r2 := "abcdef" } - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(7), string("abcdef"))); - ) -} - -BOOST_AUTO_TEST_CASE(inline_assembly_read_and_write_stack) -{ - char const* sourceCode = R"( - contract C { - function f() public returns (uint r) { - for (uint x = 0; x < 10; ++x) - assembly { r := add(r, x) } - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(45))); - ) -} - -BOOST_AUTO_TEST_CASE(inline_assembly_memory_access) -{ - char const* sourceCode = R"( - contract C { - function test() public returns (bytes memory) { - bytes memory x = new bytes(5); - for (uint i = 0; i < x.length; ++i) - x[i] = byte(uint8(i + 1)); - assembly { mstore(add(x, 32), "12345678901234567890123456789012") } - return x; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("test()"), encodeArgs(u256(0x20), u256(5), string("12345"))); -} - -BOOST_AUTO_TEST_CASE(inline_assembly_storage_access) -{ - char const* sourceCode = R"( - contract C { - uint16 x; - uint16 public y; - uint public z; - function f() public returns (bool) { - uint off1; - uint off2; - assembly { - sstore(z_slot, 7) - off1 := z_offset - off2 := y_offset - } - assert(off1 == 0); - assert(off2 == 2); - return true; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("z()"), encodeArgs(u256(7))); -} - -BOOST_AUTO_TEST_CASE(inline_assembly_storage_access_inside_function) -{ - char const* sourceCode = R"( - contract C { - uint16 x; - uint16 public y; - uint public z; - function f() public returns (bool) { - uint off1; - uint off2; - assembly { - function f() -> o1 { - sstore(z_slot, 7) - o1 := y_offset - } - off2 := f() - } - assert(off2 == 2); - return true; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("z()"), encodeArgs(u256(7))); -} - -BOOST_AUTO_TEST_CASE(inline_assembly_storage_access_via_pointer) -{ - char const* sourceCode = R"( - contract C { - struct Data { uint contents; } - uint public separator; - Data public a; - uint public separator2; - function f() public returns (bool) { - Data storage x = a; - uint off; - assembly { - sstore(x_slot, 7) - off := x_offset - } - assert(off == 0); - return true; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("a()"), encodeArgs(u256(7))); - ABI_CHECK(callContractFunction("separator()"), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("separator2()"), encodeArgs(u256(0))); -} - -BOOST_AUTO_TEST_CASE(inline_assembly_function_call) -{ - char const* sourceCode = R"( - contract C { - function f() public { - assembly { - function asmfun(a, b, c) -> x, y, z { - x := a - y := b - z := 7 - } - let a1, b1, c1 := asmfun(1, 2, 3) - mstore(0x00, a1) - mstore(0x20, b1) - mstore(0x40, c1) - return(0, 0x60) - } - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(1), u256(2), u256(7))); - ) -} - -BOOST_AUTO_TEST_CASE(inline_assembly_function_call_assignment) -{ - char const* sourceCode = R"( - contract C { - function f() public { - assembly { - let a1, b1, c1 - function asmfun(a, b, c) -> x, y, z { - x := a - y := b - z := 7 - } - a1, b1, c1 := asmfun(1, 2, 3) - mstore(0x00, a1) - mstore(0x20, b1) - mstore(0x40, c1) - return(0, 0x60) - } - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(1), u256(2), u256(7))); - ) -} - -BOOST_AUTO_TEST_CASE(inline_assembly_function_call2) -{ - char const* sourceCode = R"( - contract C { - function f() public { - assembly { - let d := 0x10 - function asmfun(a, b, c) -> x, y, z { - x := a - y := b - z := 7 - } - let a1, b1, c1 := asmfun(1, 2, 3) - mstore(0x00, a1) - mstore(0x20, b1) - mstore(0x40, c1) - mstore(0x60, d) - return(0, 0x80) - } - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(1), u256(2), u256(7), u256(0x10))); - ) -} - -BOOST_AUTO_TEST_CASE(inline_assembly_embedded_function_call) -{ - char const* sourceCode = R"( - contract C { - function f() public { - assembly { - let d := 0x10 - function asmfun(a, b, c) -> x, y, z { - x := g(a) - function g(r) -> s { s := mul(r, r) } - y := g(b) - z := 7 - } - let a1, b1, c1 := asmfun(1, 2, 3) - mstore(0x00, a1) - mstore(0x20, b1) - mstore(0x40, c1) - mstore(0x60, d) - return(0, 0x80) - } - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(1), u256(4), u256(7), u256(0x10))); - ) -} - -BOOST_AUTO_TEST_CASE(inline_assembly_if) -{ - char const* sourceCode = R"( - contract C { - function f(uint a) public returns (uint b) { - assembly { - if gt(a, 1) { b := 2 } - } - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint256)", u256(0)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("f(uint256)", u256(1)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("f(uint256)", u256(2)), encodeArgs(u256(2))); - ABI_CHECK(callContractFunction("f(uint256)", u256(3)), encodeArgs(u256(2))); - ) -} - -BOOST_AUTO_TEST_CASE(inline_assembly_switch) -{ - char const* sourceCode = R"( - contract C { - function f(uint a) public returns (uint b) { - assembly { - switch a - case 1 { b := 8 } - case 2 { b := 9 } - default { b := 2 } - } - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint256)", u256(0)), encodeArgs(u256(2))); - ABI_CHECK(callContractFunction("f(uint256)", u256(1)), encodeArgs(u256(8))); - ABI_CHECK(callContractFunction("f(uint256)", u256(2)), encodeArgs(u256(9))); - ABI_CHECK(callContractFunction("f(uint256)", u256(3)), encodeArgs(u256(2))); - ) -} - -BOOST_AUTO_TEST_CASE(inline_assembly_recursion) -{ - char const* sourceCode = R"( - contract C { - function f(uint a) public returns (uint b) { - assembly { - function fac(n) -> nf { - switch n - case 0 { nf := 1 } - case 1 { nf := 1 } - default { nf := mul(n, fac(sub(n, 1))) } - } - b := fac(a) - } - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint256)", u256(0)), encodeArgs(u256(1))); - ABI_CHECK(callContractFunction("f(uint256)", u256(1)), encodeArgs(u256(1))); - ABI_CHECK(callContractFunction("f(uint256)", u256(2)), encodeArgs(u256(2))); - ABI_CHECK(callContractFunction("f(uint256)", u256(3)), encodeArgs(u256(6))); - ABI_CHECK(callContractFunction("f(uint256)", u256(4)), encodeArgs(u256(24))); - ) -} - -BOOST_AUTO_TEST_CASE(inline_assembly_for) -{ - char const* sourceCode = R"( - contract C { - function f(uint a) public returns (uint b) { - assembly { - function fac(n) -> nf { - nf := 1 - for { let i := n } gt(i, 0) { i := sub(i, 1) } { - nf := mul(nf, i) - } - } - b := fac(a) - } - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint256)", u256(0)), encodeArgs(u256(1))); - ABI_CHECK(callContractFunction("f(uint256)", u256(1)), encodeArgs(u256(1))); - ABI_CHECK(callContractFunction("f(uint256)", u256(2)), encodeArgs(u256(2))); - ABI_CHECK(callContractFunction("f(uint256)", u256(3)), encodeArgs(u256(6))); - ABI_CHECK(callContractFunction("f(uint256)", u256(4)), encodeArgs(u256(24))); - ) -} - -BOOST_AUTO_TEST_CASE(inline_assembly_for2) -{ - char const* sourceCode = R"( - contract C { - uint st; - function f(uint a) public returns (uint b, uint c, uint d) { - st = 0; - assembly { - function sideeffect(r) -> x { sstore(0, add(sload(0), r)) x := 1} - for { let i := a } eq(i, sideeffect(2)) { d := add(d, 3) } { - b := i - i := 0 - } - } - c = st; - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint256)", u256(0)), encodeArgs(u256(0), u256(2), u256(0))); - ABI_CHECK(callContractFunction("f(uint256)", u256(1)), encodeArgs(u256(1), u256(4), u256(3))); - ABI_CHECK(callContractFunction("f(uint256)", u256(2)), encodeArgs(u256(0), u256(2), u256(0))); - ) -} - BOOST_AUTO_TEST_CASE(index_access_with_type_conversion) { // Test for a bug where higher order bits cleanup was not done for array index access. @@ -9809,152 +5852,6 @@ BOOST_AUTO_TEST_CASE(index_access_with_type_conversion) BOOST_CHECK(callContractFunction("f(uint256)", u256(0x101)).size() == 256 * 32); } -BOOST_AUTO_TEST_CASE(delete_on_array_of_structs) -{ - // Test for a bug where we did not increment the counter properly while deleting a dynamic array. - char const* sourceCode = R"( - contract C { - struct S { uint x; uint[] y; } - S[] data; - function f() public returns (bool) { - S storage s1 = data.push(); - s1.x = 2**200; - S storage s2 = data.push(); - s2.x = 2**200; - delete data; - return true; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - // This code interprets x as an array length and thus will go out of gas. - // neither of the two should throw due to out-of-bounds access - ABI_CHECK(callContractFunction("f()"), encodeArgs(true)); - -} - -BOOST_AUTO_TEST_CASE(internal_library_function) -{ - // tests that internal library functions can be called from outside - // and retain the same memory context (i.e. are pulled into the caller's code) - char const* sourceCode = R"( - library L { - function f(uint[] memory _data) internal { - _data[3] = 2; - } - } - contract C { - function f() public returns (uint) { - uint[] memory x = new uint[](7); - x[3] = 8; - L.f(x); - return x[3]; - } - } - )"; - // This has to work without linking, because everything will be inlined. - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(2))); -} - -BOOST_AUTO_TEST_CASE(internal_library_function_calling_private) -{ - // tests that internal library functions that are called from outside and that - // themselves call private functions are still able to (i.e. the private function - // also has to be pulled into the caller's code) - char const* sourceCode = R"( - library L { - function g(uint[] memory _data) private { - _data[3] = 2; - } - function f(uint[] memory _data) internal { - g(_data); - } - } - contract C { - function f() public returns (uint) { - uint[] memory x = new uint[](7); - x[3] = 8; - L.f(x); - return x[3]; - } - } - )"; - // This has to work without linking, because everything will be inlined. - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(2))); -} - -BOOST_AUTO_TEST_CASE(internal_library_function_bound) -{ - char const* sourceCode = R"( - library L { - struct S { uint[] data; } - function f(S memory _s) internal { - _s.data[3] = 2; - } - } - contract C { - using L for L.S; - function f() public returns (uint) { - L.S memory x; - x.data = new uint[](7); - x.data[3] = 8; - x.f(); - return x.data[3]; - } - } - )"; - // This has to work without linking, because everything will be inlined. - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(2))); -} - -BOOST_AUTO_TEST_CASE(internal_library_function_return_var_size) -{ - char const* sourceCode = R"( - library L { - struct S { uint[] data; } - function f(S memory _s) internal returns (uint[] memory) { - _s.data[3] = 2; - return _s.data; - } - } - contract C { - using L for L.S; - function f() public returns (uint) { - L.S memory x; - x.data = new uint[](7); - x.data[3] = 8; - return x.f()[3]; - } - } - )"; - // This has to work without linking, because everything will be inlined. - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(2))); -} - -BOOST_AUTO_TEST_CASE(iszero_bnot_correct) -{ - // A long time ago, some opcodes were renamed, which involved the opcodes - // "iszero" and "not". - char const* sourceCode = R"( - contract C { - function f() public returns (bool) { - bytes32 x = bytes32(uint256(1)); - assembly { x := not(x) } - if (x != ~bytes32(uint256(1))) return false; - assembly { x := iszero(x) } - if (x != bytes32(0)) return false; - return true; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(true)); -} - BOOST_AUTO_TEST_CASE(cleanup_bytes_types) { // Checks that bytesXX types are properly cleaned before they are compared. @@ -9973,23 +5870,6 @@ BOOST_AUTO_TEST_CASE(cleanup_bytes_types) bool v2 = solidity::test::CommonOptions::get().useABIEncoderV2; ABI_CHECK(callContractFunction("f(bytes2,uint16)", string("abc"), u256(0x040102)), v2 ? encodeArgs() : encodeArgs(0)); } -BOOST_AUTO_TEST_CASE(cleanup_bytes_types_shortening) -{ - char const* sourceCode = R"( - contract C { - function f() public pure returns (bytes32 r) { - bytes4 x = 0xffffffff; - bytes2 y = bytes2(x); - assembly { r := y } - // At this point, r and y both store four bytes, but - // y is properly cleaned before the equality check - require(y == bytes2(0xffff)); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs("\xff\xff\xff\xff")); -} BOOST_AUTO_TEST_CASE(cleanup_address_types) { // Checks that address types are properly cleaned before they are compared. @@ -10013,80 +5893,6 @@ BOOST_AUTO_TEST_CASE(cleanup_address_types) ABI_CHECK(callContractFunction("g(address)", u256("0xFFFF1234567890123456789012345678901234567890")), v2 ? encodeArgs() : encodeArgs(0)); } -BOOST_AUTO_TEST_CASE(cleanup_address_types_shortening) -{ - char const* sourceCode = R"( - contract C { - function f() public pure returns (address r) { - bytes21 x = 0x1122334455667788990011223344556677889900ff; - bytes20 y; - assembly { y := x } - address z = address(y); - assembly { r := z } - require(z == 0x1122334455667788990011223344556677889900); - } - function g() public pure returns (address payable r) { - bytes21 x = 0x1122334455667788990011223344556677889900ff; - bytes20 y; - assembly { y := x } - address payable z = address(y); - assembly { r := z } - require(z == 0x1122334455667788990011223344556677889900); - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256("0x1122334455667788990011223344556677889900"))); - ABI_CHECK(callContractFunction("g()"), encodeArgs(u256("0x1122334455667788990011223344556677889900"))); - ) -} - -BOOST_AUTO_TEST_CASE(skip_dynamic_types) -{ - // The EVM cannot provide access to dynamically-sized return values, so we have to skip them. - char const* sourceCode = R"( - contract C { - function f() public returns (uint, uint[] memory, uint) { - return (7, new uint[](2), 8); - } - function g() public returns (uint, uint) { - // Previous implementation "moved" b to the second place and did not skip. - (uint a,, uint b) = this.f(); - return (a, b); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("g()"), encodeArgs(u256(7), u256(8))); -} - -BOOST_AUTO_TEST_CASE(skip_dynamic_types_for_structs) -{ - // For accessors, the dynamic types are already removed in the external signature itself. - char const* sourceCode = R"( - contract C { - struct S { - uint x; - string a; // this is present in the accessor - uint[] b; // this is not present - uint y; - } - S public s; - function g() public returns (uint, uint) { - s.x = 2; - s.a = "abc"; - s.b = [7, 8, 9]; - s.y = 6; - (uint x,, uint y) = this.s(); - return (x, y); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("g()"), encodeArgs(u256(2), u256(6))); -} - BOOST_AUTO_TEST_CASE(failed_create) { char const* sourceCode = R"( @@ -10115,20 +5921,6 @@ BOOST_AUTO_TEST_CASE(failed_create) ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(1))); } -BOOST_AUTO_TEST_CASE(create_dynamic_array_with_zero_length) -{ - char const* sourceCode = R"( - contract C { - function f() public returns (uint) { - uint[][] memory a = new uint[][](0); - return 7; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(7))); -} - BOOST_AUTO_TEST_CASE(correctly_initialize_memory_array_in_constructor) { // Memory arrays are initialized using calldatacopy past the size of the calldata. @@ -10159,122 +5951,6 @@ BOOST_AUTO_TEST_CASE(correctly_initialize_memory_array_in_constructor) } } -BOOST_AUTO_TEST_CASE(return_does_not_skip_modifier) -{ - char const* sourceCode = R"( - contract C { - uint public x; - modifier setsx { - _; - x = 9; - } - function f() setsx public returns (uint) { - return 2; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(2))); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(9))); -} - -BOOST_AUTO_TEST_CASE(break_in_modifier) -{ - char const* sourceCode = R"( - contract C { - uint public x; - modifier run() { - for (uint i = 0; i < 10; i++) { - _; - break; - } - } - function f() run public { - uint k = x; - uint t = k + 1; - x = t; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("f()"), encodeArgs()); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(1))); -} - -BOOST_AUTO_TEST_CASE(continue_in_modifier) -{ - char const* sourceCode = R"( - contract C { - uint public x; - modifier run() { - for (uint i = 0; i < 10; i++) { - if (i % 2 == 1) continue; - _; - } - } - function f() run public { - uint k = x; - uint t = k + 1; - x = t; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("f()"), encodeArgs()); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(5))); -} - -BOOST_AUTO_TEST_CASE(return_in_modifier) -{ - char const* sourceCode = R"( - contract C { - uint public x; - modifier run() { - for (uint i = 1; i < 10; i++) { - if (i == 5) return; - _; - } - } - function f() run public { - uint k = x; - uint t = k + 1; - x = t; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("f()"), encodeArgs()); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(4))); -} - -BOOST_AUTO_TEST_CASE(stacked_return_with_modifiers) -{ - char const* sourceCode = R"( - contract C { - uint public x; - modifier run() { - for (uint i = 0; i < 10; i++) { - _; - break; - } - } - function f() run public { - uint k = x; - uint t = k + 1; - x = t; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("f()"), encodeArgs()); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(1))); -} - BOOST_AUTO_TEST_CASE(mutex) { char const* sourceCode = R"( @@ -10344,44 +6020,6 @@ BOOST_AUTO_TEST_CASE(mutex) BOOST_CHECK_EQUAL(balanceAt(fund), 460); } -BOOST_AUTO_TEST_CASE(calling_nonexisting_contract_throws) -{ - char const* sourceCode = R"YY( - abstract contract D { function g() public virtual; } - contract C { - D d = D(0x1212); - function f() public returns (uint) { - d.g(); - return 7; - } - function g() public returns (uint) { - d.g.gas(200)(); - return 7; - } - function h() public returns (uint) { - address(d).call(""); // this does not throw (low-level) - return 7; - } - } - )YY"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs()); - ABI_CHECK(callContractFunction("g()"), encodeArgs()); - ABI_CHECK(callContractFunction("h()"), encodeArgs(u256(7))); -} - -BOOST_AUTO_TEST_CASE(payable_constructor) -{ - char const* sourceCode = R"( - contract C { - constructor() public payable { } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 27, "C"); - ) -} - BOOST_AUTO_TEST_CASE(payable_function) { char const* sourceCode = R"( @@ -10496,111 +6134,6 @@ BOOST_AUTO_TEST_CASE(mem_resize_is_not_paid_at_call) ABI_CHECK(callContractFunction("f(address)", cAddr), encodeArgs(u256(7))); } -BOOST_AUTO_TEST_CASE(calling_uninitialized_function) -{ - char const* sourceCode = R"( - contract C { - function intern() public returns (uint) { - function (uint) internal returns (uint) x; - x(2); - return 7; - } - function extern() public returns (uint) { - function (uint) external returns (uint) x; - x(2); - return 7; - } - } - )"; - - compileAndRun(sourceCode, 0, "C"); - // This should throw exceptions - ABI_CHECK(callContractFunction("intern()"), encodeArgs()); - ABI_CHECK(callContractFunction("extern()"), encodeArgs()); -} - -BOOST_AUTO_TEST_CASE(calling_uninitialized_function_in_detail) -{ - char const* sourceCode = R"( - contract C { - function() internal returns (uint) x; - int mutex; - function t() public returns (uint) { - if (mutex > 0) - { assembly { mstore(0, 7) return(0, 0x20) } } - mutex = 1; - // Avoid re-executing this function if we jump somewhere. - x(); - return 2; - } - } - )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("t()"), encodeArgs()); -} - -BOOST_AUTO_TEST_CASE(calling_uninitialized_function_through_array) -{ - char const* sourceCode = R"( - contract C { - int mutex; - function t() public returns (uint) { - if (mutex > 0) - { assembly { mstore(0, 7) return(0, 0x20) } } - mutex = 1; - // Avoid re-executing this function if we jump somewhere. - function() internal returns (uint)[200] memory x; - x[0](); - return 2; - } - } - )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("t()"), encodeArgs()); -} - -BOOST_AUTO_TEST_CASE(pass_function_types_internally) -{ - char const* sourceCode = R"( - contract C { - function f(uint x) public returns (uint) { - return eval(g, x); - } - function eval(function(uint) internal returns (uint) x, uint a) internal returns (uint) { - return x(a); - } - function g(uint x) public returns (uint) { return x + 1; } - } - )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint256)", 7), encodeArgs(u256(8))); -} - -BOOST_AUTO_TEST_CASE(pass_function_types_externally) -{ - char const* sourceCode = R"( - contract C { - function f(uint x) public returns (uint) { - return this.eval(this.g, x); - } - function f2(uint x) public returns (uint) { - return eval(this.g, x); - } - function eval(function(uint) external returns (uint) x, uint a) public returns (uint) { - return x(a); - } - function g(uint x) public returns (uint) { return x + 1; } - } - )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint256)", 7), encodeArgs(u256(8))); - ABI_CHECK(callContractFunction("f2(uint256)", 7), encodeArgs(u256(8))); -} - BOOST_AUTO_TEST_CASE(receive_external_function_type) { char const* sourceCode = R"( @@ -10637,615 +6170,8 @@ BOOST_AUTO_TEST_CASE(return_external_function_type) ); } -BOOST_AUTO_TEST_CASE(store_function) -{ - char const* sourceCode = R"( - contract Other { - function addTwo(uint x) public returns (uint) { return x + 2; } - } - contract C { - function (function (uint) external returns (uint)) internal returns (uint) ev; - function (uint) external returns (uint) x; - function store(function(uint) external returns (uint) y) public { - x = y; - } - function eval(function(uint) external returns (uint) y) public returns (uint) { - return y(7); - } - function t() public returns (uint) { - ev = eval; - this.store((new Other()).addTwo); - return ev(x); - } - } - )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("t()"), encodeArgs(u256(9))); -} - -BOOST_AUTO_TEST_CASE(store_function_in_constructor) -{ - char const* sourceCode = R"( - contract C { - uint public result_in_constructor; - function (uint) internal returns (uint) x; - constructor() public { - x = double; - result_in_constructor = use(2); - } - function double(uint _arg) public returns (uint _ret) { - _ret = _arg * 2; - } - function use(uint _arg) public returns (uint) { - return x(_arg); - } - } - )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("use(uint256)", encodeArgs(u256(3))), encodeArgs(u256(6))); - ABI_CHECK(callContractFunction("result_in_constructor()"), encodeArgs(u256(4))); -} - // TODO: store bound internal library functions -BOOST_AUTO_TEST_CASE(store_internal_unused_function_in_constructor) -{ - char const* sourceCode = R"( - contract C { - function () internal returns (uint) x; - constructor() public { - x = unused; - } - function unused() internal returns (uint) { - return 7; - } - function t() public returns (uint) { - return x(); - } - } - )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("t()"), encodeArgs(u256(7))); -} - -BOOST_AUTO_TEST_CASE(store_internal_unused_library_function_in_constructor) -{ - char const* sourceCode = R"( - library L { function x() internal returns (uint) { return 7; } } - contract C { - function () internal returns (uint) x; - constructor() public { - x = L.x; - } - function t() public returns (uint) { - return x(); - } - } - )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("t()"), encodeArgs(u256(7))); -} - -BOOST_AUTO_TEST_CASE(same_function_in_construction_and_runtime) -{ - char const* sourceCode = R"( - contract C { - uint public initial; - constructor() public { - initial = double(2); - } - function double(uint _arg) public returns (uint _ret) { - _ret = _arg * 2; - } - function runtime(uint _arg) public returns (uint) { - return double(_arg); - } - } - )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("runtime(uint256)", encodeArgs(u256(3))), encodeArgs(u256(6))); - ABI_CHECK(callContractFunction("initial()"), encodeArgs(u256(4))); -} - -BOOST_AUTO_TEST_CASE(same_function_in_construction_and_runtime_equality_check) -{ - char const* sourceCode = R"( - contract C { - function (uint) internal returns (uint) x; - constructor() public { - x = double; - } - function test() public returns (bool) { - return x == double; - } - function double(uint _arg) public returns (uint _ret) { - _ret = _arg * 2; - } - } - )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("test()"), encodeArgs(true)); -} - -BOOST_AUTO_TEST_CASE(function_type_library_internal) -{ - char const* sourceCode = R"( - library Utils { - function reduce(uint[] memory array, function(uint, uint) internal returns (uint) f, uint init) internal returns (uint) { - for (uint i = 0; i < array.length; i++) { - init = f(array[i], init); - } - return init; - } - function sum(uint a, uint b) internal returns (uint) { - return a + b; - } - } - contract C { - function f(uint[] memory x) public returns (uint) { - return Utils.reduce(x, Utils.sum, 0); - } - } - )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint256[])", 0x20, 3, u256(1), u256(7), u256(3)), encodeArgs(u256(11))); -} - - -BOOST_AUTO_TEST_CASE(call_function_returning_function) -{ - char const* sourceCode = R"( - contract test { - function f0() public returns (uint) { - return 2; - } - function f1() internal returns (function() internal returns (uint)) { - return f0; - } - function f2() internal returns (function() internal returns (function () internal returns (uint))) { - return f1; - } - function f3() internal returns (function() internal returns (function () internal returns (function () internal returns (uint)))) - { - return f2; - } - function f() public returns (uint) { - function() internal returns(function() internal returns(function() internal returns(function() internal returns(uint)))) x; - x = f3; - return x()()()(); - } - } - )"; - - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "test"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(2))); - ) -} - -BOOST_AUTO_TEST_CASE(mapping_of_functions) -{ - char const* sourceCode = R"( - contract Flow { - bool public success; - - mapping (address => function () internal) stages; - - function stage0() internal { - stages[msg.sender] = stage1; - } - - function stage1() internal { - stages[msg.sender] = stage2; - } - - function stage2() internal { - success = true; - } - - constructor() public { - stages[msg.sender] = stage0; - } - - function f() public returns (uint) { - stages[msg.sender](); - return 7; - } - } - )"; - - compileAndRun(sourceCode, 0, "Flow"); - ABI_CHECK(callContractFunction("success()"), encodeArgs(false)); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(7))); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(7))); - ABI_CHECK(callContractFunction("success()"), encodeArgs(false)); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(7))); - ABI_CHECK(callContractFunction("success()"), encodeArgs(true)); -} - -BOOST_AUTO_TEST_CASE(packed_functions) -{ - char const* sourceCode = R"( - contract C { - // these should take the same slot - function() internal returns (uint) a; - function() external returns (uint) b; - function() external returns (uint) c; - function() internal returns (uint) d; - uint8 public x; - - function set() public { - x = 2; - d = g; - c = this.h; - b = this.h; - a = g; - } - function t1() public returns (uint) { - return a(); - } - function t2() public returns (uint) { - return b(); - } - function t3() public returns (uint) { - return a(); - } - function t4() public returns (uint) { - return b(); - } - function g() public returns (uint) { - return 7; - } - function h() public returns (uint) { - return 8; - } - } - )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("set()"), encodeArgs()); - ABI_CHECK(callContractFunction("t1()"), encodeArgs(u256(7))); - ABI_CHECK(callContractFunction("t2()"), encodeArgs(u256(8))); - ABI_CHECK(callContractFunction("t3()"), encodeArgs(u256(7))); - ABI_CHECK(callContractFunction("t4()"), encodeArgs(u256(8))); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(2))); -} - -BOOST_AUTO_TEST_CASE(function_memory_array) -{ - char const* sourceCode = R"( - contract C { - function a(uint x) public returns (uint) { return x + 1; } - function b(uint x) public returns (uint) { return x + 2; } - function c(uint x) public returns (uint) { return x + 3; } - function d(uint x) public returns (uint) { return x + 5; } - function e(uint x) public returns (uint) { return x + 8; } - function test(uint x, uint i) public returns (uint) { - function(uint) internal returns (uint)[] memory arr = - new function(uint) internal returns (uint)[](10); - arr[0] = a; - arr[1] = b; - arr[2] = c; - arr[3] = d; - arr[4] = e; - return arr[i](x); - } - } - )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("test(uint256,uint256)", u256(10), u256(0)), encodeArgs(u256(11))); - ABI_CHECK(callContractFunction("test(uint256,uint256)", u256(10), u256(1)), encodeArgs(u256(12))); - ABI_CHECK(callContractFunction("test(uint256,uint256)", u256(10), u256(2)), encodeArgs(u256(13))); - ABI_CHECK(callContractFunction("test(uint256,uint256)", u256(10), u256(3)), encodeArgs(u256(15))); - ABI_CHECK(callContractFunction("test(uint256,uint256)", u256(10), u256(4)), encodeArgs(u256(18))); - ABI_CHECK(callContractFunction("test(uint256,uint256)", u256(10), u256(5)), encodeArgs()); -} - -BOOST_AUTO_TEST_CASE(function_delete_storage) -{ - char const* sourceCode = R"( - contract C { - function a() public returns (uint) { return 7; } - function() internal returns (uint) y; - function set() public returns (uint) { - y = a; - return y(); - } - function d() public returns (uint) { - delete y; - return 1; - } - function ca() public returns (uint) { - return y(); - } - } - )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("set()"), encodeArgs(u256(7))); - ABI_CHECK(callContractFunction("ca()"), encodeArgs(u256(7))); - ABI_CHECK(callContractFunction("d()"), encodeArgs(u256(1))); - ABI_CHECK(callContractFunction("ca()"), encodeArgs()); -} - -BOOST_AUTO_TEST_CASE(function_delete_stack) -{ - char const* sourceCode = R"( - contract C { - function a() public returns (uint) { return 7; } - function test() public returns (uint) { - function () returns (uint) y = a; - delete y; - y(); - } - } - )"; - - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("test()"), encodeArgs()); - ) -} - -BOOST_AUTO_TEST_CASE(copy_function_storage_array) -{ - char const* sourceCode = R"( - contract C { - function() internal returns (uint)[] x; - function() internal returns (uint)[] y; - function test() public returns (uint) { - x = new function() internal returns (uint)[](10); - x[9] = a; - y = x; - return y[9](); - } - function a() public returns (uint) { - return 7; - } - } - )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("test()"), encodeArgs(u256(7))); -} - -BOOST_AUTO_TEST_CASE(function_array_cross_calls) -{ - char const* sourceCode = R"( - contract D { - function f(function() external returns (function() external returns (uint))[] memory x) - public returns (function() external returns (uint)[3] memory r) - { - r[0] = x[0](); - r[1] = x[1](); - r[2] = x[2](); - } - } - contract C { - function test() public returns (uint, uint, uint) { - function() external returns (function() external returns (uint))[] memory x = - new function() external returns (function() external returns (uint))[](10); - for (uint i = 0; i < x.length; i ++) - x[i] = this.h; - x[0] = this.htwo; - function() external returns (uint)[3] memory y = (new D()).f(x); - return (y[0](), y[1](), y[2]()); - } - function e() public returns (uint) { return 5; } - function f() public returns (uint) { return 6; } - function g() public returns (uint) { return 7; } - uint counter; - function h() public returns (function() external returns (uint)) { - return counter++ == 0 ? this.f : this.g; - } - function htwo() public returns (function() external returns (uint)) { - return this.e; - } - } - )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("test()"), encodeArgs(u256(5), u256(6), u256(7))); -} - -BOOST_AUTO_TEST_CASE(copy_internal_function_array_to_storage) -{ - char const* sourceCode = R"( - contract C { - function() internal returns (uint)[20] x; - int mutex; - function one() public returns (uint) { - function() internal returns (uint)[20] memory xmem; - x = xmem; - return 3; - } - function two() public returns (uint) { - if (mutex > 0) - return 7; - mutex = 1; - // If this test fails, it might re-execute this function. - x[0](); - return 2; - } - } - )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("one()"), encodeArgs(u256(3))); - ABI_CHECK(callContractFunction("two()"), encodeArgs()); -} - -BOOST_AUTO_TEST_CASE(shift_constant_left) -{ - char const* sourceCode = R"( - contract C { - uint public a = 0x42 << 8; - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("a()"), encodeArgs(u256(0x4200))); -} - -BOOST_AUTO_TEST_CASE(shift_negative_constant_left) -{ - char const* sourceCode = R"( - contract C { - int public a = -0x42 << 8; - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("a()"), encodeArgs(u256(-0x4200))); -} - -BOOST_AUTO_TEST_CASE(shift_constant_right) -{ - char const* sourceCode = R"( - contract C { - uint public a = 0x4200 >> 8; - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("a()"), encodeArgs(u256(0x42))); -} - -BOOST_AUTO_TEST_CASE(shift_negative_constant_right) -{ - char const* sourceCode = R"( - contract C { - int public a = -0x4200 >> 8; - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("a()"), encodeArgs(u256(-0x42))); -} - -BOOST_AUTO_TEST_CASE(shift_left) -{ - char const* sourceCode = R"( - contract C { - function f(uint a, uint b) public returns (uint) { - return a << b; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(0)), encodeArgs(u256(0x4266))); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(8)), encodeArgs(u256(0x426600))); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(16)), encodeArgs(u256(0x42660000))); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(17)), encodeArgs(u256(0x84cc0000))); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(240)), fromHex("4266000000000000000000000000000000000000000000000000000000000000")); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(256)), encodeArgs(u256(0))); -} - -BOOST_AUTO_TEST_CASE(shift_left_uint32) -{ - char const* sourceCode = R"( - contract C { - function f(uint32 a, uint32 b) public returns (uint) { - return a << b; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint32,uint32)", u256(0x4266), u256(0)), encodeArgs(u256(0x4266))); - ABI_CHECK(callContractFunction("f(uint32,uint32)", u256(0x4266), u256(8)), encodeArgs(u256(0x426600))); - ABI_CHECK(callContractFunction("f(uint32,uint32)", u256(0x4266), u256(16)), encodeArgs(u256(0x42660000))); - ABI_CHECK(callContractFunction("f(uint32,uint32)", u256(0x4266), u256(17)), encodeArgs(u256(0x84cc0000))); - ABI_CHECK(callContractFunction("f(uint32,uint32)", u256(0x4266), u256(32)), encodeArgs(u256(0))); -} - -BOOST_AUTO_TEST_CASE(shift_left_uint8) -{ - char const* sourceCode = R"( - contract C { - function f(uint8 a, uint8 b) public returns (uint) { - return a << b; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint8,uint8)", u256(0x66), u256(0)), encodeArgs(u256(0x66))); - ABI_CHECK(callContractFunction("f(uint8,uint8)", u256(0x66), u256(8)), encodeArgs(u256(0))); -} - -BOOST_AUTO_TEST_CASE(shift_left_larger_type) -{ - // This basically tests proper cleanup and conversion. It should not convert x to int8. - char const* sourceCode = R"( - contract C { - function f() public returns (int8) { - uint8 x = 254; - int8 y = 1; - return y << x; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0))); -} - -BOOST_AUTO_TEST_CASE(shift_left_assignment) -{ - char const* sourceCode = R"( - contract C { - function f(uint a, uint b) public returns (uint) { - a <<= b; - return a; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(0)), encodeArgs(u256(0x4266))); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(8)), encodeArgs(u256(0x426600))); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(16)), encodeArgs(u256(0x42660000))); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(17)), encodeArgs(u256(0x84cc0000))); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(240)), fromHex("4266000000000000000000000000000000000000000000000000000000000000")); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(256)), encodeArgs(u256(0))); -} - -BOOST_AUTO_TEST_CASE(shift_left_assignment_different_type) -{ - char const* sourceCode = R"( - contract C { - function f(uint a, uint8 b) public returns (uint) { - a <<= b; - return a; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint256,uint8)", u256(0x4266), u256(0)), encodeArgs(u256(0x4266))); - ABI_CHECK(callContractFunction("f(uint256,uint8)", u256(0x4266), u256(8)), encodeArgs(u256(0x426600))); - ABI_CHECK(callContractFunction("f(uint256,uint8)", u256(0x4266), u256(16)), encodeArgs(u256(0x42660000))); - ABI_CHECK(callContractFunction("f(uint256,uint8)", u256(0x4266), u256(17)), encodeArgs(u256(0x84cc0000))); - ABI_CHECK(callContractFunction("f(uint256,uint8)", u256(0x4266), u256(240)), fromHex("4266000000000000000000000000000000000000000000000000000000000000")); -} - -BOOST_AUTO_TEST_CASE(shift_right) -{ - char const* sourceCode = R"( - contract C { - function f(uint a, uint b) public returns (uint) { - return a >> b; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(0)), encodeArgs(u256(0x4266))); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(8)), encodeArgs(u256(0x42))); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(16)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(17)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(1)<<255, u256(5)), encodeArgs(u256(1)<<250)); -} - BOOST_AUTO_TEST_CASE(shift_right_garbled) { char const* sourceCode = R"( @@ -11299,177 +6225,6 @@ BOOST_AUTO_TEST_CASE(shift_right_garbled_signed) ABI_CHECK(callContractFunction("g(int8,uint8)", u256(0x0), u256(0x1004)), v2 ? encodeArgs() : encodeArgs(u256(-1))); } -BOOST_AUTO_TEST_CASE(shift_right_uint32) -{ - char const* sourceCode = R"( - contract C { - function f(uint32 a, uint32 b) public returns (uint) { - return a >> b; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint32,uint32)", u256(0x4266), u256(0)), encodeArgs(u256(0x4266))); - ABI_CHECK(callContractFunction("f(uint32,uint32)", u256(0x4266), u256(8)), encodeArgs(u256(0x42))); - ABI_CHECK(callContractFunction("f(uint32,uint32)", u256(0x4266), u256(16)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("f(uint32,uint32)", u256(0x4266), u256(17)), encodeArgs(u256(0))); -} - -BOOST_AUTO_TEST_CASE(shift_right_uint8) -{ - char const* sourceCode = R"( - contract C { - function f(uint8 a, uint8 b) public returns (uint) { - return a >> b; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint8,uint8)", u256(0x66), u256(0)), encodeArgs(u256(0x66))); - ABI_CHECK(callContractFunction("f(uint8,uint8)", u256(0x66), u256(8)), encodeArgs(u256(0x0))); -} - -BOOST_AUTO_TEST_CASE(shift_right_assignment) -{ - char const* sourceCode = R"( - contract C { - function f(uint a, uint b) public returns (uint) { - a >>= b; - return a; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(0)), encodeArgs(u256(0x4266))); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(8)), encodeArgs(u256(0x42))); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(16)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(17)), encodeArgs(u256(0))); -} - -BOOST_AUTO_TEST_CASE(shift_right_assignment_signed) -{ - char const* sourceCode = R"( - contract C { - function f(int a, int b) public returns (int) { - a >>= b; - return a; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(0x4266), u256(0)), encodeArgs(u256(0x4266))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(0x4266), u256(8)), encodeArgs(u256(0x42))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(0x4266), u256(16)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(0x4266), u256(17)), encodeArgs(u256(0))); -} - -BOOST_AUTO_TEST_CASE(shift_right_negative_lvalue) -{ - char const* sourceCode = R"( - contract C { - function f(int a, int b) public returns (int) { - return a >> b; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4266), u256(0)), encodeArgs(u256(-4266))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4266), u256(1)), encodeArgs(u256(-2133))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4266), u256(4)), encodeArgs(u256(-267))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4266), u256(8)), encodeArgs(u256(-17))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4266), u256(16)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4266), u256(17)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4267), u256(0)), encodeArgs(u256(-4267))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4267), u256(1)), encodeArgs(u256(-2134))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4267), u256(4)), encodeArgs(u256(-267))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4267), u256(8)), encodeArgs(u256(-17))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4267), u256(16)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4267), u256(17)), encodeArgs(u256(-1))); -} - -BOOST_AUTO_TEST_CASE(shift_right_negative_literal) -{ - char const* sourceCode = R"( - contract C { - function f1() public pure returns (bool) { - return (-4266 >> 0) == -4266; - } - function f2() public pure returns (bool) { - return (-4266 >> 1) == -2133; - } - function f3() public pure returns (bool) { - return (-4266 >> 4) == -267; - } - function f4() public pure returns (bool) { - return (-4266 >> 8) == -17; - } - function f5() public pure returns (bool) { - return (-4266 >> 16) == -1; - } - function f6() public pure returns (bool) { - return (-4266 >> 17) == -1; - } - function g1() public pure returns (bool) { - return (-4267 >> 0) == -4267; - } - function g2() public pure returns (bool) { - return (-4267 >> 1) == -2134; - } - function g3() public pure returns (bool) { - return (-4267 >> 4) == -267; - } - function g4() public pure returns (bool) { - return (-4267 >> 8) == -17; - } - function g5() public pure returns (bool) { - return (-4267 >> 16) == -1; - } - function g6() public pure returns (bool) { - return (-4267 >> 17) == -1; - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f1()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("f2()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("f3()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("f4()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("f5()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("f6()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("g1()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("g2()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("g3()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("g4()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("g5()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("g6()"), encodeArgs(true)); - ) -} - -BOOST_AUTO_TEST_CASE(shift_right_negative_lvalue_int8) -{ - char const* sourceCode = R"( - contract C { - function f(int8 a, int8 b) public returns (int) { - return a >> b; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(int8,int8)", u256(-66), u256(0)), encodeArgs(u256(-66))); - ABI_CHECK(callContractFunction("f(int8,int8)", u256(-66), u256(1)), encodeArgs(u256(-33))); - ABI_CHECK(callContractFunction("f(int8,int8)", u256(-66), u256(4)), encodeArgs(u256(-5))); - ABI_CHECK(callContractFunction("f(int8,int8)", u256(-66), u256(8)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int8,int8)", u256(-66), u256(16)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int8,int8)", u256(-66), u256(17)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int8,int8)", u256(-67), u256(0)), encodeArgs(u256(-67))); - ABI_CHECK(callContractFunction("f(int8,int8)", u256(-67), u256(1)), encodeArgs(u256(-34))); - ABI_CHECK(callContractFunction("f(int8,int8)", u256(-67), u256(4)), encodeArgs(u256(-5))); - ABI_CHECK(callContractFunction("f(int8,int8)", u256(-67), u256(8)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int8,int8)", u256(-67), u256(16)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int8,int8)", u256(-67), u256(17)), encodeArgs(u256(-1))); -} - BOOST_AUTO_TEST_CASE(shift_right_negative_lvalue_signextend_int8) { char const* sourceCode = R"( @@ -11524,198 +6279,6 @@ BOOST_AUTO_TEST_CASE(shift_right_negative_lvalue_signextend_int32) ABI_CHECK(callContractFunction("f(int32,int32)", u256(0xFFFFFF99u), u256(8)), v2 ? encodeArgs() : encodeArgs(u256(-1))); } - -BOOST_AUTO_TEST_CASE(shift_right_negative_lvalue_int16) -{ - char const* sourceCode = R"( - contract C { - function f(int16 a, int16 b) public returns (int) { - return a >> b; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(int16,int16)", u256(-4266), u256(0)), encodeArgs(u256(-4266))); - ABI_CHECK(callContractFunction("f(int16,int16)", u256(-4266), u256(1)), encodeArgs(u256(-2133))); - ABI_CHECK(callContractFunction("f(int16,int16)", u256(-4266), u256(4)), encodeArgs(u256(-267))); - ABI_CHECK(callContractFunction("f(int16,int16)", u256(-4266), u256(8)), encodeArgs(u256(-17))); - ABI_CHECK(callContractFunction("f(int16,int16)", u256(-4266), u256(16)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int16,int16)", u256(-4266), u256(17)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int16,int16)", u256(-4267), u256(0)), encodeArgs(u256(-4267))); - ABI_CHECK(callContractFunction("f(int16,int16)", u256(-4267), u256(1)), encodeArgs(u256(-2134))); - ABI_CHECK(callContractFunction("f(int16,int16)", u256(-4267), u256(4)), encodeArgs(u256(-267))); - ABI_CHECK(callContractFunction("f(int16,int16)", u256(-4267), u256(8)), encodeArgs(u256(-17))); - ABI_CHECK(callContractFunction("f(int16,int16)", u256(-4267), u256(16)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int16,int16)", u256(-4267), u256(17)), encodeArgs(u256(-1))); -} - -BOOST_AUTO_TEST_CASE(shift_right_negative_lvalue_int32) -{ - char const* sourceCode = R"( - contract C { - function f(int32 a, int32 b) public returns (int) { - return a >> b; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(int32,int32)", u256(-4266), u256(0)), encodeArgs(u256(-4266))); - ABI_CHECK(callContractFunction("f(int32,int32)", u256(-4266), u256(1)), encodeArgs(u256(-2133))); - ABI_CHECK(callContractFunction("f(int32,int32)", u256(-4266), u256(4)), encodeArgs(u256(-267))); - ABI_CHECK(callContractFunction("f(int32,int32)", u256(-4266), u256(8)), encodeArgs(u256(-17))); - ABI_CHECK(callContractFunction("f(int32,int32)", u256(-4266), u256(16)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int32,int32)", u256(-4266), u256(17)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int32,int32)", u256(-4267), u256(0)), encodeArgs(u256(-4267))); - ABI_CHECK(callContractFunction("f(int32,int32)", u256(-4267), u256(1)), encodeArgs(u256(-2134))); - ABI_CHECK(callContractFunction("f(int32,int32)", u256(-4267), u256(4)), encodeArgs(u256(-267))); - ABI_CHECK(callContractFunction("f(int32,int32)", u256(-4267), u256(8)), encodeArgs(u256(-17))); - ABI_CHECK(callContractFunction("f(int32,int32)", u256(-4267), u256(16)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int32,int32)", u256(-4267), u256(17)), encodeArgs(u256(-1))); -} - -BOOST_AUTO_TEST_CASE(shift_right_negative_lvalue_assignment) -{ - char const* sourceCode = R"( - contract C { - function f(int a, int b) public returns (int) { - a >>= b; - return a; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4266), u256(0)), encodeArgs(u256(-4266))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4266), u256(1)), encodeArgs(u256(-2133))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4266), u256(4)), encodeArgs(u256(-267))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4266), u256(8)), encodeArgs(u256(-17))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4266), u256(16)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4266), u256(17)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4267), u256(0)), encodeArgs(u256(-4267))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4267), u256(1)), encodeArgs(u256(-2134))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4267), u256(4)), encodeArgs(u256(-267))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4267), u256(8)), encodeArgs(u256(-17))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4267), u256(16)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4267), u256(17)), encodeArgs(u256(-1))); -} - -BOOST_AUTO_TEST_CASE(shift_negative_rvalue) -{ - char const* sourceCode = R"( - contract C { - function f(int a, int b) public returns (int) { - return a << b; - } - function g(int a, int b) public returns (int) { - return a >> b; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(1), u256(-1)), encodeArgs()); - ABI_CHECK(callContractFunction("g(int256,int256)", u256(1), u256(-1)), encodeArgs()); -} - -BOOST_AUTO_TEST_CASE(shift_negative_rvalue_assignment) -{ - char const* sourceCode = R"( - contract C { - function f(int a, int b) public returns (int) { - a <<= b; - return a; - } - function g(int a, int b) public returns (int) { - a >>= b; - return a; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(1), u256(-1)), encodeArgs()); - ABI_CHECK(callContractFunction("g(int256,int256)", u256(1), u256(-1)), encodeArgs()); -} - -BOOST_AUTO_TEST_CASE(shift_constant_left_assignment) -{ - char const* sourceCode = R"( - contract C { - function f() public returns (uint a) { - a = 0x42; - a <<= 8; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0x4200))); -} - -BOOST_AUTO_TEST_CASE(shift_constant_right_assignment) -{ - char const* sourceCode = R"( - contract C { - function f() public returns (uint a) { - a = 0x4200; - a >>= 8; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0x42))); -} - -BOOST_AUTO_TEST_CASE(shift_cleanup) -{ - char const* sourceCode = R"( - contract C { - function f() public returns (uint16 x) { - x = 0xffff; - x += 32; - x <<= 8; - x >>= 16; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0x0))); -} - -BOOST_AUTO_TEST_CASE(shift_cleanup_garbled) -{ - char const* sourceCode = R"( - contract C { - function f() public returns (uint8 x) { - assembly { - x := 0xffff - } - x >>= 8; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0x0))); -} - -BOOST_AUTO_TEST_CASE(shift_overflow) -{ - char const* sourceCode = R"( - contract C { - function leftU(uint8 x, uint8 y) public returns (uint8) { - return x << y; - } - function leftS(int8 x, int8 y) public returns (int8) { - return x << y; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("leftU(uint8,uint8)", 255, 8), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("leftU(uint8,uint8)", 255, 1), encodeArgs(u256(254))); - ABI_CHECK(callContractFunction("leftU(uint8,uint8)", 255, 0), encodeArgs(u256(255))); - - // Result is -128 and output is sign-extended, not zero-padded. - ABI_CHECK(callContractFunction("leftS(int8,int8)", 1, 7), encodeArgs(u256(0) - 128)); - ABI_CHECK(callContractFunction("leftS(int8,int8)", 1, 6), encodeArgs(u256(64))); -} - BOOST_AUTO_TEST_CASE(shift_bytes) { char const* sourceCode = R"( @@ -11754,108 +6317,6 @@ BOOST_AUTO_TEST_CASE(shift_bytes_cleanup) ABI_CHECK(callContractFunction("right(uint8)", 8 * 8), encodeArgs(string(8, 0) + "123456789012")); } -BOOST_AUTO_TEST_CASE(exp_cleanup) -{ - char const* sourceCode = R"( - contract C { - function f() public pure returns (uint8 x) { - uint8 y = uint8(2) ** uint8(8); - return 0 ** y; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0x1))); -} - -BOOST_AUTO_TEST_CASE(exp_cleanup_direct) -{ - char const* sourceCode = R"( - contract C { - function f() public pure returns (uint8 x) { - return uint8(0) ** uint8(uint8(2) ** uint8(8)); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0x1))); -} - -BOOST_AUTO_TEST_CASE(exp_cleanup_nonzero_base) -{ - char const* sourceCode = R"( - contract C { - function f() public pure returns (uint8 x) { - return uint8(0x166) ** uint8(uint8(2) ** uint8(8)); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0x1))); -} - -BOOST_AUTO_TEST_CASE(cleanup_in_compound_assign) -{ - char const* sourceCode = R"( - contract C { - function test() public returns (uint, uint) { - uint32 a = 0xffffffff; - uint16 x = uint16(a); - uint16 y = x; - x /= 0x100; - y = y / 0x100; - return (x, y); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("test()"), encodeArgs(u256(0xff), u256(0xff))); -} - -BOOST_AUTO_TEST_CASE(inline_assembly_in_modifiers) -{ - char const* sourceCode = R"( - contract C { - modifier m { - uint a = 1; - assembly { - a := 2 - } - if (a != 2) - revert(); - _; - } - function f() m public returns (bool) { - return true; - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(true)); - ) -} - -BOOST_AUTO_TEST_CASE(packed_storage_overflow) -{ - char const* sourceCode = R"( - contract C { - uint16 x = 0x1234; - uint16 a = 0xffff; - uint16 b; - function f() public returns (uint, uint, uint, uint) { - a++; - uint c = b; - delete b; - a -= 2; - return (x, c, b, a); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0x1234), u256(0), u256(0), u256(0xfffe))); -} - BOOST_AUTO_TEST_CASE(contracts_separated_with_comment) { char const* sourceCode = R"( @@ -11870,7 +6331,6 @@ BOOST_AUTO_TEST_CASE(contracts_separated_with_comment) ) } - BOOST_AUTO_TEST_CASE(include_creation_bytecode_only_once) { char const* sourceCode = R"( @@ -11900,97 +6360,6 @@ BOOST_AUTO_TEST_CASE(include_creation_bytecode_only_once) ); } -BOOST_AUTO_TEST_CASE(recursive_structs) -{ - char const* sourceCode = R"( - contract C { - struct S { - S[] x; - } - S sstorage; - function f() public returns (uint) { - S memory s; - s.x = new S[](10); - delete s; - // TODO Uncomment after implemented. - // sstorage.x.push(); - delete sstorage; - return 1; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(1))); -} - -BOOST_AUTO_TEST_CASE(invalid_instruction) -{ - char const* sourceCode = R"( - contract C { - function f() public { - assembly { - invalid() - } - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs()); - ) -} - -BOOST_AUTO_TEST_CASE(assert_require) -{ - char const* sourceCode = R"( - contract C { - function f() public { - assert(false); - } - function g(bool val) public returns (bool) { - assert(val == true); - return true; - } - function h(bool val) public returns (bool) { - require(val); - return true; - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs()); - ABI_CHECK(callContractFunction("g(bool)", false), encodeArgs()); - ABI_CHECK(callContractFunction("g(bool)", true), encodeArgs(true)); - ABI_CHECK(callContractFunction("h(bool)", false), encodeArgs()); - ABI_CHECK(callContractFunction("h(bool)", true), encodeArgs(true)); - ) -} - -BOOST_AUTO_TEST_CASE(revert) -{ - char const* sourceCode = R"( - contract C { - uint public a = 42; - function f() public { - a = 1; - revert(); - } - function g() public { - a = 1; - assembly { - revert(0, 0) - } - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs()); - ABI_CHECK(callContractFunction("a()"), encodeArgs(u256(42))); - ABI_CHECK(callContractFunction("g()"), encodeArgs()); - ABI_CHECK(callContractFunction("a()"), encodeArgs(u256(42))); -} - BOOST_AUTO_TEST_CASE(revert_with_cause) { char const* sourceCode = R"( @@ -12249,85 +6618,6 @@ BOOST_AUTO_TEST_CASE(bubble_up_error_messages_through_create) } } -BOOST_AUTO_TEST_CASE(negative_stack_height) -{ - // This code was causing negative stack height during code generation - // because the stack height was not adjusted at the beginning of functions. - char const* sourceCode = R"( - contract C { - mapping(uint => Invoice) public invoices; - struct Invoice { - uint AID; - bool Aboola; - bool Aboolc; - bool exists; - } - function nredit(uint startindex) public pure returns(uint[500] memory CIDs, uint[500] memory dates, uint[500] memory RIDs, bool[500] memory Cboolas, uint[500] memory amounts){} - function return500InvoicesByDates(uint begindate, uint enddate, uint startindex) public view returns(uint[500] memory AIDs, bool[500] memory Aboolas, uint[500] memory dates, bytes32[3][500] memory Abytesas, bytes32[3][500] memory bytesbs, bytes32[2][500] memory bytescs, uint[500] memory amounts, bool[500] memory Aboolbs, bool[500] memory Aboolcs){} - function return500PaymentsByDates(uint begindate, uint enddate, uint startindex) public view returns(uint[500] memory BIDs, uint[500] memory dates, uint[500] memory RIDs, bool[500] memory Bboolas, bytes32[3][500] memory bytesbs,bytes32[2][500] memory bytescs, uint[500] memory amounts, bool[500] memory Bboolbs){} - } - )"; - compileAndRun(sourceCode, 0, "C"); -} - -BOOST_AUTO_TEST_CASE(literal_empty_string) -{ - char const* sourceCode = R"( - contract C { - bytes32 public x; - uint public a; - function f(bytes32 _x, uint _a) public { - x = _x; - a = _a; - } - function g() public { - this.f("", 2); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("a()"), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("g()"), encodeArgs()); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("a()"), encodeArgs(u256(2))); -} - -BOOST_AUTO_TEST_CASE(scientific_notation) -{ - char const* sourceCode = R"( - contract C { - function f() public returns (uint) { - return 2e10 wei; - } - function g() public returns (uint) { - return 200e-2 wei; - } - function h() public returns (uint) { - return 2.5e1; - } - function i() public returns (int) { - return -2e10; - } - function j() public returns (int) { - return -200e-2; - } - function k() public returns (int) { - return -2.5e1; - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(20000000000))); - ABI_CHECK(callContractFunction("g()"), encodeArgs(u256(2))); - ABI_CHECK(callContractFunction("h()"), encodeArgs(u256(25))); - ABI_CHECK(callContractFunction("i()"), encodeArgs(u256(-20000000000))); - ABI_CHECK(callContractFunction("j()"), encodeArgs(u256(-2))); - ABI_CHECK(callContractFunction("k()"), encodeArgs(u256(-25))); - ) -} - BOOST_AUTO_TEST_CASE(interface_contract) { char const* sourceCode = R"( @@ -12363,23 +6653,6 @@ BOOST_AUTO_TEST_CASE(interface_contract) ABI_CHECK(callContractFunction("f(address)", recipient), encodeArgs(true)); } -BOOST_AUTO_TEST_CASE(keccak256_assembly) -{ - char const* sourceCode = R"( - contract C { - function f() public pure returns (bytes32 ret) { - assembly { - ret := keccak256(0, 0) - } - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), fromHex("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")); - ) -} - BOOST_AUTO_TEST_CASE(multi_modifiers) { // This triggered a bug in some version because the variable in the modifier was not @@ -12407,26 +6680,6 @@ BOOST_AUTO_TEST_CASE(multi_modifiers) ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(12))); } -BOOST_AUTO_TEST_CASE(inlineasm_empty_let) -{ - char const* sourceCode = R"( - contract C { - function f() public pure returns (uint a, uint b) { - assembly { - let x - let y, z - a := x - b := z - } - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0), u256(0))); - ) -} - BOOST_AUTO_TEST_CASE(bare_call_invalid_address) { char const* sourceCode = R"YY( @@ -12691,140 +6944,6 @@ BOOST_AUTO_TEST_CASE(function_types_sig) ABI_CHECK(callContractFunction("i()"), encodeArgs(asString(FixedHash<4>(util::keccak256("x()")).asBytes()))); } -BOOST_AUTO_TEST_CASE(constant_string) -{ - char const* sourceCode = R"( - contract C { - bytes constant a = "\x03\x01\x02"; - bytes constant b = hex"030102"; - string constant c = "hello"; - function f() public returns (bytes memory) { - return a; - } - function g() public returns (bytes memory) { - return b; - } - function h() public returns (bytes memory) { - return bytes(c); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeDyn(string("\x03\x01\x02"))); - ABI_CHECK(callContractFunction("g()"), encodeDyn(string("\x03\x01\x02"))); - ABI_CHECK(callContractFunction("h()"), encodeDyn(string("hello"))); -} - -BOOST_AUTO_TEST_CASE(address_overload_resolution) -{ - char const* sourceCode = R"( - contract C { - function balance() public returns (uint) { - return 1; - } - function transfer(uint amount) public returns (uint) { - return amount; - } - } - contract D { - function f() public returns (uint) { - return (new C()).balance(); - } - function g() public returns (uint) { - return (new C()).transfer(5); - } - } - )"; - compileAndRun(sourceCode, 0, "D"); - BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(1))); - BOOST_CHECK(callContractFunction("g()") == encodeArgs(u256(5))); -} - -BOOST_AUTO_TEST_CASE(abi_encode) -{ - char const* sourceCode = R"( - contract C { - function f0() public returns (bytes memory) { - return abi.encode(); - } - function f1() public returns (bytes memory) { - return abi.encode(1, 2); - } - function f2() public returns (bytes memory) { - string memory x = "abc"; - return abi.encode(1, x, 2); - } - function f3() public returns (bytes memory r) { - // test that memory is properly allocated - string memory x = "abc"; - r = abi.encode(1, x, 2); - bytes memory y = "def"; - require(y[0] == "d"); - y[0] = "e"; - require(y[0] == "e"); - } - function f4() public returns (bytes memory) { - bytes4 x = "abcd"; - return abi.encode(bytes2(x)); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f0()"), encodeArgs(0x20, 0)); - ABI_CHECK(callContractFunction("f1()"), encodeArgs(0x20, 0x40, 1, 2)); - ABI_CHECK(callContractFunction("f2()"), encodeArgs(0x20, 0xa0, 1, 0x60, 2, 3, "abc")); - ABI_CHECK(callContractFunction("f3()"), encodeArgs(0x20, 0xa0, 1, 0x60, 2, 3, "abc")); - ABI_CHECK(callContractFunction("f4()"), encodeArgs(0x20, 0x20, "ab")); -} - -BOOST_AUTO_TEST_CASE(abi_encode_v2) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - struct S { uint a; uint[] b; } - function f0() public pure returns (bytes memory) { - return abi.encode(); - } - function f1() public pure returns (bytes memory) { - return abi.encode(1, 2); - } - function f2() public pure returns (bytes memory) { - string memory x = "abc"; - return abi.encode(1, x, 2); - } - function f3() public pure returns (bytes memory r) { - // test that memory is properly allocated - string memory x = "abc"; - r = abi.encode(1, x, 2); - bytes memory y = "def"; - require(y[0] == "d"); - y[0] = "e"; - require(y[0] == "e"); - } - S s; - function f4() public returns (bytes memory r) { - string memory x = "abc"; - s.a = 7; - s.b.push(2); - s.b.push(3); - r = abi.encode(1, x, s, 2); - bytes memory y = "def"; - require(y[0] == "d"); - y[0] = "e"; - require(y[0] == "e"); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f0()"), encodeArgs(0x20, 0)); - ABI_CHECK(callContractFunction("f1()"), encodeArgs(0x20, 0x40, 1, 2)); - ABI_CHECK(callContractFunction("f2()"), encodeArgs(0x20, 0xa0, 1, 0x60, 2, 3, "abc")); - ABI_CHECK(callContractFunction("f3()"), encodeArgs(0x20, 0xa0, 1, 0x60, 2, 3, "abc")); - ABI_CHECK(callContractFunction("f4()"), encodeArgs(0x20, 0x160, 1, 0x80, 0xc0, 2, 3, "abc", 7, 0x40, 2, 2, 3)); -} - - BOOST_AUTO_TEST_CASE(abi_encodePacked) { char const* sourceCode = R"( @@ -12867,11 +6986,7 @@ BOOST_AUTO_TEST_CASE(abi_encodePacked) ABI_CHECK(callContractFunction("f1()"), encodeArgs(0x20, 2, "\x01\x02")); ABI_CHECK(callContractFunction("f2()"), encodeArgs(0x20, 5, "\x01" "abc" "\x02")); ABI_CHECK(callContractFunction("f3()"), encodeArgs(0x20, 5, "\x01" "abc" "\x02")); - ABI_CHECK(callContractFunction("f4()"), encodeArgs( - 0x20, - 2 + 26 + 26 + 2, - "\x07\x01" "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" "\x12\x01" - )); + ABI_CHECK(callContractFunction("f4()"), encodeArgs(0x20, 2 + 26 + 26 + 2, "\x07\x01" "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" "\x12\x01")); ABI_CHECK(callContractFunction("f_literal()"), encodeArgs(0x20, 5, "\x01" "abc" "\x02")); ABI_CHECK(callContractFunction("f_calldata()"), encodeArgs(0x20, 6, "\x01" "\xa5\xbf\xa1\xee" "\x02")); } @@ -12958,10 +7073,7 @@ BOOST_AUTO_TEST_CASE(abi_encodePacked_from_storage) ABI_CHECK(callContractFunction("lf()"), encodeArgs(0x20, 5 * 32 + 2, "\x01" + asString(encodeArgs(payload)) + "\x02")); ABI_CHECK(callContractFunction("ld()"), encodeArgs(0x20, 5 * 32 + 2, "\x01" + asString(encodeArgs(payload)) + "\x02")); ABI_CHECK(callContractFunction("bytes_short()"), encodeArgs(0x20, 6, "\x01" "abcd\x02")); - ABI_CHECK( - callContractFunction("bytes_long()"), - encodeArgs(0x20, 42, "\x01" "0123456789012345678901234567890123456789\x02") - ); + ABI_CHECK(callContractFunction("bytes_long()"), encodeArgs(0x20, 42, "\x01" "0123456789012345678901234567890123456789\x02")); } } @@ -13196,7 +7308,6 @@ BOOST_AUTO_TEST_CASE(event_signature_in_library) BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E((uint8,int16),(uint8,int16))"))); } - BOOST_AUTO_TEST_CASE(abi_encode_with_selector) { char const* sourceCode = R"( @@ -13401,88 +7512,6 @@ BOOST_AUTO_TEST_CASE(abi_encode_empty_string) } } -BOOST_AUTO_TEST_CASE(abi_encode_empty_string_v2) -{ - char const* sourceCode = R"( - // Tests that this will not end up using a "bytes0" type - // (which would assert) - pragma experimental ABIEncoderV2; - contract C { - function f() public pure returns (bytes memory, bytes memory) { - return (abi.encode(""), abi.encodePacked("")); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs( - 0x40, 0xa0, - 0x40, 0x20, 0x00, - 0x00 - )); -} - -BOOST_AUTO_TEST_CASE(abi_encode_rational) -{ - char const* sourceCode = R"( - // Tests that rational numbers (even negative ones) are encoded properly. - contract C { - function f() public pure returns (bytes memory) { - return abi.encode(1, -2); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs( - 0x20, - 0x40, u256(1), u256(-2) - )); -} - -BOOST_AUTO_TEST_CASE(abi_encode_rational_v2) -{ - char const* sourceCode = R"( - // Tests that rational numbers (even negative ones) are encoded properly. - pragma experimental ABIEncoderV2; - contract C { - function f() public pure returns (bytes memory) { - return abi.encode(1, -2); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs( - 0x20, - 0x40, u256(1), u256(-2) - )); -} - -BOOST_AUTO_TEST_CASE(abi_encode_call) -{ - char const* sourceCode = R"T( - contract C { - bool x; - function c(uint a, uint[] memory b) public { - require(a == 5); - require(b.length == 2); - require(b[0] == 6); - require(b[1] == 7); - x = true; - } - function f() public returns (bool) { - uint a = 5; - uint[] memory b = new uint[](2); - b[0] = 6; - b[1] = 7; - (bool success,) = address(this).call(abi.encodeWithSignature("c(uint256,uint256[])", a, b)); - require(success); - return x; - } - } - )T"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(true)); -} - BOOST_AUTO_TEST_CASE(staticcall_for_view_and_pure) { char const* sourceCode = R"( @@ -13756,56 +7785,6 @@ BOOST_AUTO_TEST_CASE(bitwise_shifting_constantinople_combined) ) } -BOOST_AUTO_TEST_CASE(senders_balance) -{ - char const* sourceCode = R"( - contract C { - function f() public view returns (uint) { - return msg.sender.balance; - } - } - contract D { - C c = new C(); - constructor() public payable { } - function f() public view returns (uint) { - return c.f(); - } - } - )"; - compileAndRun(sourceCode, 27, "D"); - BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(27))); -} - -BOOST_AUTO_TEST_CASE(abi_decode_trivial) -{ - char const* sourceCode = R"( - contract C { - function f(bytes memory data) public pure returns (uint) { - return abi.decode(data, (uint)); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f(bytes)", 0x20, 0x20, 33), encodeArgs(u256(33))); -} - -BOOST_AUTO_TEST_CASE(abi_encode_decode_simple) -{ - char const* sourceCode = R"XX( - contract C { - function f() public pure returns (uint, bytes memory) { - bytes memory arg = "abcdefg"; - return abi.decode(abi.encode(uint(33), arg), (uint, bytes)); - } - } - )XX"; - compileAndRun(sourceCode); - ABI_CHECK( - callContractFunction("f()"), - encodeArgs(33, 0x40, 7, "abcdefg") - ); -} - BOOST_AUTO_TEST_CASE(abi_decode_simple) { char const* sourceCode = R"( @@ -13816,34 +7795,7 @@ BOOST_AUTO_TEST_CASE(abi_decode_simple) } )"; compileAndRun(sourceCode); - ABI_CHECK( - callContractFunction("f(bytes)", 0x20, 0x20 * 4, 33, 0x40, 7, "abcdefg"), - encodeArgs(33, 0x40, 7, "abcdefg") - ); -} - -BOOST_AUTO_TEST_CASE(abi_decode_v2) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - struct S { uint a; uint[] b; } - function f() public pure returns (S memory) { - S memory s; - s.a = 8; - s.b = new uint[](3); - s.b[0] = 9; - s.b[1] = 10; - s.b[2] = 11; - return abi.decode(abi.encode(s), (S)); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK( - callContractFunction("f()"), - encodeArgs(0x20, 8, 0x40, 3, 9, 10, 11) - ); + ABI_CHECK(callContractFunction("f(bytes)", 0x20, 0x20 * 4, 33, 0x40, 7, "abcdefg"), encodeArgs(33, 0x40, 7, "abcdefg")); } BOOST_AUTO_TEST_CASE(abi_decode_simple_storage) @@ -13858,36 +7810,7 @@ BOOST_AUTO_TEST_CASE(abi_decode_simple_storage) } )"; compileAndRun(sourceCode); - ABI_CHECK( - callContractFunction("f(bytes)", 0x20, 0x20 * 4, 33, 0x40, 7, "abcdefg"), - encodeArgs(33, 0x40, 7, "abcdefg") - ); -} - -BOOST_AUTO_TEST_CASE(abi_decode_v2_storage) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - bytes data; - struct S { uint a; uint[] b; } - function f() public returns (S memory) { - S memory s; - s.a = 8; - s.b = new uint[](3); - s.b[0] = 9; - s.b[1] = 10; - s.b[2] = 11; - data = abi.encode(s); - return abi.decode(data, (S)); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK( - callContractFunction("f()"), - encodeArgs(0x20, 8, 0x40, 3, 9, 10, 11) - ); + ABI_CHECK(callContractFunction("f(bytes)", 0x20, 0x20 * 4, 33, 0x40, 7, "abcdefg"), encodeArgs(33, 0x40, 7, "abcdefg")); } BOOST_AUTO_TEST_CASE(abi_decode_calldata) @@ -13900,181 +7823,7 @@ BOOST_AUTO_TEST_CASE(abi_decode_calldata) } )"; compileAndRun(sourceCode); - ABI_CHECK( - callContractFunction("f(bytes)", 0x20, 0x20 * 4, 33, 0x40, 7, "abcdefg"), - encodeArgs(33, 0x40, 7, "abcdefg") - ); -} - -BOOST_AUTO_TEST_CASE(abi_decode_v2_calldata) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - struct S { uint a; uint[] b; } - function f(bytes calldata data) external pure returns (S memory) { - return abi.decode(data, (S)); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK( - callContractFunction("f(bytes)", 0x20, 0x20 * 7, 0x20, 33, 0x40, 3, 10, 11, 12), - encodeArgs(0x20, 33, 0x40, 3, 10, 11, 12) - ); -} - -BOOST_AUTO_TEST_CASE(abi_decode_static_array) -{ - char const* sourceCode = R"( - contract C { - function f(bytes calldata data) external pure returns (uint[2][3] memory) { - return abi.decode(data, (uint[2][3])); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK( - callContractFunction("f(bytes)", 0x20, 6 * 0x20, 1, 2, 3, 4, 5, 6), - encodeArgs(1, 2, 3, 4, 5, 6) - ); -} - -BOOST_AUTO_TEST_CASE(abi_decode_static_array_v2) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - function f(bytes calldata data) external pure returns (uint[2][3] memory) { - return abi.decode(data, (uint[2][3])); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK( - callContractFunction("f(bytes)", 0x20, 6 * 0x20, 1, 2, 3, 4, 5, 6), - encodeArgs(1, 2, 3, 4, 5, 6) - ); -} - -BOOST_AUTO_TEST_CASE(abi_decode_dynamic_array) -{ - char const* sourceCode = R"( - contract C { - function f(bytes calldata data) external pure returns (uint[] memory) { - return abi.decode(data, (uint[])); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK( - callContractFunction("f(bytes)", 0x20, 6 * 0x20, 0x20, 4, 3, 4, 5, 6), - encodeArgs(0x20, 4, 3, 4, 5, 6) - ); -} - -BOOST_AUTO_TEST_CASE(write_storage_external) -{ - char const* sourceCode = R"( - contract C { - uint public x; - function f(uint y) public payable { - x = y; - } - function g(uint y) external { - x = y; - } - function h() public { - this.g(12); - } - } - contract D { - C c = new C(); - function f() public payable returns (uint) { - c.g(3); - return c.x(); - } - function g() public returns (uint) { - c.g(8); - return c.x(); - } - function h() public returns (uint) { - c.h(); - return c.x(); - } - } - )"; - compileAndRun(sourceCode, 0, "D"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(3)); - ABI_CHECK(callContractFunction("g()"), encodeArgs(8)); - ABI_CHECK(callContractFunction("h()"), encodeArgs(12)); -} - -BOOST_AUTO_TEST_CASE(test_underscore_in_hex) -{ - char const* sourceCode = R"( - contract test { - function f(bool cond) public pure returns (uint) { - uint32 x = 0x1234_ab; - uint y = 0x1234_abcd_1234; - return cond ? x : y; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f(bool)", true), encodeArgs(u256(0x1234ab))); - ABI_CHECK(callContractFunction("f(bool)", false), encodeArgs(u256(0x1234abcd1234))); -} - -BOOST_AUTO_TEST_CASE(flipping_sign_tests) -{ - char const* sourceCode = R"( - contract test { - function f() public returns (bool){ - int x = -2**255; - assert(-x == x); - return true; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(true)); -} -BOOST_AUTO_TEST_CASE(external_public_override) -{ - char const* sourceCode = R"( - contract A { - function f() external virtual returns (uint) { return 1; } - } - contract B is A { - function f() public override returns (uint) { return 2; } - function g() public returns (uint) { return f(); } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(2)); - ABI_CHECK(callContractFunction("g()"), encodeArgs(2)); - ) -} - -BOOST_AUTO_TEST_CASE(base_access_to_function_type_variables) -{ - char const* sourceCode = R"( - contract C { - function () internal returns (uint) x; - function set() public { - C.x = g; - } - function g() public pure returns (uint) { return 2; } - function h() public returns (uint) { return C.x(); } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("g()"), encodeArgs(2)); - ABI_CHECK(callContractFunction("h()"), encodeArgs()); - ABI_CHECK(callContractFunction("set()"), encodeArgs()); - ABI_CHECK(callContractFunction("h()"), encodeArgs(2)); + ABI_CHECK(callContractFunction("f(bytes)", 0x20, 0x20 * 4, 33, 0x40, 7, "abcdefg"), encodeArgs(33, 0x40, 7, "abcdefg")); } BOOST_AUTO_TEST_CASE(code_access) @@ -14118,91 +7867,6 @@ BOOST_AUTO_TEST_CASE(code_access) ABI_CHECK(codeRuntime1, codeRuntime2); } -BOOST_AUTO_TEST_CASE(code_access_padding) -{ - char const* sourceCode = R"( - contract C { - function diff() public pure returns (uint remainder) { - bytes memory a = type(D).creationCode; - bytes memory b = type(D).runtimeCode; - assembly { remainder := mod(sub(b, a), 0x20) } - } - } - contract D { - function f() public pure returns (uint) { return 7; } - } - )"; - compileAndRun(sourceCode, 0, "C"); - // This checks that the allocation function pads to multiples of 32 bytes - ABI_CHECK(callContractFunction("diff()"), encodeArgs(0)); -} - -BOOST_AUTO_TEST_CASE(code_access_create) -{ - char const* sourceCode = R"( - contract C { - function test() public returns (uint) { - bytes memory c = type(D).creationCode; - D d; - assembly { - d := create(0, add(c, 0x20), mload(c)) - } - return d.f(); - } - } - contract D { - uint x; - constructor() public { x = 7; } - function f() public view returns (uint) { return x; } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("test()"), encodeArgs(7)); -} - -BOOST_AUTO_TEST_CASE(code_access_content) -{ - char const* sourceCode = R"( - contract C { - function testRuntime() public returns (bool) { - D d = new D(); - bytes32 runtimeHash = keccak256(type(D).runtimeCode); - bytes32 otherHash; - uint size; - assembly { - size := extcodesize(d) - extcodecopy(d, mload(0x40), 0, size) - otherHash := keccak256(mload(0x40), size) - } - require(size == type(D).runtimeCode.length); - require(runtimeHash == otherHash); - return true; - } - function testCreation() public returns (bool) { - D d = new D(); - bytes32 creationHash = keccak256(type(D).creationCode); - require(creationHash == d.x()); - return true; - } - } - contract D { - bytes32 public x; - constructor() public { - bytes32 codeHash; - assembly { - let size := codesize() - codecopy(mload(0x40), 0, size) - codeHash := keccak256(mload(0x40), size) - } - x = codeHash; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("testRuntime()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("testCreation()"), encodeArgs(true)); -} - BOOST_AUTO_TEST_CASE(contract_name) { char const* sourceCode = R"( @@ -14295,22 +7959,6 @@ BOOST_AUTO_TEST_CASE(uninitialized_internal_storage_function) BOOST_CHECK(result != encodeArgs(0)); } -BOOST_AUTO_TEST_CASE(uninitialized_internal_storage_function_call) -{ - char const* sourceCode = R"( - contract Test { - function() internal x; - function f() public returns (uint r) { - x(); - return 2; - } - } - )"; - compileAndRun(sourceCode, 0, "Test"); - - ABI_CHECK(callContractFunction("f()"), bytes{}); -} - BOOST_AUTO_TEST_CASE(dirty_scratch_space_prior_to_constant_optimiser) { char const* sourceCode = R"( diff --git a/test/libsolidity/SolidityExecutionFramework.cpp b/test/libsolidity/SolidityExecutionFramework.cpp index dcfb3e6bf..0afe95c6d 100644 --- a/test/libsolidity/SolidityExecutionFramework.cpp +++ b/test/libsolidity/SolidityExecutionFramework.cpp @@ -21,6 +21,7 @@ */ #include +#include #include #include @@ -60,6 +61,7 @@ bytes SolidityExecutionFramework::compileContract( formatter.printErrorInformation(*error); BOOST_ERROR("Compiling contract failed"); } + std::string contractName(_contractName.empty() ? m_compiler.lastContractName() : _contractName); evmasm::LinkerObject obj; if (m_compileViaYul) { @@ -70,9 +72,7 @@ bytes SolidityExecutionFramework::compileContract( // get code that does not exhaust the stack. OptimiserSettings::full() ); - if (!asmStack.parseAndAnalyze("", m_compiler.yulIROptimized( - _contractName.empty() ? m_compiler.lastContractName() : _contractName - ))) + if (!asmStack.parseAndAnalyze("", m_compiler.yulIROptimized(contractName))) { langutil::SourceReferenceFormatter formatter(std::cerr); @@ -84,7 +84,9 @@ bytes SolidityExecutionFramework::compileContract( obj = std::move(*asmStack.assemble(yul::AssemblyStack::Machine::EVM).bytecode); } else - obj = m_compiler.object(_contractName.empty() ? m_compiler.lastContractName() : _contractName); + obj = m_compiler.object(contractName); BOOST_REQUIRE(obj.linkReferences.empty()); + if (m_showMetadata) + cout << "metadata: " << m_compiler.metadata(contractName) << endl; return obj.bytecode; } diff --git a/test/libsolidity/SolidityExecutionFramework.h b/test/libsolidity/SolidityExecutionFramework.h index dfcf4a46b..aaa17525f 100644 --- a/test/libsolidity/SolidityExecutionFramework.h +++ b/test/libsolidity/SolidityExecutionFramework.h @@ -41,9 +41,9 @@ class SolidityExecutionFramework: public solidity::test::ExecutionFramework { public: - SolidityExecutionFramework() {} + SolidityExecutionFramework(): m_showMetadata(solidity::test::CommonOptions::get().showMetadata) {} explicit SolidityExecutionFramework(langutil::EVMVersion _evmVersion): - ExecutionFramework(_evmVersion) + ExecutionFramework(_evmVersion), m_showMetadata(solidity::test::CommonOptions::get().showMetadata) {} virtual bytes const& compileAndRunWithoutCheck( @@ -68,6 +68,7 @@ public: protected: solidity::frontend::CompilerStack m_compiler; bool m_compileViaYul = false; + bool m_showMetadata = false; RevertStrings m_revertStrings = RevertStrings::Default; }; diff --git a/test/libsolidity/SyntaxTest.cpp b/test/libsolidity/SyntaxTest.cpp index 1938cfe86..3ec506998 100644 --- a/test/libsolidity/SyntaxTest.cpp +++ b/test/libsolidity/SyntaxTest.cpp @@ -37,20 +37,7 @@ namespace fs = boost::filesystem; SyntaxTest::SyntaxTest(string const& _filename, langutil::EVMVersion _evmVersion, bool _parserErrorRecovery): CommonSyntaxTest(_filename, _evmVersion) { - if (m_settings.count("optimize-yul")) - { - if (m_settings["optimize-yul"] == "true") - { - m_validatedSettings["optimize-yul"] = "true"; - m_settings.erase("optimize-yul"); - } - else if (m_settings["optimize-yul"] == "false") - { - m_validatedSettings["optimize-yul"] = "false"; - m_settings.erase("optimize-yul"); - m_optimiseYul = false; - } - } + m_optimiseYul = m_reader.boolSetting("optimize-yul", true); m_parserErrorRecovery = _parserErrorRecovery; } @@ -60,7 +47,7 @@ TestCase::TestResult SyntaxTest::run(ostream& _stream, string const& _linePrefix parseAndAnalyze(); filterObtainedErrors(); - return printExpectationAndError(_stream, _linePrefix, _formatted) ? TestResult::Success : TestResult::Failure; + return conclude(_stream, _linePrefix, _formatted); } void SyntaxTest::setupCompiler() diff --git a/test/libsolidity/gasTests/abiv2.sol b/test/libsolidity/gasTests/abiv2.sol index f0892b83b..1fd96ff76 100644 --- a/test/libsolidity/gasTests/abiv2.sol +++ b/test/libsolidity/gasTests/abiv2.sol @@ -14,9 +14,9 @@ contract C { } // ---- // creation: -// codeDepositCost: 1120000 -// executionCost: 1160 -// totalCost: 1121160 +// codeDepositCost: 1094400 +// executionCost: 1134 +// totalCost: 1095534 // external: // a(): 1130 // b(uint256): infinite diff --git a/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_dynamic_array.sol b/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_dynamic_array.sol new file mode 100644 index 000000000..180d89ec1 --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_dynamic_array.sol @@ -0,0 +1,8 @@ +contract C { + function f(bytes calldata data) external pure returns (uint256[] memory) { + return abi.decode(data, (uint256[])); + } +} + +// ---- +// f(bytes): 0x20, 0xc0, 0x20, 0x4, 0x3, 0x4, 0x5, 0x6 -> 0x20, 0x4, 0x3, 0x4, 0x5, 0x6 diff --git a/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_static_array.sol b/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_static_array.sol new file mode 100644 index 000000000..270a5abc0 --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_static_array.sol @@ -0,0 +1,12 @@ +contract C { + function f(bytes calldata data) + external + pure + returns (uint256[2][3] memory) + { + return abi.decode(data, (uint256[2][3])); + } +} + +// ---- +// f(bytes): 0x20, 0xc0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6 -> 1, 2, 3, 4, 5, 6 diff --git a/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_static_array_v2.sol b/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_static_array_v2.sol new file mode 100644 index 000000000..46450f704 --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_static_array_v2.sol @@ -0,0 +1,15 @@ +pragma experimental ABIEncoderV2; + + +contract C { + function f(bytes calldata data) + external + pure + returns (uint256[2][3] memory) + { + return abi.decode(data, (uint256[2][3])); + } +} + +// ---- +// f(bytes): 0x20, 0xc0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6 -> 1, 2, 3, 4, 5, 6 diff --git a/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_trivial.sol b/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_trivial.sol new file mode 100644 index 000000000..7b873951f --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_trivial.sol @@ -0,0 +1,8 @@ +contract C { + function f(bytes memory data) public pure returns (uint256) { + return abi.decode(data, (uint256)); + } +} + +// ---- +// f(bytes): 0x20, 0x20, 0x21 -> 33 diff --git a/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_v2.sol b/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_v2.sol new file mode 100644 index 000000000..1dbf320bd --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_v2.sol @@ -0,0 +1,22 @@ +pragma experimental ABIEncoderV2; + + +contract C { + struct S { + uint256 a; + uint256[] b; + } + + function f() public pure returns (S memory) { + S memory s; + s.a = 8; + s.b = new uint256[](3); + s.b[0] = 9; + s.b[1] = 10; + s.b[2] = 11; + return abi.decode(abi.encode(s), (S)); + } +} + +// ---- +// f() -> 0x20, 0x8, 0x40, 0x3, 0x9, 0xa, 0xb diff --git a/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_v2_calldata.sol b/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_v2_calldata.sol new file mode 100644 index 000000000..a5e7a9af8 --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_v2_calldata.sol @@ -0,0 +1,16 @@ +pragma experimental ABIEncoderV2; + + +contract C { + struct S { + uint256 a; + uint256[] b; + } + + function f(bytes calldata data) external pure returns (S memory) { + return abi.decode(data, (S)); + } +} + +// ---- +// f(bytes): 0x20, 0xe0, 0x20, 0x21, 0x40, 0x3, 0xa, 0xb, 0xc -> 0x20, 0x21, 0x40, 0x3, 0xa, 0xb, 0xc diff --git a/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_v2_storage.sol b/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_v2_storage.sol new file mode 100644 index 000000000..95b667e47 --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_v2_storage.sol @@ -0,0 +1,24 @@ +pragma experimental ABIEncoderV2; + + +contract C { + bytes data; + struct S { + uint256 a; + uint256[] b; + } + + function f() public returns (S memory) { + S memory s; + s.a = 8; + s.b = new uint256[](3); + s.b[0] = 9; + s.b[1] = 10; + s.b[2] = 11; + data = abi.encode(s); + return abi.decode(data, (S)); + } +} + +// ---- +// f() -> 0x20, 0x8, 0x40, 0x3, 0x9, 0xa, 0xb diff --git a/test/libsolidity/semanticTests/abiEncoderV1/abi_encode.sol b/test/libsolidity/semanticTests/abiEncoderV1/abi_encode.sol new file mode 100644 index 000000000..ac17cf80e --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV1/abi_encode.sol @@ -0,0 +1,36 @@ +contract C { + function f0() public returns (bytes memory) { + return abi.encode(); + } + + function f1() public returns (bytes memory) { + return abi.encode(1, 2); + } + + function f2() public returns (bytes memory) { + string memory x = "abc"; + return abi.encode(1, x, 2); + } + + function f3() public returns (bytes memory r) { + // test that memory is properly allocated + string memory x = "abc"; + r = abi.encode(1, x, 2); + bytes memory y = "def"; + require(y[0] == "d"); + y[0] = "e"; + require(y[0] == "e"); + } + + function f4() public returns (bytes memory) { + bytes4 x = "abcd"; + return abi.encode(bytes2(x)); + } +} + +// ---- +// f0() -> 0x20, 0x0 +// f1() -> 0x20, 0x40, 0x1, 0x2 +// f2() -> 0x20, 0xa0, 0x1, 0x60, 0x2, 0x3, "abc" +// f3() -> 0x20, 0xa0, 0x1, 0x60, 0x2, 0x3, "abc" +// f4() -> 0x20, 0x20, "ab" diff --git a/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_call.sol b/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_call.sol new file mode 100644 index 000000000..d73db5da6 --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_call.sol @@ -0,0 +1,26 @@ +contract C { + bool x; + + function c(uint256 a, uint256[] memory b) public { + require(a == 5); + require(b.length == 2); + require(b[0] == 6); + require(b[1] == 7); + x = true; + } + + function f() public returns (bool) { + uint256 a = 5; + uint256[] memory b = new uint256[](2); + b[0] = 6; + b[1] = 7; + (bool success, ) = address(this).call( + abi.encodeWithSignature("c(uint256,uint256[])", a, b) + ); + require(success); + return x; + } +} + +// ---- +// f() -> true diff --git a/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_decode_simple.sol b/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_decode_simple.sol new file mode 100644 index 000000000..1fbcfa53d --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_decode_simple.sol @@ -0,0 +1,9 @@ +contract C { + function f() public pure returns (uint256, bytes memory) { + bytes memory arg = "abcdefg"; + return abi.decode(abi.encode(uint256(33), arg), (uint256, bytes)); + } +} + +// ---- +// f() -> 0x21, 0x40, 0x7, "abcdefg" diff --git a/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_rational.sol b/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_rational.sol new file mode 100644 index 000000000..704fd54dc --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_rational.sol @@ -0,0 +1,9 @@ +// Tests that rational numbers (even negative ones) are encoded properly. +contract C { + function f() public pure returns (bytes memory) { + return abi.encode(1, -2); + } +} + +// ---- +// f() -> 0x20, 0x40, 0x1, -2 diff --git a/test/libsolidity/semanticTests/abiDecodeV1/decode_slice.sol b/test/libsolidity/semanticTests/abiEncoderV1/decode_slice.sol similarity index 100% rename from test/libsolidity/semanticTests/abiDecodeV1/decode_slice.sol rename to test/libsolidity/semanticTests/abiEncoderV1/decode_slice.sol diff --git a/test/libsolidity/semanticTests/abiDecodeV1/dynamic_memory_copy.sol b/test/libsolidity/semanticTests/abiEncoderV1/dynamic_memory_copy.sol similarity index 100% rename from test/libsolidity/semanticTests/abiDecodeV1/dynamic_memory_copy.sol rename to test/libsolidity/semanticTests/abiEncoderV1/dynamic_memory_copy.sol diff --git a/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_empty_string_v2.sol b/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_empty_string_v2.sol new file mode 100644 index 000000000..373334ee7 --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_empty_string_v2.sol @@ -0,0 +1,13 @@ +// Tests that this will not end up using a "bytes0" type +// (which would assert) +pragma experimental ABIEncoderV2; + + +contract C { + function f() public pure returns (bytes memory, bytes memory) { + return (abi.encode(""), abi.encodePacked("")); + } +} + +// ---- +// f() -> 0x40, 0xa0, 0x40, 0x20, 0x0, 0x0 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_rational_v2.sol b/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_rational_v2.sol new file mode 100644 index 000000000..55047880a --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_rational_v2.sol @@ -0,0 +1,12 @@ +// Tests that rational numbers (even negative ones) are encoded properly. +pragma experimental ABIEncoderV2; + + +contract C { + function f() public pure returns (bytes memory) { + return abi.encode(1, -2); + } +} + +// ---- +// f() -> 0x20, 0x40, 0x1, -2 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_v2.sol b/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_v2.sol new file mode 100644 index 000000000..f6510b53d --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_v2.sol @@ -0,0 +1,53 @@ +pragma experimental ABIEncoderV2; + + +contract C { + struct S { + uint256 a; + uint256[] b; + } + + function f0() public pure returns (bytes memory) { + return abi.encode(); + } + + function f1() public pure returns (bytes memory) { + return abi.encode(1, 2); + } + + function f2() public pure returns (bytes memory) { + string memory x = "abc"; + return abi.encode(1, x, 2); + } + + function f3() public pure returns (bytes memory r) { + // test that memory is properly allocated + string memory x = "abc"; + r = abi.encode(1, x, 2); + bytes memory y = "def"; + require(y[0] == "d"); + y[0] = "e"; + require(y[0] == "e"); + } + + S s; + + function f4() public returns (bytes memory r) { + string memory x = "abc"; + s.a = 7; + s.b.push(2); + s.b.push(3); + r = abi.encode(1, x, s, 2); + bytes memory y = "def"; + require(y[0] == "d"); + y[0] = "e"; + require(y[0] == "e"); + } +} + +// ---- +// f0() -> 0x20, 0x0 +// f1() -> 0x20, 0x40, 0x1, 0x2 +// f2() -> 0x20, 0xa0, 0x1, 0x60, 0x2, 0x3, "abc" +// f3() -> 0x20, 0xa0, 0x1, 0x60, 0x2, 0x3, "abc" +// f4() -> 0x20, 0x160, 0x1, 0x80, 0xc0, 0x2, 0x3, "abc", 0x7, 0x40, 0x2, 0x2, 0x3 diff --git a/test/libsolidity/semanticTests/accessor/accessor_for_const_state_variable.sol b/test/libsolidity/semanticTests/accessor/accessor_for_const_state_variable.sol new file mode 100644 index 000000000..a9402aa86 --- /dev/null +++ b/test/libsolidity/semanticTests/accessor/accessor_for_const_state_variable.sol @@ -0,0 +1,6 @@ +contract Lotto { + uint256 public constant ticketPrice = 555; +} + +// ---- +// ticketPrice() -> 555 diff --git a/test/libsolidity/semanticTests/accessor/accessor_for_state_variable.sol b/test/libsolidity/semanticTests/accessor/accessor_for_state_variable.sol new file mode 100644 index 000000000..e2b59b530 --- /dev/null +++ b/test/libsolidity/semanticTests/accessor/accessor_for_state_variable.sol @@ -0,0 +1,8 @@ +contract Lotto { + uint256 public ticketPrice = 500; +} + +// ==== +// compileViaYul: also +// ---- +// ticketPrice() -> 500 diff --git a/test/libsolidity/semanticTests/arithmetics/addmod_mulmod.sol b/test/libsolidity/semanticTests/arithmetics/addmod_mulmod.sol new file mode 100644 index 000000000..d1e9f5c20 --- /dev/null +++ b/test/libsolidity/semanticTests/arithmetics/addmod_mulmod.sol @@ -0,0 +1,12 @@ +contract C { + function test() public returns (uint256) { + // Note that this only works because computation on literals is done using + // unbounded integers. + if ((2**255 + 2**255) % 7 != addmod(2**255, 2**255, 7)) return 1; + if ((2**255 + 2**255) % 7 != addmod(2**255, 2**255, 7)) return 2; + return 0; + } +} + +// ---- +// test() -> 0 diff --git a/test/libsolidity/semanticTests/arithmetics/addmod_mulmod_zero.sol b/test/libsolidity/semanticTests/arithmetics/addmod_mulmod_zero.sol new file mode 100644 index 000000000..7585980e1 --- /dev/null +++ b/test/libsolidity/semanticTests/arithmetics/addmod_mulmod_zero.sol @@ -0,0 +1,24 @@ +contract C { + function f(uint256 d) public pure returns (uint256) { + addmod(1, 2, d); + return 2; + } + + function g(uint256 d) public pure returns (uint256) { + mulmod(1, 2, d); + return 2; + } + + function h() public pure returns (uint256) { + mulmod(0, 1, 2); + mulmod(1, 0, 2); + addmod(0, 1, 2); + addmod(1, 0, 2); + return 2; + } +} + +// ---- +// f(uint256): 0 -> FAILURE +// g(uint256): 0 -> FAILURE +// h() -> 2 diff --git a/test/libsolidity/semanticTests/arithmetics/divisiod_by_zero.sol b/test/libsolidity/semanticTests/arithmetics/divisiod_by_zero.sol new file mode 100644 index 000000000..127320fc6 --- /dev/null +++ b/test/libsolidity/semanticTests/arithmetics/divisiod_by_zero.sol @@ -0,0 +1,15 @@ +contract C { + function div(uint256 a, uint256 b) public returns (uint256) { + return a / b; + } + + function mod(uint256 a, uint256 b) public returns (uint256) { + return a % b; + } +} + +// ---- +// div(uint256,uint256): 7, 2 -> 3 +// div(uint256,uint256): 7, 0 -> FAILURE # throws # +// mod(uint256,uint256): 7, 2 -> 1 +// mod(uint256,uint256): 7, 0 -> FAILURE # throws # diff --git a/test/libsolidity/semanticTests/array/array_copy_different_packing.sol b/test/libsolidity/semanticTests/array/array_copy_different_packing.sol new file mode 100644 index 000000000..f0afcffc9 --- /dev/null +++ b/test/libsolidity/semanticTests/array/array_copy_different_packing.sol @@ -0,0 +1,21 @@ +contract c { + bytes8[] data1; // 4 per slot + bytes10[] data2; // 3 per slot + + function test() + public + returns (bytes10 a, bytes10 b, bytes10 c, bytes10 d, bytes10 e) + { + data1 = new bytes8[](9); + for (uint256 i = 0; i < data1.length; ++i) data1[i] = bytes8(uint64(i)); + data2 = data1; + a = data2[1]; + b = data2[2]; + c = data2[3]; + d = data2[4]; + e = data2[5]; + } +} + +// ---- +// test() -> 0x01000000000000000000000000000000000000000000000000, 0x02000000000000000000000000000000000000000000000000, 0x03000000000000000000000000000000000000000000000000, 0x04000000000000000000000000000000000000000000000000, 0x05000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/semanticTests/array/array_copy_nested_array.sol b/test/libsolidity/semanticTests/array/array_copy_nested_array.sol new file mode 100644 index 000000000..9330d3162 --- /dev/null +++ b/test/libsolidity/semanticTests/array/array_copy_nested_array.sol @@ -0,0 +1,15 @@ +contract c { + uint256[4][] a; + uint256[10][] b; + uint256[][] c; + + function test(uint256[2][] calldata d) external returns (uint256) { + a = d; + b = a; + c = b; + return c[1][1] | c[1][2] | c[1][3] | c[1][4]; + } +} + +// ---- +// test(uint256[2][]): 32, 3, 7, 8, 9, 10, 11, 12 -> 10 diff --git a/test/libsolidity/semanticTests/array/array_copy_storage_abi_signed.sol b/test/libsolidity/semanticTests/array/array_copy_storage_abi_signed.sol new file mode 100644 index 000000000..0e225f1e5 --- /dev/null +++ b/test/libsolidity/semanticTests/array/array_copy_storage_abi_signed.sol @@ -0,0 +1,20 @@ +// NOTE: This does not really test copying from storage to ABI directly, +// because it will always copy to memory first. +contract c { + int16[] x; + + function test() public returns (int16[] memory) { + x.push(int16(-1)); + x.push(int16(-1)); + x.push(int16(8)); + x.push(int16(-16)); + x.push(int16(-2)); + x.push(int16(6)); + x.push(int16(8)); + x.push(int16(-1)); + return x; + } +} + +// ---- +// test() -> 0x20, 0x8, -1, -1, 8, -16, -2, 6, 8, -1 diff --git a/test/libsolidity/semanticTests/array/array_copy_storage_storage_static_dynamic.sol b/test/libsolidity/semanticTests/array/array_copy_storage_storage_static_dynamic.sol new file mode 100644 index 000000000..4432776fb --- /dev/null +++ b/test/libsolidity/semanticTests/array/array_copy_storage_storage_static_dynamic.sol @@ -0,0 +1,14 @@ +contract c { + uint256[9] data1; + uint256[] data2; + + function test() public returns (uint256 x, uint256 y) { + data1[8] = 4; + data2 = data1; + x = data2.length; + y = data2[8]; + } +} + +// ---- +// test() -> 9, 4 diff --git a/test/libsolidity/semanticTests/array/array_copy_storage_storage_static_static.sol b/test/libsolidity/semanticTests/array/array_copy_storage_storage_static_static.sol new file mode 100644 index 000000000..71601d477 --- /dev/null +++ b/test/libsolidity/semanticTests/array/array_copy_storage_storage_static_static.sol @@ -0,0 +1,17 @@ +contract c { + uint256[40] data1; + uint256[20] data2; + + function test() public returns (uint256 x, uint256 y) { + data1[30] = 4; + data1[2] = 7; + data1[3] = 9; + data2[3] = 8; + data1 = data2; + x = data1[3]; + y = data1[30]; // should be cleared + } +} + +// ---- +// test() -> 8, 0 diff --git a/test/libsolidity/semanticTests/array/array_copy_target_leftover2.sol b/test/libsolidity/semanticTests/array/array_copy_target_leftover2.sol new file mode 100644 index 000000000..1bbd95f6f --- /dev/null +++ b/test/libsolidity/semanticTests/array/array_copy_target_leftover2.sol @@ -0,0 +1,22 @@ +// since the copy always copies whole slots, we have to make sure that the source size maxes +// out a whole slot and at the same time there are still elements left in the target at that point +contract c { + bytes8[4] data1; // fits into one slot + bytes10[6] data2; // 4 elements need two slots + + function test() public returns (bytes10 r1, bytes10 r2, bytes10 r3) { + data1[0] = bytes8(uint64(1)); + data1[1] = bytes8(uint64(2)); + data1[2] = bytes8(uint64(3)); + data1[3] = bytes8(uint64(4)); + for (uint256 i = 0; i < data2.length; ++i) + data2[i] = bytes10(uint80(0xffff00 | (1 + i))); + data2 = data1; + r1 = data2[3]; + r2 = data2[4]; + r3 = data2[5]; + } +} + +// ---- +// test() -> 0x04000000000000000000000000000000000000000000000000, 0x0, 0x0 diff --git a/test/libsolidity/semanticTests/array/array_copy_target_simple.sol b/test/libsolidity/semanticTests/array/array_copy_target_simple.sol new file mode 100644 index 000000000..ab82589c2 --- /dev/null +++ b/test/libsolidity/semanticTests/array/array_copy_target_simple.sol @@ -0,0 +1,21 @@ +contract c { + bytes8[9] data1; // 4 per slot + bytes17[10] data2; // 1 per slot, no offset counter + + function test() + public + returns (bytes17 a, bytes17 b, bytes17 c, bytes17 d, bytes17 e) + { + for (uint256 i = 0; i < data1.length; ++i) data1[i] = bytes8(uint64(i)); + data2[8] = data2[9] = bytes8(uint64(2)); + data2 = data1; + a = data2[1]; + b = data2[2]; + c = data2[3]; + d = data2[4]; + e = data2[9]; + } +} + +// ---- +// test() -> 0x01000000000000000000000000000000000000000000000000, 0x02000000000000000000000000000000000000000000000000, 0x03000000000000000000000000000000000000000000000000, 0x04000000000000000000000000000000000000000000000000, 0x0 diff --git a/test/libsolidity/semanticTests/array/array_pop.sol b/test/libsolidity/semanticTests/array/array_pop.sol new file mode 100644 index 000000000..5667b61d4 --- /dev/null +++ b/test/libsolidity/semanticTests/array/array_pop.sol @@ -0,0 +1,16 @@ +contract c { + uint256[] data; + + function test() public returns (uint256 x, uint256 l) { + data.push(7); + data.push(3); + x = data.length; + data.pop(); + x = data.length; + data.pop(); + l = data.length; + } +} + +// ---- +// test() -> 1, 0 diff --git a/test/libsolidity/semanticTests/array/array_pop_empty_exception.sol b/test/libsolidity/semanticTests/array/array_pop_empty_exception.sol new file mode 100644 index 000000000..8fc018d72 --- /dev/null +++ b/test/libsolidity/semanticTests/array/array_pop_empty_exception.sol @@ -0,0 +1,11 @@ +contract c { + uint256[] data; + + function test() public returns (bool) { + data.pop(); + return true; + } +} + +// ---- +// test() -> FAILURE diff --git a/test/libsolidity/semanticTests/array/array_pop_isolated.sol b/test/libsolidity/semanticTests/array/array_pop_isolated.sol new file mode 100644 index 000000000..2e6eac83e --- /dev/null +++ b/test/libsolidity/semanticTests/array/array_pop_isolated.sol @@ -0,0 +1,13 @@ +// This tests that the compiler knows the correct size of the function on the stack. +contract c { + uint256[] data; + + function test() public returns (uint256 x) { + x = 2; + data.pop; + x = 3; + } +} + +// ---- +// test() -> 3 diff --git a/test/libsolidity/semanticTests/array/array_push.sol b/test/libsolidity/semanticTests/array/array_push.sol new file mode 100644 index 000000000..bd8200a37 --- /dev/null +++ b/test/libsolidity/semanticTests/array/array_push.sol @@ -0,0 +1,19 @@ +contract c { + uint256[] data; + + function test() + public + returns (uint256 x, uint256 y, uint256 z, uint256 l) + { + data.push(5); + x = data[0]; + data.push(4); + y = data[1]; + data.push(3); + l = data.length; + z = data[2]; + } +} + +// ---- +// test() -> 5, 4, 3, 3 diff --git a/test/libsolidity/semanticTests/array/array_push_packed_array.sol b/test/libsolidity/semanticTests/array/array_push_packed_array.sol new file mode 100644 index 000000000..dd5e2e855 --- /dev/null +++ b/test/libsolidity/semanticTests/array/array_push_packed_array.sol @@ -0,0 +1,16 @@ +contract c { + uint80[] x; + + function test() public returns (uint80, uint80, uint80, uint80) { + x.push(1); + x.push(2); + x.push(3); + x.push(4); + x.push(5); + x.pop(); + return (x[0], x[1], x[2], x[3]); + } +} + +// ---- +// test() -> 1, 2, 3, 4 diff --git a/test/libsolidity/semanticTests/array/array_push_struct.sol b/test/libsolidity/semanticTests/array/array_push_struct.sol new file mode 100644 index 000000000..e407fc025 --- /dev/null +++ b/test/libsolidity/semanticTests/array/array_push_struct.sol @@ -0,0 +1,23 @@ +contract c { + struct S { + uint16 a; + uint16 b; + uint16[3] c; + uint16[] d; + } + S[] data; + + function test() public returns (uint16, uint16, uint16, uint16) { + S memory s; + s.a = 2; + s.b = 3; + s.c[2] = 4; + s.d = new uint16[](4); + s.d[2] = 5; + data.push(s); + return (data[0].a, data[0].b, data[0].c[2], data[0].d[2]); + } +} + +// ---- +// test() -> 2, 3, 4, 5 diff --git a/test/libsolidity/semanticTests/array/byte_array_pop.sol b/test/libsolidity/semanticTests/array/byte_array_pop.sol new file mode 100644 index 000000000..5ed849702 --- /dev/null +++ b/test/libsolidity/semanticTests/array/byte_array_pop.sol @@ -0,0 +1,17 @@ +contract c { + bytes data; + + function test() public returns (uint256 x, uint256 y, uint256 l) { + data.push(0x07); + data.push(0x03); + x = data.length; + data.pop(); + data.pop(); + data.push(0x02); + y = data.length; + l = data.length; + } +} + +// ---- +// test() -> 2, 1, 1 diff --git a/test/libsolidity/semanticTests/array/byte_array_pop_copy_long.sol b/test/libsolidity/semanticTests/array/byte_array_pop_copy_long.sol new file mode 100644 index 000000000..2589f1f55 --- /dev/null +++ b/test/libsolidity/semanticTests/array/byte_array_pop_copy_long.sol @@ -0,0 +1,12 @@ +contract c { + bytes data; + + function test() public returns (bytes memory) { + for (uint256 i = 0; i < 33; i++) data.push(0x03); + for (uint256 j = 0; j < 4; j++) data.pop(); + return data; + } +} + +// ---- +// test() -> 0x20, 29, 0x0303030303030303030303030303030303030303030303030303030303000000 diff --git a/test/libsolidity/semanticTests/array/byte_array_pop_empty_exception.sol b/test/libsolidity/semanticTests/array/byte_array_pop_empty_exception.sol new file mode 100644 index 000000000..30ffa3a4c --- /dev/null +++ b/test/libsolidity/semanticTests/array/byte_array_pop_empty_exception.sol @@ -0,0 +1,14 @@ +contract c { + uint256 a; + uint256 b; + uint256 c; + bytes data; + + function test() public returns (bool) { + data.pop(); + return true; + } +} + +// ---- +// test() -> FAILURE diff --git a/test/libsolidity/semanticTests/array/byte_array_pop_isolated.sol b/test/libsolidity/semanticTests/array/byte_array_pop_isolated.sol new file mode 100644 index 000000000..a9e3fd383 --- /dev/null +++ b/test/libsolidity/semanticTests/array/byte_array_pop_isolated.sol @@ -0,0 +1,13 @@ +// This tests that the compiler knows the correct size of the function on the stack. +contract c { + bytes data; + + function test() public returns (uint256 x) { + x = 2; + data.pop; + x = 3; + } +} + +// ---- +// test() -> 3 diff --git a/test/libsolidity/semanticTests/array/byte_array_pop_masking_long.sol b/test/libsolidity/semanticTests/array/byte_array_pop_masking_long.sol new file mode 100644 index 000000000..1f6d500bd --- /dev/null +++ b/test/libsolidity/semanticTests/array/byte_array_pop_masking_long.sol @@ -0,0 +1,12 @@ +contract c { + bytes data; + + function test() public returns (bytes memory) { + for (uint256 i = 0; i < 34; i++) data.push(0x03); + data.pop(); + return data; + } +} + +// ---- +// test() -> 0x20, 33, 0x303030303030303030303030303030303030303030303030303030303030303, 0x0300000000000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/semanticTests/array/byte_array_push.sol b/test/libsolidity/semanticTests/array/byte_array_push.sol new file mode 100644 index 000000000..67ed87b69 --- /dev/null +++ b/test/libsolidity/semanticTests/array/byte_array_push.sol @@ -0,0 +1,18 @@ +contract c { + bytes data; + + function test() public returns (bool x) { + data.push(0x05); + if (data.length != 1) return true; + if (data[0] != 0x05) return true; + data.push(0x04); + if (data[1] != 0x04) return true; + data.push(0x03); + uint256 l = data.length; + if (data[2] != 0x03) return true; + if (l != 0x03) return true; + } +} + +// ---- +// test() -> false diff --git a/test/libsolidity/semanticTests/array/byte_array_push_transition.sol b/test/libsolidity/semanticTests/array/byte_array_push_transition.sol new file mode 100644 index 000000000..ceecf6726 --- /dev/null +++ b/test/libsolidity/semanticTests/array/byte_array_push_transition.sol @@ -0,0 +1,18 @@ +// Tests transition between short and long encoding +contract c { + bytes data; + + function test() public returns (uint256) { + for (uint8 i = 1; i < 40; i++) { + data.push(bytes1(i)); + if (data.length != i) return 0x1000 + i; + if (data[data.length - 1] != bytes1(i)) return i; + } + for (uint8 i = 1; i < 40; i++) + if (data[i - 1] != bytes1(i)) return 0x1000000 + i; + return 0; + } +} + +// ---- +// test() -> 0 diff --git a/test/libsolidity/semanticTests/array/bytes_delete_element.sol b/test/libsolidity/semanticTests/array/bytes_delete_element.sol new file mode 100644 index 000000000..e3a8ec19d --- /dev/null +++ b/test/libsolidity/semanticTests/array/bytes_delete_element.sol @@ -0,0 +1,19 @@ +contract c { + bytes data; + + function test1() external returns (bool) { + data = new bytes(100); + for (uint256 i = 0; i < data.length; i++) data[i] = bytes1(uint8(i)); + delete data[94]; + delete data[96]; + delete data[98]; + return + data[94] == 0 && + uint8(data[95]) == 95 && + data[96] == 0 && + uint8(data[97]) == 97; + } +} + +// ---- +// test1() -> true diff --git a/test/libsolidity/semanticTests/array/bytes_length_member.sol b/test/libsolidity/semanticTests/array/bytes_length_member.sol new file mode 100644 index 000000000..8c4872017 --- /dev/null +++ b/test/libsolidity/semanticTests/array/bytes_length_member.sol @@ -0,0 +1,17 @@ +contract c { + function set() public returns (bool) { + data = msg.data; + return true; + } + + function getLength() public returns (uint256) { + return data.length; + } + + bytes data; +} + +// ---- +// getLength() -> 0 +// set(): 1, 2 -> true +// getLength() -> 68 diff --git a/test/libsolidity/semanticTests/array/calldata_array.sol b/test/libsolidity/semanticTests/array/calldata_array.sol new file mode 100644 index 000000000..c9c6dbda0 --- /dev/null +++ b/test/libsolidity/semanticTests/array/calldata_array.sol @@ -0,0 +1,16 @@ +pragma experimental ABIEncoderV2; + + +contract C { + function f(uint256[2] calldata s) + external + pure + returns (uint256 a, uint256 b) + { + a = s[0]; + b = s[1]; + } +} + +// ---- +// f(uint256[2]): 42, 23 -> 42, 23 diff --git a/test/libsolidity/semanticTests/array/calldata_array_dynamic_invalid.sol b/test/libsolidity/semanticTests/array/calldata_array_dynamic_invalid.sol new file mode 100644 index 000000000..d643d3973 --- /dev/null +++ b/test/libsolidity/semanticTests/array/calldata_array_dynamic_invalid.sol @@ -0,0 +1,21 @@ +pragma experimental ABIEncoderV2; + + +contract C { + function f(uint256[][] calldata a) external returns (uint256) { + return 42; + } + + function g(uint256[][] calldata a) external returns (uint256) { + a[0]; + return 42; + } +} + +// ---- +// f(uint256[][]): 0x20, 0x0 -> 42 # valid access stub # +// f(uint256[][]): 0x20, 0x1 -> FAILURE # invalid on argument decoding # +// f(uint256[][]): 0x20, 0x1, 0x20 -> 42 # invalid on outer access # +// g(uint256[][]): 0x20, 0x1, 0x20 -> FAILURE +// f(uint256[][]): 0x20, 0x1, 0x20, 0x2, 0x42 -> 42 # invalid on inner access # +// g(uint256[][]): 0x20, 0x1, 0x20, 0x2, 0x42 -> FAILURE diff --git a/test/libsolidity/semanticTests/array/calldata_array_dynamic_invalid_static_middle.sol b/test/libsolidity/semanticTests/array/calldata_array_dynamic_invalid_static_middle.sol new file mode 100644 index 000000000..3efd177b2 --- /dev/null +++ b/test/libsolidity/semanticTests/array/calldata_array_dynamic_invalid_static_middle.sol @@ -0,0 +1,30 @@ +pragma experimental ABIEncoderV2; + + +contract C { + function f(uint256[][1][] calldata a) external returns (uint256) { + return 42; + } + + function g(uint256[][1][] calldata a) external returns (uint256) { + a[0]; + return 42; + } + + function h(uint256[][1][] calldata a) external returns (uint256) { + a[0][0]; + return 42; + } +} + +// ---- +// f(uint256[][1][]): 0x20, 0x0 -> 42 # valid access stub # +// f(uint256[][1][]): 0x20, 0x1 -> FAILURE # invalid on argument decoding # +// f(uint256[][1][]): 0x20, 0x1, 0x20 -> 42 # invalid on outer access # +// g(uint256[][1][]): 0x20, 0x1, 0x20 -> FAILURE +// f(uint256[][1][]): 0x20, 0x1, 0x20, 0x20 -> 42 # invalid on inner access # +// g(uint256[][1][]): 0x20, 0x1, 0x20, 0x20 -> 42 +// h(uint256[][1][]): 0x20, 0x1, 0x20, 0x20 -> FAILURE +// f(uint256[][1][]): 0x20, 0x1, 0x20, 0x20, 0x1 -> 42 +// g(uint256[][1][]): 0x20, 0x1, 0x20, 0x20, 0x1 -> 42 +// h(uint256[][1][]): 0x20, 0x1, 0x20, 0x20, 0x1 -> FAILURE diff --git a/test/libsolidity/semanticTests/array/calldata_array_of_struct.sol b/test/libsolidity/semanticTests/array/calldata_array_of_struct.sol new file mode 100644 index 000000000..333112265 --- /dev/null +++ b/test/libsolidity/semanticTests/array/calldata_array_of_struct.sol @@ -0,0 +1,24 @@ +pragma experimental ABIEncoderV2; + + +contract C { + struct S { + uint256 a; + uint256 b; + } + + function f(S[] calldata s) + external + pure + returns (uint256 l, uint256 a, uint256 b, uint256 c, uint256 d) + { + l = s.length; + a = s[0].a; + b = s[0].b; + c = s[1].a; + d = s[1].b; + } +} + +// ---- +// f((uint256,uint256)[]): 0x20, 0x2, 0x1, 0x2, 0x3, 0x4 -> 2, 1, 2, 3, 4 diff --git a/test/libsolidity/semanticTests/array/calldata_array_of_struct_to_memory.sol b/test/libsolidity/semanticTests/array/calldata_array_of_struct_to_memory.sol new file mode 100644 index 000000000..f408746f5 --- /dev/null +++ b/test/libsolidity/semanticTests/array/calldata_array_of_struct_to_memory.sol @@ -0,0 +1,25 @@ +pragma experimental ABIEncoderV2; + + +contract C { + struct S { + uint256 a; + uint256 b; + } + + function f(S[] calldata s) + external + pure + returns (uint256 l, uint256 a, uint256 b, uint256 c, uint256 d) + { + S[] memory m = s; + l = m.length; + a = m[0].a; + b = m[0].b; + c = m[1].a; + d = m[1].b; + } +} + +// ---- +// f((uint256,uint256)[]): 0x20, 0x2, 0x1, 0x2, 0x3, 0x4 -> 2, 1, 2, 3, 4 diff --git a/test/libsolidity/semanticTests/array/calldata_dynamic_array_to_memory.sol b/test/libsolidity/semanticTests/array/calldata_dynamic_array_to_memory.sol new file mode 100644 index 000000000..7b225a33b --- /dev/null +++ b/test/libsolidity/semanticTests/array/calldata_dynamic_array_to_memory.sol @@ -0,0 +1,15 @@ +pragma experimental ABIEncoderV2; + + +contract C { + function f(uint256[][] calldata a) + external + returns (uint256, uint256[] memory) + { + uint256[] memory m = a[0]; + return (a.length, m); + } +} + +// ---- +// f(uint256[][]): 0x20, 0x1, 0x20, 0x2, 0x17, 0x2a -> 0x1, 0x40, 0x2, 0x17, 0x2a diff --git a/test/libsolidity/semanticTests/array/calldata_slice_access.sol b/test/libsolidity/semanticTests/array/calldata_slice_access.sol index 8e8a398de..7eb975677 100644 --- a/test/libsolidity/semanticTests/array/calldata_slice_access.sol +++ b/test/libsolidity/semanticTests/array/calldata_slice_access.sol @@ -6,6 +6,8 @@ contract C { return (x[start:end][index], x[start:][0:end-start][index], x[:end][start:][index]); } } +// ==== +// compileViaYul: also // ---- // f(uint256[],uint256,uint256): 0x80, 0, 0, 0, 1, 42 -> // f(uint256[],uint256,uint256): 0x80, 0, 1, 0, 1, 42 -> diff --git a/test/libsolidity/semanticTests/array/constant_var_as_array_length.sol b/test/libsolidity/semanticTests/array/constant_var_as_array_length.sol new file mode 100644 index 000000000..017de5d7b --- /dev/null +++ b/test/libsolidity/semanticTests/array/constant_var_as_array_length.sol @@ -0,0 +1,14 @@ +contract C { + uint256 constant LEN = 3; + uint256[LEN] public a; + + constructor(uint256[LEN] memory _a) public { + a = _a; + } +} + +// ---- +// constructor(): 1, 2, 3 -> +// a(uint256): 0 -> 1 +// a(uint256): 1 -> 2 +// a(uint256): 2 -> 3 diff --git a/test/libsolidity/semanticTests/array/copy_function_storage_array.sol b/test/libsolidity/semanticTests/array/copy_function_storage_array.sol new file mode 100644 index 000000000..eba61ad1a --- /dev/null +++ b/test/libsolidity/semanticTests/array/copy_function_storage_array.sol @@ -0,0 +1,18 @@ +contract C { + function() internal returns (uint)[] x; + function() internal returns (uint)[] y; + + function test() public returns (uint256) { + x = new function() internal returns (uint)[](10); + x[9] = a; + y = x; + return y[9](); + } + + function a() public returns (uint256) { + return 7; + } +} + +// ---- +// test() -> 7 diff --git a/test/libsolidity/semanticTests/array/copy_internal_function_array_to_storage.sol b/test/libsolidity/semanticTests/array/copy_internal_function_array_to_storage.sol new file mode 100644 index 000000000..076cbbf69 --- /dev/null +++ b/test/libsolidity/semanticTests/array/copy_internal_function_array_to_storage.sol @@ -0,0 +1,22 @@ +contract C { + function() internal returns (uint)[20] x; + int256 mutex; + + function one() public returns (uint256) { + function() internal returns (uint)[20] memory xmem; + x = xmem; + return 3; + } + + function two() public returns (uint256) { + if (mutex > 0) return 7; + mutex = 1; + // If this test fails, it might re-execute this function. + x[0](); + return 2; + } +} + +// ---- +// one() -> 3 +// two() -> FAILURE diff --git a/test/libsolidity/semanticTests/array/create_dynamic_array_with_zero_length.sol b/test/libsolidity/semanticTests/array/create_dynamic_array_with_zero_length.sol new file mode 100644 index 000000000..7c2ccde6e --- /dev/null +++ b/test/libsolidity/semanticTests/array/create_dynamic_array_with_zero_length.sol @@ -0,0 +1,9 @@ +contract C { + function f() public returns (uint256) { + uint256[][] memory a = new uint256[][](0); + return 7; + } +} + +// ---- +// f() -> 7 diff --git a/test/libsolidity/semanticTests/array/create_memory_array.sol b/test/libsolidity/semanticTests/array/create_memory_array.sol new file mode 100644 index 000000000..fd4fe943c --- /dev/null +++ b/test/libsolidity/semanticTests/array/create_memory_array.sol @@ -0,0 +1,21 @@ +contract C { + struct S { + uint256[2] a; + bytes b; + } + + function f() public returns (bytes1, uint256, uint256, bytes1) { + bytes memory x = new bytes(200); + x[199] = "A"; + uint256[2][] memory y = new uint256[2][](300); + y[203][1] = 8; + S[] memory z = new S[](180); + z[170].a[1] = 4; + z[170].b = new bytes(102); + z[170].b[99] = "B"; + return (x[199], y[203][1], z[170].a[1], z[170].b[99]); + } +} + +// ---- +// f() -> "A", 8, 4, "B" diff --git a/test/libsolidity/semanticTests/array/create_multiple_dynamic_arrays.sol b/test/libsolidity/semanticTests/array/create_multiple_dynamic_arrays.sol new file mode 100644 index 000000000..731fb4312 --- /dev/null +++ b/test/libsolidity/semanticTests/array/create_multiple_dynamic_arrays.sol @@ -0,0 +1,34 @@ +contract C { + function f() public returns (uint256) { + uint256[][] memory x = new uint256[][](42); + assert(x[0].length == 0); + x[0] = new uint256[](1); + x[0][0] = 1; + assert(x[4].length == 0); + x[4] = new uint256[](1); + x[4][0] = 2; + assert(x[10].length == 0); + x[10] = new uint256[](1); + x[10][0] = 44; + uint256[][] memory y = new uint256[][](24); + assert(y[0].length == 0); + y[0] = new uint256[](1); + y[0][0] = 1; + assert(y[4].length == 0); + y[4] = new uint256[](1); + y[4][0] = 2; + assert(y[10].length == 0); + y[10] = new uint256[](1); + y[10][0] = 88; + if ( + (x[0][0] == y[0][0]) && + (x[4][0] == y[4][0]) && + (x[10][0] == 44) && + (y[10][0] == 88) + ) return 7; + return 0; + } +} + +// ---- +// f() -> 7 diff --git a/test/libsolidity/semanticTests/array/delete_on_array_of_structs.sol b/test/libsolidity/semanticTests/array/delete_on_array_of_structs.sol new file mode 100644 index 000000000..316b8d9ef --- /dev/null +++ b/test/libsolidity/semanticTests/array/delete_on_array_of_structs.sol @@ -0,0 +1,20 @@ +// Test for a bug where we did not increment the counter properly while deleting a dynamic array. +contract C { + struct S { + uint256 x; + uint256[] y; + } + S[] data; + + function f() public returns (bool) { + S storage s1 = data.push(); + s1.x = 2**200; + S storage s2 = data.push(); + s2.x = 2**200; + delete data; + return true; + } +} + +// ---- +// f() -> true # This code interprets x as an array length and thus will go out of gas. neither of the two should throw due to out-of-bounds access # diff --git a/test/libsolidity/semanticTests/array/dynamic_arrays_in_storage.sol b/test/libsolidity/semanticTests/array/dynamic_arrays_in_storage.sol new file mode 100644 index 000000000..6680ec5d9 --- /dev/null +++ b/test/libsolidity/semanticTests/array/dynamic_arrays_in_storage.sol @@ -0,0 +1,53 @@ +contract c { + struct Data { + uint256 x; + uint256 y; + } + Data[] data; + uint256[] ids; + + function setIDStatic(uint256 id) public { + ids[2] = id; + } + + function setID(uint256 index, uint256 id) public { + ids[index] = id; + } + + function setData(uint256 index, uint256 x, uint256 y) public { + data[index].x = x; + data[index].y = y; + } + + function getID(uint256 index) public returns (uint256) { + return ids[index]; + } + + function getData(uint256 index) public returns (uint256 x, uint256 y) { + x = data[index].x; + y = data[index].y; + } + + function getLengths() public returns (uint256 l1, uint256 l2) { + l1 = data.length; + l2 = ids.length; + } + + function setLengths(uint256 l1, uint256 l2) public { + while (data.length < l1) data.push(); + while (ids.length < l2) ids.push(); + } +} + +// ---- +// getLengths() -> 0, 0 +// setLengths(uint256,uint256): 48, 49 -> +// getLengths() -> 48, 49 +// setIDStatic(uint256): 11 -> +// getID(uint256): 2 -> 11 +// setID(uint256,uint256): 7, 8 -> +// getID(uint256): 7 -> 8 +// setData(uint256,uint256,uint256): 7, 8, 9 -> +// setData(uint256,uint256,uint256): 8, 10, 11 -> +// getData(uint256): 7 -> 8, 9 +// getData(uint256): 8 -> 10, 11 diff --git a/test/libsolidity/semanticTests/array/dynamic_out_of_bounds_array_access.sol b/test/libsolidity/semanticTests/array/dynamic_out_of_bounds_array_access.sol new file mode 100644 index 000000000..b2c6893a5 --- /dev/null +++ b/test/libsolidity/semanticTests/array/dynamic_out_of_bounds_array_access.sol @@ -0,0 +1,34 @@ +contract c { + uint256[] data; + + function enlarge(uint256 amount) public returns (uint256) { + while (data.length < amount) data.push(); + return data.length; + } + + function set(uint256 index, uint256 value) public returns (bool) { + data[index] = value; + return true; + } + + function get(uint256 index) public returns (uint256) { + return data[index]; + } + + function length() public returns (uint256) { + return data.length; + } +} + +// ==== +// compileViaYul: also +// ---- +// length() -> 0 +// get(uint256): 3 -> FAILURE +// enlarge(uint256): 4 -> 4 +// length() -> 4 +// set(uint256,uint256): 3, 4 -> true +// get(uint256): 3 -> 4 +// length() -> 4 +// set(uint256,uint256): 4, 8 -> FAILURE +// length() -> 4 diff --git a/test/libsolidity/semanticTests/array/evm_exceptions_out_of_band_access.sol b/test/libsolidity/semanticTests/array/evm_exceptions_out_of_band_access.sol new file mode 100644 index 000000000..af14b48b4 --- /dev/null +++ b/test/libsolidity/semanticTests/array/evm_exceptions_out_of_band_access.sol @@ -0,0 +1,19 @@ +contract A { + uint256[3] arr; + bool public test = false; + + function getElement(uint256 i) public returns (uint256) { + return arr[i]; + } + + function testIt() public returns (bool) { + uint256 i = this.getElement(5); + test = true; + return true; + } +} + +// ---- +// test() -> false +// testIt() -> FAILURE +// test() -> false diff --git a/test/libsolidity/semanticTests/array/fixed_arrays_as_return_type.sol b/test/libsolidity/semanticTests/array/fixed_arrays_as_return_type.sol new file mode 100644 index 000000000..61d1a33f5 --- /dev/null +++ b/test/libsolidity/semanticTests/array/fixed_arrays_as_return_type.sol @@ -0,0 +1,21 @@ +contract A { + function f(uint16 input) public pure returns (uint16[5] memory arr) { + arr[0] = input; + arr[1] = ++input; + arr[2] = ++input; + arr[3] = ++input; + arr[4] = ++input; + } +} + + +contract B { + function f() public returns (uint16[5] memory res, uint16[5] memory res2) { + A a = new A(); + res = a.f(2); + res2 = a.f(1000); + } +} + +// ---- +// f() -> 2, 3, 4, 5, 6, 1000, 1001, 1002, 1003, 1004 diff --git a/test/libsolidity/semanticTests/array/fixed_arrays_in_constructors.sol b/test/libsolidity/semanticTests/array/fixed_arrays_in_constructors.sol new file mode 100644 index 000000000..ff13db5be --- /dev/null +++ b/test/libsolidity/semanticTests/array/fixed_arrays_in_constructors.sol @@ -0,0 +1,14 @@ +contract Creator { + uint256 public r; + address public ch; + + constructor(address[3] memory s, uint256 x) public { + r = x; + ch = s[2]; + } +} + +// ---- +// constructor(): 1, 2, 3, 4 -> +// r() -> 4 +// ch() -> 3 diff --git a/test/libsolidity/semanticTests/array/fixed_bytes_length_access.sol b/test/libsolidity/semanticTests/array/fixed_bytes_length_access.sol new file mode 100644 index 000000000..7a6afbae7 --- /dev/null +++ b/test/libsolidity/semanticTests/array/fixed_bytes_length_access.sol @@ -0,0 +1,10 @@ +contract C { + bytes1 a; + + function f(bytes32 x) public returns (uint256, uint256, uint256) { + return (x.length, bytes16(uint128(2)).length, a.length + 7); + } +} + +// ---- +// f(bytes32): "789" -> 32, 16, 8 diff --git a/test/libsolidity/semanticTests/array/fixed_out_of_bounds_array_access.sol b/test/libsolidity/semanticTests/array/fixed_out_of_bounds_array_access.sol new file mode 100644 index 000000000..06246cdc6 --- /dev/null +++ b/test/libsolidity/semanticTests/array/fixed_out_of_bounds_array_access.sol @@ -0,0 +1,28 @@ +contract c { + uint256[4] data; + + function set(uint256 index, uint256 value) public returns (bool) { + data[index] = value; + return true; + } + + function get(uint256 index) public returns (uint256) { + return data[index]; + } + + function length() public returns (uint256) { + return data.length; + } +} + +// ==== +// compileViaYul: also +// ---- +// length() -> 4 +// set(uint256,uint256): 3, 4 -> true +// set(uint256,uint256): 4, 5 -> FAILURE +// set(uint256,uint256): 400, 5 -> FAILURE +// get(uint256): 3 -> 4 +// get(uint256): 4 -> FAILURE +// get(uint256): 400 -> FAILURE +// length() -> 4 diff --git a/test/libsolidity/semanticTests/array/function_array_cross_calls.sol b/test/libsolidity/semanticTests/array/function_array_cross_calls.sol new file mode 100644 index 000000000..64f8c7402 --- /dev/null +++ b/test/libsolidity/semanticTests/array/function_array_cross_calls.sol @@ -0,0 +1,45 @@ +contract D { + function f(function() external returns (function() external returns (uint))[] memory x) + public returns (function() external returns (uint)[3] memory r) { + r[0] = x[0](); + r[1] = x[1](); + r[2] = x[2](); + } +} + + +contract C { + function test() public returns (uint256, uint256, uint256) { + function() external returns (function() external returns (uint))[] memory x = + new function() external returns (function() external returns (uint))[](10); + for (uint256 i = 0; i < x.length; i++) x[i] = this.h; + x[0] = this.htwo; + function() external returns (uint)[3] memory y = (new D()).f(x); + return (y[0](), y[1](), y[2]()); + } + + function e() public returns (uint256) { + return 5; + } + + function f() public returns (uint256) { + return 6; + } + + function g() public returns (uint256) { + return 7; + } + + uint256 counter; + + function h() public returns (function() external returns (uint)) { + return counter++ == 0 ? this.f : this.g; + } + + function htwo() public returns (function() external returns (uint)) { + return this.e; + } +} + +// ---- +// test() -> 5, 6, 7 diff --git a/test/libsolidity/semanticTests/array/function_memory_array.sol b/test/libsolidity/semanticTests/array/function_memory_array.sol new file mode 100644 index 000000000..cc6b3cf46 --- /dev/null +++ b/test/libsolidity/semanticTests/array/function_memory_array.sol @@ -0,0 +1,40 @@ +contract C { + function a(uint256 x) public returns (uint256) { + return x + 1; + } + + function b(uint256 x) public returns (uint256) { + return x + 2; + } + + function c(uint256 x) public returns (uint256) { + return x + 3; + } + + function d(uint256 x) public returns (uint256) { + return x + 5; + } + + function e(uint256 x) public returns (uint256) { + return x + 8; + } + + function test(uint256 x, uint256 i) public returns (uint256) { + function(uint) internal returns (uint)[] memory arr = + new function(uint) internal returns (uint)[](10); + arr[0] = a; + arr[1] = b; + arr[2] = c; + arr[3] = d; + arr[4] = e; + return arr[i](x); + } +} + +// ---- +// test(uint256,uint256): 10, 0 -> 11 +// test(uint256,uint256): 10, 1 -> 12 +// test(uint256,uint256): 10, 2 -> 13 +// test(uint256,uint256): 10, 3 -> 15 +// test(uint256,uint256): 10, 4 -> 18 +// test(uint256,uint256): 10, 5 -> FAILURE diff --git a/test/libsolidity/semanticTests/array/inline_array_index_access_ints.sol b/test/libsolidity/semanticTests/array/inline_array_index_access_ints.sol new file mode 100644 index 000000000..8dc5a7451 --- /dev/null +++ b/test/libsolidity/semanticTests/array/inline_array_index_access_ints.sol @@ -0,0 +1,8 @@ +contract C { + function f() public returns (uint256) { + return ([1, 2, 3, 4][2]); + } +} + +// ---- +// f() -> 3 diff --git a/test/libsolidity/semanticTests/array/inline_array_index_access_strings.sol b/test/libsolidity/semanticTests/array/inline_array_index_access_strings.sol new file mode 100644 index 000000000..19dfcf3b7 --- /dev/null +++ b/test/libsolidity/semanticTests/array/inline_array_index_access_strings.sol @@ -0,0 +1,15 @@ +contract C { + string public tester; + + function f() public returns (string memory) { + return (["abc", "def", "g"][0]); + } + + function test() public { + tester = f(); + } +} + +// ---- +// test() -> +// tester() -> 0x20, 0x3, "abc" diff --git a/test/libsolidity/semanticTests/array/inline_array_return.sol b/test/libsolidity/semanticTests/array/inline_array_return.sol new file mode 100644 index 000000000..e247d1558 --- /dev/null +++ b/test/libsolidity/semanticTests/array/inline_array_return.sol @@ -0,0 +1,15 @@ +contract C { + uint8[] tester; + + function f() public returns (uint8[5] memory) { + return ([1, 2, 3, 4, 5]); + } + + function test() public returns (uint8, uint8, uint8, uint8, uint8) { + tester = f(); + return (tester[0], tester[1], tester[2], tester[3], tester[4]); + } +} + +// ---- +// f() -> 1, 2, 3, 4, 5 diff --git a/test/libsolidity/semanticTests/array/inline_array_singleton.sol b/test/libsolidity/semanticTests/array/inline_array_singleton.sol new file mode 100644 index 000000000..5925aba0f --- /dev/null +++ b/test/libsolidity/semanticTests/array/inline_array_singleton.sol @@ -0,0 +1,9 @@ +// This caused a failure since the type was not converted to its mobile type. +contract C { + function f() public returns (uint256) { + return [4][0]; + } +} + +// ---- +// f() -> 4 diff --git a/test/libsolidity/semanticTests/array/inline_array_storage_to_memory_conversion_ints.sol b/test/libsolidity/semanticTests/array/inline_array_storage_to_memory_conversion_ints.sol new file mode 100644 index 000000000..f3f37ea20 --- /dev/null +++ b/test/libsolidity/semanticTests/array/inline_array_storage_to_memory_conversion_ints.sol @@ -0,0 +1,11 @@ +contract C { + function f() public returns (uint256 x, uint256 y) { + x = 3; + y = 6; + uint256[2] memory z = [x, y]; + return (z[0], z[1]); + } +} + +// ---- +// f() -> 3, 6 diff --git a/test/libsolidity/semanticTests/array/inline_array_storage_to_memory_conversion_strings.sol b/test/libsolidity/semanticTests/array/inline_array_storage_to_memory_conversion_strings.sol new file mode 100644 index 000000000..fa9f24a7a --- /dev/null +++ b/test/libsolidity/semanticTests/array/inline_array_storage_to_memory_conversion_strings.sol @@ -0,0 +1,12 @@ +contract C { + string s = "doh"; + + function f() public returns (string memory, string memory) { + string memory t = "ray"; + string[3] memory x = [s, t, "mi"]; + return (x[1], x[2]); + } +} + +// ---- +// f() -> 0x40, 0x80, 0x3, "ray", 0x2, "mi" diff --git a/test/libsolidity/semanticTests/array/inline_array_strings_from_document.sol b/test/libsolidity/semanticTests/array/inline_array_strings_from_document.sol new file mode 100644 index 000000000..ebcae638a --- /dev/null +++ b/test/libsolidity/semanticTests/array/inline_array_strings_from_document.sol @@ -0,0 +1,12 @@ +contract C { + function f(uint256 i) public returns (string memory) { + string[4] memory x = ["This", "is", "an", "array"]; + return (x[i]); + } +} + +// ---- +// f(uint256): 0 -> 0x20, 0x4, "This" +// f(uint256): 1 -> 0x20, 0x2, "is" +// f(uint256): 2 -> 0x20, 0x2, "an" +// f(uint256): 3 -> 0x20, 0x5, "array" diff --git a/test/libsolidity/semanticTests/array/memory_arrays_of_various_sizes.sol b/test/libsolidity/semanticTests/array/memory_arrays_of_various_sizes.sol new file mode 100644 index 000000000..b641ec1da --- /dev/null +++ b/test/libsolidity/semanticTests/array/memory_arrays_of_various_sizes.sol @@ -0,0 +1,17 @@ +// Computes binomial coefficients the chinese way +contract C { + function f(uint256 n, uint256 k) public returns (uint256) { + uint256[][] memory rows = new uint256[][](n + 1); + for (uint256 i = 1; i <= n; i++) { + rows[i] = new uint256[](i); + rows[i][0] = rows[i][rows[i].length - 1] = 1; + for (uint256 j = 1; j < i - 1; j++) + rows[i][j] = rows[i - 1][j - 1] + rows[i - 1][j]; + } + return rows[n][k - 1]; + } +} + +// ---- +// f(uint256,uint256): 3, 1 -> 1 +// f(uint256,uint256): 9, 5 -> 70 diff --git a/test/libsolidity/semanticTests/array/storage_array_ref.sol b/test/libsolidity/semanticTests/array/storage_array_ref.sol new file mode 100644 index 000000000..0b0224bfc --- /dev/null +++ b/test/libsolidity/semanticTests/array/storage_array_ref.sol @@ -0,0 +1,60 @@ +contract BinarySearch { + /// Finds the position of _value in the sorted list _data. + /// Note that "internal" is important here, because storage references only work for internal or private functions + function find(uint256[] storage _data, uint256 _value) + internal + returns (uint256 o_position) + { + return find(_data, 0, _data.length, _value); + } + + function find( + uint256[] storage _data, + uint256 _begin, + uint256 _len, + uint256 _value + ) private returns (uint256 o_position) { + if (_len == 0 || (_len == 1 && _data[_begin] != _value)) + return uint256(-1); // failure + uint256 halfLen = _len / 2; + uint256 v = _data[_begin + halfLen]; + if (_value < v) return find(_data, _begin, halfLen, _value); + else if (_value > v) + return find(_data, _begin + halfLen + 1, halfLen - 1, _value); + else return _begin + halfLen; + } +} + + +contract Store is BinarySearch { + uint256[] data; + + function add(uint256 v) public { + data.push(0); + data[data.length - 1] = v; + } + + function find(uint256 v) public returns (uint256) { + return find(data, v); + } +} + +// ==== +// compileViaYul: also +// ---- +// find(uint256): 7 -> -1 +// add(uint256): 7 -> +// find(uint256): 7 -> 0 +// add(uint256): 11 -> +// add(uint256): 17 -> +// add(uint256): 27 -> +// add(uint256): 31 -> +// add(uint256): 32 -> +// add(uint256): 66 -> +// add(uint256): 177 -> +// find(uint256): 7 -> 0 +// find(uint256): 27 -> 3 +// find(uint256): 32 -> 5 +// find(uint256): 176 -> -1 +// find(uint256): 0 -> -1 +// find(uint256): 400 -> -1 diff --git a/test/libsolidity/semanticTests/builtinFunctions/keccak256_empty.sol b/test/libsolidity/semanticTests/builtinFunctions/keccak256_empty.sol new file mode 100644 index 000000000..1374538c2 --- /dev/null +++ b/test/libsolidity/semanticTests/builtinFunctions/keccak256_empty.sol @@ -0,0 +1,10 @@ +contract C { + function f() public returns (bytes32) { + return keccak256(""); + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 diff --git a/test/libsolidity/semanticTests/builtinFunctions/keccak256_with_bytes.sol b/test/libsolidity/semanticTests/builtinFunctions/keccak256_with_bytes.sol new file mode 100644 index 000000000..725d984d8 --- /dev/null +++ b/test/libsolidity/semanticTests/builtinFunctions/keccak256_with_bytes.sol @@ -0,0 +1,13 @@ +contract c { + bytes data; + + function foo() public returns (bool) { + data.push("f"); + data.push("o"); + data.push("o"); + return keccak256(data) == keccak256("foo"); + } +} + +// ---- +// foo() -> true diff --git a/test/libsolidity/semanticTests/builtinFunctions/ripemd160_empty.sol b/test/libsolidity/semanticTests/builtinFunctions/ripemd160_empty.sol new file mode 100644 index 000000000..c79625d3c --- /dev/null +++ b/test/libsolidity/semanticTests/builtinFunctions/ripemd160_empty.sol @@ -0,0 +1,8 @@ +contract C { + function f() public returns (bytes20) { + return ripemd160(""); + } +} + +// ---- +// f() -> 0x9c1185a5c5e9fc54612808977ee8f548b2258d31000000000000000000000000 diff --git a/test/libsolidity/semanticTests/builtinFunctions/sha256_empty.sol b/test/libsolidity/semanticTests/builtinFunctions/sha256_empty.sol new file mode 100644 index 000000000..69b9e15f5 --- /dev/null +++ b/test/libsolidity/semanticTests/builtinFunctions/sha256_empty.sol @@ -0,0 +1,8 @@ +contract C { + function f() public returns (bytes32) { + return sha256(""); + } +} + +// ---- +// f() -> 0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/test/libsolidity/semanticTests/cleanup/cleanup_address_types_shortening.sol b/test/libsolidity/semanticTests/cleanup/cleanup_address_types_shortening.sol new file mode 100644 index 000000000..074b3ff6b --- /dev/null +++ b/test/libsolidity/semanticTests/cleanup/cleanup_address_types_shortening.sol @@ -0,0 +1,33 @@ +contract C { + function f() public pure returns (address r) { + bytes21 x = 0x1122334455667788990011223344556677889900ff; + bytes20 y; + assembly { + y := x + } + address z = address(y); + assembly { + r := z + } + require(z == 0x1122334455667788990011223344556677889900); + } + + function g() public pure returns (address payable r) { + bytes21 x = 0x1122334455667788990011223344556677889900ff; + bytes20 y; + assembly { + y := x + } + address payable z = address(y); + assembly { + r := z + } + require(z == 0x1122334455667788990011223344556677889900); + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> 0x1122334455667788990011223344556677889900 +// g() -> 0x1122334455667788990011223344556677889900 diff --git a/test/libsolidity/semanticTests/cleanup/cleanup_bytes_types_shortening.sol b/test/libsolidity/semanticTests/cleanup/cleanup_bytes_types_shortening.sol new file mode 100644 index 000000000..dc7c7f890 --- /dev/null +++ b/test/libsolidity/semanticTests/cleanup/cleanup_bytes_types_shortening.sol @@ -0,0 +1,15 @@ +contract C { + function f() public pure returns (bytes32 r) { + bytes4 x = 0xffffffff; + bytes2 y = bytes2(x); + assembly { + r := y + } + // At this point, r and y both store four bytes, but + // y is properly cleaned before the equality check + require(y == bytes2(0xffff)); + } +} + +// ---- +// f() -> "\xff\xff\xff\xff" diff --git a/test/libsolidity/semanticTests/cleanup/cleanup_in_compound_assign.sol b/test/libsolidity/semanticTests/cleanup/cleanup_in_compound_assign.sol new file mode 100644 index 000000000..c1901c738 --- /dev/null +++ b/test/libsolidity/semanticTests/cleanup/cleanup_in_compound_assign.sol @@ -0,0 +1,13 @@ +contract C { + function test() public returns (uint256, uint256) { + uint32 a = 0xffffffff; + uint16 x = uint16(a); + uint16 y = x; + x /= 0x100; + y = y / 0x100; + return (x, y); + } +} + +// ---- +// test() -> 0xff, 0xff diff --git a/test/libsolidity/semanticTests/cleanup/exp_cleanup.sol b/test/libsolidity/semanticTests/cleanup/exp_cleanup.sol new file mode 100644 index 000000000..a81e2755e --- /dev/null +++ b/test/libsolidity/semanticTests/cleanup/exp_cleanup.sol @@ -0,0 +1,9 @@ +contract C { + function f() public pure returns (uint8 x) { + uint8 y = uint8(2)**uint8(8); + return 0**y; + } +} + +// ---- +// f() -> 0x1 diff --git a/test/libsolidity/semanticTests/cleanup/exp_cleanup_direct.sol b/test/libsolidity/semanticTests/cleanup/exp_cleanup_direct.sol new file mode 100644 index 000000000..a9b5e81b5 --- /dev/null +++ b/test/libsolidity/semanticTests/cleanup/exp_cleanup_direct.sol @@ -0,0 +1,8 @@ +contract C { + function f() public pure returns (uint8 x) { + return uint8(0)**uint8(uint8(2)**uint8(8)); + } +} + +// ---- +// f() -> 0x1 diff --git a/test/libsolidity/semanticTests/cleanup/exp_cleanup_nonzero_base.sol b/test/libsolidity/semanticTests/cleanup/exp_cleanup_nonzero_base.sol new file mode 100644 index 000000000..4f817d186 --- /dev/null +++ b/test/libsolidity/semanticTests/cleanup/exp_cleanup_nonzero_base.sol @@ -0,0 +1,8 @@ +contract C { + function f() public pure returns (uint8 x) { + return uint8(0x166)**uint8(uint8(2)**uint8(8)); + } +} + +// ---- +// f() -> 0x1 diff --git a/test/libsolidity/semanticTests/constants/constant_string.sol b/test/libsolidity/semanticTests/constants/constant_string.sol new file mode 100644 index 000000000..56cbf982d --- /dev/null +++ b/test/libsolidity/semanticTests/constants/constant_string.sol @@ -0,0 +1,22 @@ +contract C { + bytes constant a = "\x03\x01\x02"; + bytes constant b = hex"030102"; + string constant c = "hello"; + + function f() public returns (bytes memory) { + return a; + } + + function g() public returns (bytes memory) { + return b; + } + + function h() public returns (bytes memory) { + return bytes(c); + } +} + +// ---- +// f() -> 0x20, 3, "\x03\x01\x02" +// g() -> 0x20, 3, "\x03\x01\x02" +// h() -> 0x20, 5, "hello" diff --git a/test/libsolidity/semanticTests/constants/constant_variables.sol b/test/libsolidity/semanticTests/constants/constant_variables.sol new file mode 100644 index 000000000..98b4773c7 --- /dev/null +++ b/test/libsolidity/semanticTests/constants/constant_variables.sol @@ -0,0 +1,11 @@ +contract Foo { + uint256 constant x = 56; + enum ActionChoices {GoLeft, GoRight, GoStraight, Sit} + ActionChoices constant choices = ActionChoices.GoLeft; + bytes32 constant st = "abc\x00\xff__"; +} + +// ==== +// compileViaYul: also +// ---- +// constructor() -> diff --git a/test/libsolidity/semanticTests/constants/simple_constant_variables_test.sol b/test/libsolidity/semanticTests/constants/simple_constant_variables_test.sol new file mode 100644 index 000000000..c05060b7e --- /dev/null +++ b/test/libsolidity/semanticTests/constants/simple_constant_variables_test.sol @@ -0,0 +1,10 @@ +contract Foo { + function getX() public returns (uint256 r) { + return x; + } + + uint256 constant x = 56; +} + +// ---- +// getX() -> 56 diff --git a/test/libsolidity/semanticTests/constructor/base_constructor_arguments.sol b/test/libsolidity/semanticTests/constructor/base_constructor_arguments.sol new file mode 100644 index 000000000..2384c061f --- /dev/null +++ b/test/libsolidity/semanticTests/constructor/base_constructor_arguments.sol @@ -0,0 +1,24 @@ +contract BaseBase { + uint256 m_a; + + constructor(uint256 a) public { + m_a = a; + } +} + + +contract Base is BaseBase(7) { + constructor() public { + m_a *= m_a; + } +} + + +contract Derived is Base { + function getA() public returns (uint256 r) { + return m_a; + } +} + +// ---- +// getA() -> 49 diff --git a/test/libsolidity/semanticTests/constructor/constructor_arguments_external.sol b/test/libsolidity/semanticTests/constructor/constructor_arguments_external.sol new file mode 100644 index 000000000..ec30bacf6 --- /dev/null +++ b/test/libsolidity/semanticTests/constructor/constructor_arguments_external.sol @@ -0,0 +1,22 @@ +contract Main { + bytes3 name; + bool flag; + + constructor(bytes3 x, bool f) public { + name = x; + flag = f; + } + + function getName() public returns (bytes3 ret) { + return name; + } + + function getFlag() public returns (bool ret) { + return flag; + } +} + +// ---- +// constructor(): "abc", true +// getFlag() -> true +// getName() -> "abc" diff --git a/test/libsolidity/semanticTests/constructor/constructor_arguments_internal.sol b/test/libsolidity/semanticTests/constructor/constructor_arguments_internal.sol new file mode 100644 index 000000000..756478e34 --- /dev/null +++ b/test/libsolidity/semanticTests/constructor/constructor_arguments_internal.sol @@ -0,0 +1,38 @@ +contract Helper { + bytes3 name; + bool flag; + + constructor(bytes3 x, bool f) public { + name = x; + flag = f; + } + + function getName() public returns (bytes3 ret) { + return name; + } + + function getFlag() public returns (bool ret) { + return flag; + } +} + + +contract Main { + Helper h; + + constructor() public { + h = new Helper("abc", true); + } + + function getFlag() public returns (bool ret) { + return h.getFlag(); + } + + function getName() public returns (bytes3 ret) { + return h.getName(); + } +} + +// ---- +// getFlag() -> true +// getName() -> "abc" diff --git a/test/libsolidity/semanticTests/constructor/constructor_static_array_argument.sol b/test/libsolidity/semanticTests/constructor/constructor_static_array_argument.sol new file mode 100644 index 000000000..10243f897 --- /dev/null +++ b/test/libsolidity/semanticTests/constructor/constructor_static_array_argument.sol @@ -0,0 +1,16 @@ +contract C { + uint256 public a; + uint256[3] public b; + + constructor(uint256 _a, uint256[3] memory _b) public { + a = _a; + b = _b; + } +} + +// ---- +// constructor(): 1, 2, 3, 4 -> +// a() -> 1 +// b(uint256): 0 -> 2 +// b(uint256): 1 -> 3 +// b(uint256): 2 -> 4 diff --git a/test/libsolidity/semanticTests/constructor/evm_exceptions_in_constructor_call_fail.sol b/test/libsolidity/semanticTests/constructor/evm_exceptions_in_constructor_call_fail.sol new file mode 100644 index 000000000..2192dabf3 --- /dev/null +++ b/test/libsolidity/semanticTests/constructor/evm_exceptions_in_constructor_call_fail.sol @@ -0,0 +1,19 @@ +contract A { + constructor() public { + address(this).call("123"); + } +} + + +contract B { + uint256 public test = 1; + + function testIt() public { + A a = new A(); + ++test; + } +} + +// ---- +// testIt() -> +// test() -> 2 diff --git a/test/libsolidity/semanticTests/constructor/function_usage_in_constructor_arguments.sol b/test/libsolidity/semanticTests/constructor/function_usage_in_constructor_arguments.sol new file mode 100644 index 000000000..e92a37b19 --- /dev/null +++ b/test/libsolidity/semanticTests/constructor/function_usage_in_constructor_arguments.sol @@ -0,0 +1,24 @@ +contract BaseBase { + uint256 m_a; + + constructor(uint256 a) public { + m_a = a; + } + + function g() public returns (uint256 r) { + return 2; + } +} + + +contract Base is BaseBase(BaseBase.g()) {} + + +contract Derived is Base { + function getA() public returns (uint256 r) { + return m_a; + } +} + +// ---- +// getA() -> 2 diff --git a/test/libsolidity/semanticTests/constructor/functions_called_by_constructor.sol b/test/libsolidity/semanticTests/constructor/functions_called_by_constructor.sol new file mode 100644 index 000000000..42db8582a --- /dev/null +++ b/test/libsolidity/semanticTests/constructor/functions_called_by_constructor.sol @@ -0,0 +1,21 @@ +contract Test { + bytes3 name; + bool flag; + + constructor() public { + setName("abc"); + } + + function getName() public returns (bytes3 ret) { + return name; + } + + function setName(bytes3 _name) private { + name = _name; + } +} + +// ==== +// compileViaYul: also +// ---- +// getName() -> "abc" diff --git a/test/libsolidity/semanticTests/constructor/inline_member_init_inheritence_without_constructor.sol b/test/libsolidity/semanticTests/constructor/inline_member_init_inheritence_without_constructor.sol new file mode 100644 index 000000000..0aea44e6a --- /dev/null +++ b/test/libsolidity/semanticTests/constructor/inline_member_init_inheritence_without_constructor.sol @@ -0,0 +1,20 @@ +contract Base { + uint256 m_base = 5; + + function getBMember() public returns (uint256 i) { + return m_base; + } +} + + +contract Derived is Base { + uint256 m_derived = 6; + + function getDMember() public returns (uint256 i) { + return m_derived; + } +} + +// ---- +// getBMember() -> 5 +// getDMember() -> 6 diff --git a/test/libsolidity/semanticTests/constructor/payable_constructor.sol b/test/libsolidity/semanticTests/constructor/payable_constructor.sol new file mode 100644 index 000000000..9a3c56ebe --- /dev/null +++ b/test/libsolidity/semanticTests/constructor/payable_constructor.sol @@ -0,0 +1,8 @@ +contract C { + constructor() public payable {} +} + +// ==== +// compileViaYul: also +// ---- +// constructor(), 27 wei -> diff --git a/test/libsolidity/semanticTests/constructor/store_function_in_constructor.sol b/test/libsolidity/semanticTests/constructor/store_function_in_constructor.sol new file mode 100644 index 000000000..ab8ad47f9 --- /dev/null +++ b/test/libsolidity/semanticTests/constructor/store_function_in_constructor.sol @@ -0,0 +1,21 @@ +contract C { + uint256 public result_in_constructor; + function(uint256) returns (uint256) internal x; + + constructor() public { + x = double; + result_in_constructor = use(2); + } + + function double(uint256 _arg) public returns (uint256 _ret) { + _ret = _arg * 2; + } + + function use(uint256 _arg) public returns (uint256) { + return x(_arg); + } +} + +// ---- +// use(uint256): 3 -> 6 +// result_in_constructor() -> 4 diff --git a/test/libsolidity/semanticTests/constructor/store_internal_unused_function_in_constructor.sol b/test/libsolidity/semanticTests/constructor/store_internal_unused_function_in_constructor.sol new file mode 100644 index 000000000..7492a4281 --- /dev/null +++ b/test/libsolidity/semanticTests/constructor/store_internal_unused_function_in_constructor.sol @@ -0,0 +1,18 @@ +contract C { + function() returns (uint256) internal x; + + constructor() public { + x = unused; + } + + function unused() internal returns (uint256) { + return 7; + } + + function t() public returns (uint256) { + return x(); + } +} + +// ---- +// t() -> 7 diff --git a/test/libsolidity/semanticTests/constructor/store_internal_unused_library_function_in_constructor.sol b/test/libsolidity/semanticTests/constructor/store_internal_unused_library_function_in_constructor.sol new file mode 100644 index 000000000..0a4295114 --- /dev/null +++ b/test/libsolidity/semanticTests/constructor/store_internal_unused_library_function_in_constructor.sol @@ -0,0 +1,21 @@ +library L { + function x() internal returns (uint256) { + return 7; + } +} + + +contract C { + function() returns (uint256) internal x; + + constructor() public { + x = L.x; + } + + function t() public returns (uint256) { + return x(); + } +} + +// ---- +// t() -> 7 diff --git a/test/libsolidity/semanticTests/enums/constructing_enums_from_ints.sol b/test/libsolidity/semanticTests/enums/constructing_enums_from_ints.sol new file mode 100644 index 000000000..9ff75fad6 --- /dev/null +++ b/test/libsolidity/semanticTests/enums/constructing_enums_from_ints.sol @@ -0,0 +1,12 @@ +contract c { + enum Truth {False, True} + + function test() public returns (uint256) { + return uint256(Truth(uint8(0x701))); + } +} + +// ==== +// compileViaYul: also +// ---- +// test() -> 1 diff --git a/test/libsolidity/semanticTests/enums/enum_explicit_overflow.sol b/test/libsolidity/semanticTests/enums/enum_explicit_overflow.sol new file mode 100644 index 000000000..fd4c96ce7 --- /dev/null +++ b/test/libsolidity/semanticTests/enums/enum_explicit_overflow.sol @@ -0,0 +1,31 @@ +contract test { + enum ActionChoices {GoLeft, GoRight, GoStraight} + + constructor() public {} + + function getChoiceExp(uint256 x) public returns (uint256 d) { + choice = ActionChoices(x); + d = uint256(choice); + } + + function getChoiceFromSigned(int256 x) public returns (uint256 d) { + choice = ActionChoices(x); + d = uint256(choice); + } + + function getChoiceFromNegativeLiteral() public returns (uint256 d) { + choice = ActionChoices(-1); + d = uint256(choice); + } + + ActionChoices choice; +} + +// ==== +// compileViaYul: also +// ---- +// getChoiceExp(uint256): 3 -> FAILURE # These should throw # +// getChoiceFromSigned(int256): -1 -> FAILURE +// getChoiceFromNegativeLiteral() -> FAILURE +// getChoiceExp(uint256): 2 -> 2 # These should work # +// getChoiceExp(uint256): 0 -> 0 diff --git a/test/libsolidity/semanticTests/enums/using_contract_enums_with_explicit_contract_name.sol b/test/libsolidity/semanticTests/enums/using_contract_enums_with_explicit_contract_name.sol new file mode 100644 index 000000000..5d60a7466 --- /dev/null +++ b/test/libsolidity/semanticTests/enums/using_contract_enums_with_explicit_contract_name.sol @@ -0,0 +1,10 @@ +contract test { + enum Choice {A, B, C} + + function answer() public returns (test.Choice _ret) { + _ret = test.Choice.B; + } +} + +// ---- +// answer() -> 1 diff --git a/test/libsolidity/semanticTests/enums/using_enums.sol b/test/libsolidity/semanticTests/enums/using_enums.sol new file mode 100644 index 000000000..ae497f409 --- /dev/null +++ b/test/libsolidity/semanticTests/enums/using_enums.sol @@ -0,0 +1,16 @@ +contract test { + enum ActionChoices {GoLeft, GoRight, GoStraight, Sit} + + constructor() public { + choices = ActionChoices.GoStraight; + } + + function getChoice() public returns (uint256 d) { + d = uint256(choices); + } + + ActionChoices choices; +} + +// ---- +// getChoice() -> 2 diff --git a/test/libsolidity/semanticTests/enums/using_inherited_enum.sol b/test/libsolidity/semanticTests/enums/using_inherited_enum.sol new file mode 100644 index 000000000..c39bfe064 --- /dev/null +++ b/test/libsolidity/semanticTests/enums/using_inherited_enum.sol @@ -0,0 +1,13 @@ +contract base { + enum Choice {A, B, C} +} + + +contract test is base { + function answer() public returns (Choice _ret) { + _ret = Choice.B; + } +} + +// ---- +// answer() -> 1 diff --git a/test/libsolidity/semanticTests/enums/using_inherited_enum_excplicitly.sol b/test/libsolidity/semanticTests/enums/using_inherited_enum_excplicitly.sol new file mode 100644 index 000000000..0be3f80d4 --- /dev/null +++ b/test/libsolidity/semanticTests/enums/using_inherited_enum_excplicitly.sol @@ -0,0 +1,13 @@ +contract base { + enum Choice {A, B, C} +} + + +contract test is base { + function answer() public returns (base.Choice _ret) { + _ret = base.Choice.B; + } +} + +// ---- +// answer() -> 1 diff --git a/test/libsolidity/semanticTests/functionCall/call_function_returning_function.sol b/test/libsolidity/semanticTests/functionCall/call_function_returning_function.sol new file mode 100644 index 000000000..5d93ba0ee --- /dev/null +++ b/test/libsolidity/semanticTests/functionCall/call_function_returning_function.sol @@ -0,0 +1,28 @@ +contract test { + function f0() public returns (uint) { + return 2; + } + + function f1() internal returns (function() internal returns (uint)) { + return f0; + } + + function f2() internal returns (function() internal returns (function () internal returns (uint))) { + return f1; + } + + function f3() internal returns (function() internal returns (function () internal returns (function () internal returns (uint)))) { + return f2; + } + + function f() public returns (uint) { + function() internal returns(function() internal returns(function() internal returns(function() internal returns(uint)))) x; + x = f3; + return x()()()(); + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> 2 diff --git a/test/libsolidity/semanticTests/functionCall/calling_nonexisting_contract_throws.sol b/test/libsolidity/semanticTests/functionCall/calling_nonexisting_contract_throws.sol new file mode 100644 index 000000000..2ccfc064c --- /dev/null +++ b/test/libsolidity/semanticTests/functionCall/calling_nonexisting_contract_throws.sol @@ -0,0 +1,28 @@ +abstract contract D { + function g() public virtual; +} + + +contract C { + D d = D(0x1212); + + function f() public returns (uint256) { + d.g(); + return 7; + } + + function g() public returns (uint256) { + d.g.gas(200)(); + return 7; + } + + function h() public returns (uint256) { + address(d).call(""); // this does not throw (low-level) + return 7; + } +} + +// ---- +// f() -> FAILURE +// g() -> FAILURE +// h() -> 7 diff --git a/test/libsolidity/semanticTests/functionCall/calling_uninitialized_function.sol b/test/libsolidity/semanticTests/functionCall/calling_uninitialized_function.sol new file mode 100644 index 000000000..e1cab8fe8 --- /dev/null +++ b/test/libsolidity/semanticTests/functionCall/calling_uninitialized_function.sol @@ -0,0 +1,17 @@ +contract C { + function intern() public returns (uint256) { + function (uint) internal returns (uint) x; + x(2); + return 7; + } + + function extern() public returns (uint256) { + function (uint) external returns (uint) x; + x(2); + return 7; + } +} + +// ---- +// intern() -> FAILURE # This should throw exceptions # +// extern() -> FAILURE diff --git a/test/libsolidity/semanticTests/functionCall/calling_uninitialized_function_in_detail.sol b/test/libsolidity/semanticTests/functionCall/calling_uninitialized_function_in_detail.sol new file mode 100644 index 000000000..0ae431b24 --- /dev/null +++ b/test/libsolidity/semanticTests/functionCall/calling_uninitialized_function_in_detail.sol @@ -0,0 +1,20 @@ +contract C { + function() returns (uint256) internal x; + int256 mutex; + + function t() public returns (uint256) { + if (mutex > 0) { + assembly { + mstore(0, 7) + return(0, 0x20) + } + } + mutex = 1; + // Avoid re-executing this function if we jump somewhere. + x(); + return 2; + } +} + +// ---- +// t() -> FAILURE diff --git a/test/libsolidity/semanticTests/functionCall/calling_uninitialized_function_through_array.sol b/test/libsolidity/semanticTests/functionCall/calling_uninitialized_function_through_array.sol new file mode 100644 index 000000000..26a2a79f4 --- /dev/null +++ b/test/libsolidity/semanticTests/functionCall/calling_uninitialized_function_through_array.sol @@ -0,0 +1,20 @@ +contract C { + int256 mutex; + + function t() public returns (uint256) { + if (mutex > 0) { + assembly { + mstore(0, 7) + return(0, 0x20) + } + } + mutex = 1; + // Avoid re-executing this function if we jump somewhere. + function() internal returns (uint)[200] memory x; + x[0](); + return 2; + } +} + +// ---- +// t() -> FAILURE diff --git a/test/libsolidity/semanticTests/functionCall/external_call_value.sol b/test/libsolidity/semanticTests/functionCall/external_call_value.sol new file mode 100644 index 000000000..47e2bfb76 --- /dev/null +++ b/test/libsolidity/semanticTests/functionCall/external_call_value.sol @@ -0,0 +1,17 @@ +pragma solidity >= 0.6.0; + +contract C { + function g(uint n) external payable returns (uint, uint) { + return (msg.value * 1000, n); + } + + function f(uint n) public payable returns (uint, uint) { + return this.g{value: 10}(n); + } +} + +// ==== +// compileViaYul: also +// ---- +// g(uint256), 1 ether: 4 -> 1000000000000000000000, 4 +// f(uint256), 11 ether: 2 -> 10000, 2 diff --git a/test/libsolidity/semanticTests/functionCall/external_function.sol b/test/libsolidity/semanticTests/functionCall/external_function.sol new file mode 100644 index 000000000..362586447 --- /dev/null +++ b/test/libsolidity/semanticTests/functionCall/external_function.sol @@ -0,0 +1,18 @@ +contract c { + function f(uint256 a) public returns (uint256) { + return a; + } + + function test(uint256 a, uint256 b) + external + returns (uint256 r_a, uint256 r_b) + { + r_a = f(a + 7); + r_b = b; + } +} + +// ==== +// compileViaYul: also +// ---- +// test(uint256,uint256): 2, 3 -> 9, 3 diff --git a/test/libsolidity/semanticTests/functionCall/external_public_override.sol b/test/libsolidity/semanticTests/functionCall/external_public_override.sol new file mode 100644 index 000000000..7909f8e32 --- /dev/null +++ b/test/libsolidity/semanticTests/functionCall/external_public_override.sol @@ -0,0 +1,22 @@ +contract A { + function f() external virtual returns (uint256) { + return 1; + } +} + + +contract B is A { + function f() public override returns (uint256) { + return 2; + } + + function g() public returns (uint256) { + return f(); + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> 2 +// g() -> 2 diff --git a/test/libsolidity/semanticTests/functionCall/gas_and_value_basic.sol b/test/libsolidity/semanticTests/functionCall/gas_and_value_basic.sol new file mode 100644 index 000000000..aaafb6f28 --- /dev/null +++ b/test/libsolidity/semanticTests/functionCall/gas_and_value_basic.sol @@ -0,0 +1,44 @@ +contract helper { + bool flag; + + function getBalance() public payable returns (uint256 myBalance) { + return address(this).balance; + } + + function setFlag() public { + flag = true; + } + + function getFlag() public returns (bool fl) { + return flag; + } +} + + +contract test { + helper h; + + constructor() public payable { + h = new helper(); + } + + function sendAmount(uint256 amount) public payable returns (uint256 bal) { + return h.getBalance.value(amount)(); + } + + function outOfGas() public returns (bool ret) { + h.setFlag.gas(2)(); // should fail due to OOG + return true; + } + + function checkState() public returns (bool flagAfter, uint256 myBal) { + flagAfter = h.getFlag(); + myBal = address(this).balance; + } +} + +// ---- +// constructor(), 20 wei -> +// sendAmount(uint256): 5 -> 5 +// outOfGas() -> FAILURE # call to helper should not succeed but amount should be transferred anyway # +// checkState() -> false, 15 diff --git a/test/libsolidity/semanticTests/functionCall/gas_and_value_brace_syntax.sol b/test/libsolidity/semanticTests/functionCall/gas_and_value_brace_syntax.sol new file mode 100644 index 000000000..dbd524deb --- /dev/null +++ b/test/libsolidity/semanticTests/functionCall/gas_and_value_brace_syntax.sol @@ -0,0 +1,43 @@ +contract helper { + bool flag; + + function getBalance() payable public returns(uint256 myBalance) { + return address(this).balance; + } + + function setFlag() public { + flag = true; + } + + function getFlag() public returns(bool fl) { + return flag; + } +} +contract test { + helper h; + constructor() public payable { + h = new helper(); + } + + function sendAmount(uint amount) public payable returns(uint256 bal) { + return h.getBalance{value: amount}(); + } + + function outOfGas() public returns(bool ret) { + h.setFlag { + gas: 2 + }(); // should fail due to OOG + return true; + } + + function checkState() public returns(bool flagAfter, uint myBal) { + flagAfter = h.getFlag(); + myBal = address(this).balance; + } +} + +// ---- +// constructor(), 20 wei -> +// sendAmount(uint256): 5 -> 5 +// outOfGas() -> FAILURE # call to helper should not succeed but amount should be transferred anyway # +// checkState() -> false, 15 \ No newline at end of file diff --git a/test/libsolidity/semanticTests/functionCall/send_zero_ether.sol b/test/libsolidity/semanticTests/functionCall/send_zero_ether.sol new file mode 100644 index 000000000..e0c6ff5e0 --- /dev/null +++ b/test/libsolidity/semanticTests/functionCall/send_zero_ether.sol @@ -0,0 +1,19 @@ +// Sending zero ether to a contract should still invoke the receive ether function +// (it previously did not because the gas stipend was not provided by the EVM) +contract Receiver { + receive() external payable {} +} + + +contract Main { + constructor() public payable {} + + function s() public returns (bool) { + Receiver r = new Receiver(); + return address(r).send(0); + } +} + +// ---- +// constructor(), 20 wei -> +// s() -> true diff --git a/test/libsolidity/semanticTests/functionTypes/function_delete_stack.sol b/test/libsolidity/semanticTests/functionTypes/function_delete_stack.sol new file mode 100644 index 000000000..96a66fce2 --- /dev/null +++ b/test/libsolidity/semanticTests/functionTypes/function_delete_stack.sol @@ -0,0 +1,16 @@ +contract C { + function a() public returns (uint256) { + return 7; + } + + function test() public returns (uint256) { + function() returns (uint256) y = a; + delete y; + y(); + } +} + +// ==== +// compileViaYul: also +// ---- +// test() -> FAILURE diff --git a/test/libsolidity/semanticTests/functionTypes/function_delete_storage.sol b/test/libsolidity/semanticTests/functionTypes/function_delete_storage.sol new file mode 100644 index 000000000..6c7ecf4f6 --- /dev/null +++ b/test/libsolidity/semanticTests/functionTypes/function_delete_storage.sol @@ -0,0 +1,27 @@ +contract C { + function a() public returns (uint256) { + return 7; + } + + function() returns (uint256) internal y; + + function set() public returns (uint256) { + y = a; + return y(); + } + + function d() public returns (uint256) { + delete y; + return 1; + } + + function ca() public returns (uint256) { + return y(); + } +} + +// ---- +// set() -> 7 +// ca() -> 7 +// d() -> 1 +// ca() -> FAILURE diff --git a/test/libsolidity/semanticTests/functionTypes/function_type_library_internal.sol b/test/libsolidity/semanticTests/functionTypes/function_type_library_internal.sol new file mode 100644 index 000000000..f096a4979 --- /dev/null +++ b/test/libsolidity/semanticTests/functionTypes/function_type_library_internal.sol @@ -0,0 +1,26 @@ +library Utils { + function reduce( + uint256[] memory array, + function(uint, uint) internal returns (uint) f, + uint256 init + ) internal returns (uint256) { + for (uint256 i = 0; i < array.length; i++) { + init = f(array[i], init); + } + return init; + } + + function sum(uint256 a, uint256 b) internal returns (uint256) { + return a + b; + } +} + + +contract C { + function f(uint256[] memory x) public returns (uint256) { + return Utils.reduce(x, Utils.sum, 0); + } +} + +// ---- +// f(uint256[]): 0x20, 0x3, 0x1, 0x7, 0x3 -> 11 diff --git a/test/libsolidity/semanticTests/functionTypes/mapping_of_functions.sol b/test/libsolidity/semanticTests/functionTypes/mapping_of_functions.sol new file mode 100644 index 000000000..ac802ee9e --- /dev/null +++ b/test/libsolidity/semanticTests/functionTypes/mapping_of_functions.sol @@ -0,0 +1,34 @@ +contract Flow { + bool public success; + + mapping(address => function() internal) stages; + + function stage0() internal { + stages[msg.sender] = stage1; + } + + function stage1() internal { + stages[msg.sender] = stage2; + } + + function stage2() internal { + success = true; + } + + constructor() public { + stages[msg.sender] = stage0; + } + + function f() public returns (uint256) { + stages[msg.sender](); + return 7; + } +} + +// ---- +// success() -> false +// f() -> 7 +// f() -> 7 +// success() -> false +// f() -> 7 +// success() -> true diff --git a/test/libsolidity/semanticTests/functionTypes/pass_function_types_externally.sol b/test/libsolidity/semanticTests/functionTypes/pass_function_types_externally.sol new file mode 100644 index 000000000..ebef9a254 --- /dev/null +++ b/test/libsolidity/semanticTests/functionTypes/pass_function_types_externally.sol @@ -0,0 +1,21 @@ +contract C { + function f(uint256 x) public returns (uint256) { + return this.eval(this.g, x); + } + + function f2(uint256 x) public returns (uint256) { + return eval(this.g, x); + } + + function eval(function(uint) external returns (uint) x, uint a) public returns (uint) { + return x(a); + } + + function g(uint256 x) public returns (uint256) { + return x + 1; + } +} + +// ---- +// f(uint256): 7 -> 8 +// f2(uint256): 7 -> 8 diff --git a/test/libsolidity/semanticTests/functionTypes/pass_function_types_internally.sol b/test/libsolidity/semanticTests/functionTypes/pass_function_types_internally.sol new file mode 100644 index 000000000..6fb4f5f6e --- /dev/null +++ b/test/libsolidity/semanticTests/functionTypes/pass_function_types_internally.sol @@ -0,0 +1,16 @@ +contract C { + function f(uint256 x) public returns (uint256) { + return eval(g, x); + } + + function eval(function(uint) internal returns (uint) x, uint a) internal returns (uint) { + return x(a); + } + + function g(uint256 x) public returns (uint256) { + return x + 1; + } +} + +// ---- +// f(uint256): 7 -> 8 diff --git a/test/libsolidity/semanticTests/functionTypes/same_function_in_construction_and_runtime.sol b/test/libsolidity/semanticTests/functionTypes/same_function_in_construction_and_runtime.sol new file mode 100644 index 000000000..a79cb2d76 --- /dev/null +++ b/test/libsolidity/semanticTests/functionTypes/same_function_in_construction_and_runtime.sol @@ -0,0 +1,19 @@ +contract C { + uint256 public initial; + + constructor() public { + initial = double(2); + } + + function double(uint256 _arg) public returns (uint256 _ret) { + _ret = _arg * 2; + } + + function runtime(uint256 _arg) public returns (uint256) { + return double(_arg); + } +} + +// ---- +// runtime(uint256): 3 -> 6 +// initial() -> 4 diff --git a/test/libsolidity/semanticTests/functionTypes/same_function_in_construction_and_runtime_equality_check.sol b/test/libsolidity/semanticTests/functionTypes/same_function_in_construction_and_runtime_equality_check.sol new file mode 100644 index 000000000..f8230b21a --- /dev/null +++ b/test/libsolidity/semanticTests/functionTypes/same_function_in_construction_and_runtime_equality_check.sol @@ -0,0 +1,18 @@ +contract C { + function(uint256) returns (uint256) internal x; + + constructor() public { + x = double; + } + + function test() public returns (bool) { + return x == double; + } + + function double(uint256 _arg) public returns (uint256 _ret) { + _ret = _arg * 2; + } +} + +// ---- +// test() -> true diff --git a/test/libsolidity/semanticTests/functionTypes/store_function.sol b/test/libsolidity/semanticTests/functionTypes/store_function.sol new file mode 100644 index 000000000..a09404fce --- /dev/null +++ b/test/libsolidity/semanticTests/functionTypes/store_function.sol @@ -0,0 +1,28 @@ +contract Other { + function addTwo(uint256 x) public returns (uint256) { + return x + 2; + } +} + + +contract C { + function (function (uint) external returns (uint)) internal returns (uint) ev; + function (uint) external returns (uint) x; + + function store(function(uint) external returns (uint) y) public { + x = y; + } + + function eval(function(uint) external returns (uint) y) public returns (uint) { + return y(7); + } + + function t() public returns (uint256) { + ev = eval; + this.store((new Other()).addTwo); + return ev(x); + } +} + +// ---- +// t() -> 9 diff --git a/test/libsolidity/semanticTests/functionTypes/uninitialized_internal_storage_function_call.sol b/test/libsolidity/semanticTests/functionTypes/uninitialized_internal_storage_function_call.sol new file mode 100644 index 000000000..ca1055fd6 --- /dev/null +++ b/test/libsolidity/semanticTests/functionTypes/uninitialized_internal_storage_function_call.sol @@ -0,0 +1,11 @@ +contract Test { + function() internal x; + + function f() public returns (uint256 r) { + x(); + return 2; + } +} + +// ---- +// f() -> FAILURE diff --git a/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_embedded_function_call.sol b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_embedded_function_call.sol new file mode 100644 index 000000000..3d31c1add --- /dev/null +++ b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_embedded_function_call.sol @@ -0,0 +1,27 @@ +contract C { + function f() public { + assembly { + let d:= 0x10 + + function asmfun(a, b, c) - > x, y, z { + x := g(a) + function g(r) - > s { + s := mul(r, r) + } + y := g(b) + z := 7 + } + let a1, b1, c1 := asmfun(1, 2, 3) + mstore(0x00, a1) + mstore(0x20, b1) + mstore(0x40, c1) + mstore(0x60, d) + return (0, 0x80) + } + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> 0x1, 0x4, 0x7, 0x10 diff --git a/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_for.sol b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_for.sol new file mode 100644 index 000000000..451ecbbe5 --- /dev/null +++ b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_for.sol @@ -0,0 +1,26 @@ +contract C { + function f(uint256 a) public returns (uint256 b) { + assembly { + function fac(n) -> nf { + nf := 1 + for { + let i := n + } gt(i, 0) { + i := sub(i, 1) + } { + nf := mul(nf, i) + } + } + b := fac(a) + } + } +} + +// ==== +// compileViaYul: also +// ---- +// f(uint256): 0 -> 1 +// f(uint256): 1 -> 1 +// f(uint256): 2 -> 2 +// f(uint256): 3 -> 6 +// f(uint256): 4 -> 24 diff --git a/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_for2.sol b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_for2.sol new file mode 100644 index 000000000..2c05f1556 --- /dev/null +++ b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_for2.sol @@ -0,0 +1,29 @@ +contract C { + uint256 st; + + function f(uint256 a) public returns (uint256 b, uint256 c, uint256 d) { + st = 0; + assembly { + function sideeffect(r) -> x { + sstore(0, add(sload(0), r)) + x := 1 + } + for { + let i := a + } eq(i, sideeffect(2)) { + d := add(d, 3) + } { + b := i + i := 0 + } + } + c = st; + } +} + +// ==== +// compileViaYul: also +// ---- +// f(uint256): 0 -> 0, 2, 0 +// f(uint256): 1 -> 1, 4, 3 +// f(uint256): 2 -> 0, 2, 0 diff --git a/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_function_call.sol b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_function_call.sol new file mode 100644 index 000000000..17a271d5b --- /dev/null +++ b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_function_call.sol @@ -0,0 +1,21 @@ +contract C { + function f() public { + assembly { + function asmfun(a, b, c) - > x, y, z { + x := a + y := b + z := 7 + } + let a1, b1, c1 := asmfun(1, 2, 3) + mstore(0x00, a1) + mstore(0x20, b1) + mstore(0x40, c1) + return (0, 0x60) + } + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> 1, 2, 7 diff --git a/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_function_call2.sol b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_function_call2.sol new file mode 100644 index 000000000..26d3d43b7 --- /dev/null +++ b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_function_call2.sol @@ -0,0 +1,24 @@ +contract C { + function f() public { + assembly { + let d := 0x10 + + function asmfun(a, b, c) - > x, y, z { + x := a + y := b + z := 7 + } + let a1, b1, c1 := asmfun(1, 2, 3) + mstore(0x00, a1) + mstore(0x20, b1) + mstore(0x40, c1) + mstore(0x60, d) + return (0, 0x80) + } + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> 0x1, 0x2, 0x7, 0x10 diff --git a/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_function_call_assignment.sol b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_function_call_assignment.sol new file mode 100644 index 000000000..2dec9761b --- /dev/null +++ b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_function_call_assignment.sol @@ -0,0 +1,23 @@ +contract C { + function f() public { + assembly { + let a1, b1, c1 + + function asmfun(a, b, c) - > x, y, z { + x := a + y := b + z := 7 + } + a1, b1, c1 := asmfun(1, 2, 3) + mstore(0x00, a1) + mstore(0x20, b1) + mstore(0x40, c1) + return (0, 0x60) + } + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> 1, 2, 7 diff --git a/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_if.sol b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_if.sol new file mode 100644 index 000000000..9f94f3c19 --- /dev/null +++ b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_if.sol @@ -0,0 +1,17 @@ +contract C { + function f(uint256 a) public returns (uint256 b) { + assembly { + if gt(a, 1) { + b := 2 + } + } + } +} + +// ==== +// compileViaYul: also +// ---- +// f(uint256): 0 -> 0 +// f(uint256): 1 -> 0 +// f(uint256): 2 -> 2 +// f(uint256): 3 -> 2 diff --git a/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_in_modifiers.sol b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_in_modifiers.sol new file mode 100644 index 000000000..3c9f3a2f3 --- /dev/null +++ b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_in_modifiers.sol @@ -0,0 +1,19 @@ +contract C { + modifier m { + uint256 a = 1; + assembly { + a := 2 + } + if (a != 2) revert(); + _; + } + + function f() public m returns (bool) { + return true; + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> true diff --git a/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_memory_access.sol b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_memory_access.sol new file mode 100644 index 000000000..b43b5f611 --- /dev/null +++ b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_memory_access.sol @@ -0,0 +1,13 @@ +contract C { + function test() public returns (bytes memory) { + bytes memory x = new bytes(5); + for (uint256 i = 0; i < x.length; ++i) x[i] = bytes1(uint8(i + 1)); + assembly { + mstore(add(x, 32), "12345678901234567890123456789012") + } + return x; + } +} + +// ---- +// test() -> 0x20, 0x5, "12345" diff --git a/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_read_and_write_stack.sol b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_read_and_write_stack.sol new file mode 100644 index 000000000..c48d74967 --- /dev/null +++ b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_read_and_write_stack.sol @@ -0,0 +1,13 @@ +contract C { + function f() public returns (uint256 r) { + for (uint256 x = 0; x < 10; ++x) + assembly { + r := add(r, x) + } + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> 45 diff --git a/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_recursion.sol b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_recursion.sol new file mode 100644 index 000000000..a5e3c4675 --- /dev/null +++ b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_recursion.sol @@ -0,0 +1,28 @@ +contract C { + function f(uint256 a) public returns (uint256 b) { + assembly { + function fac(n) -> nf { + switch n + case 0 { + nf := 1 + } + case 1 { + nf := 1 + } + default { + nf := mul(n, fac(sub(n, 1))) + } + } + b := fac(a) + } + } +} + +// ==== +// compileViaYul: also +// ---- +// f(uint256): 0 -> 1 +// f(uint256): 1 -> 1 +// f(uint256): 2 -> 2 +// f(uint256): 3 -> 6 +// f(uint256): 4 -> 24 diff --git a/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_storage_access.sol b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_storage_access.sol new file mode 100644 index 000000000..823afe2bd --- /dev/null +++ b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_storage_access.sol @@ -0,0 +1,22 @@ +contract C { + uint16 x; + uint16 public y; + uint256 public z; + + function f() public returns (bool) { + uint256 off1; + uint256 off2; + assembly { + sstore(z_slot, 7) + off1 := z_offset + off2 := y_offset + } + assert(off1 == 0); + assert(off2 == 2); + return true; + } +} + +// ---- +// f() -> true +// z() -> 7 diff --git a/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_storage_access_inside_function.sol b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_storage_access_inside_function.sol new file mode 100644 index 000000000..ce56dbaa1 --- /dev/null +++ b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_storage_access_inside_function.sol @@ -0,0 +1,23 @@ +contract C { + uint16 x; + uint16 public y; + uint256 public z; + + function f() public returns (bool) { + uint256 off1; + uint256 off2; + assembly { + function f() -> o1 { + sstore(z_slot, 7) + o1 := y_offset + } + off2 := f() + } + assert(off2 == 2); + return true; + } +} + +// ---- +// f() -> true +// z() -> 7 diff --git a/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_storage_access_via_pointer.sol b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_storage_access_via_pointer.sol new file mode 100644 index 000000000..3893c8e89 --- /dev/null +++ b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_storage_access_via_pointer.sol @@ -0,0 +1,25 @@ +contract C { + struct Data { + uint256 contents; + } + uint256 public separator; + Data public a; + uint256 public separator2; + + function f() public returns (bool) { + Data storage x = a; + uint256 off; + assembly { + sstore(x_slot, 7) + off := x_offset + } + assert(off == 0); + return true; + } +} + +// ---- +// f() -> true +// a() -> 7 +// separator() -> 0 +// separator2() -> 0 diff --git a/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_switch.sol b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_switch.sol new file mode 100644 index 000000000..9b9a76109 --- /dev/null +++ b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_switch.sol @@ -0,0 +1,24 @@ +contract C { + function f(uint256 a) public returns (uint256 b) { + assembly { + switch a + case 1 { + b := 8 + } + case 2 { + b := 9 + } + default { + b := 2 + } + } + } +} + +// ==== +// compileViaYul: also +// ---- +// f(uint256): 0 -> 2 +// f(uint256): 1 -> 8 +// f(uint256): 2 -> 9 +// f(uint256): 3 -> 2 diff --git a/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_write_to_stack.sol b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_write_to_stack.sol new file mode 100644 index 000000000..fa981fbd3 --- /dev/null +++ b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_write_to_stack.sol @@ -0,0 +1,13 @@ +contract C { + function f() public returns (uint256 r, bytes32 r2) { + assembly { + r := 7 + r2 := "abcdef" + } + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> 7, "abcdef" diff --git a/test/libsolidity/semanticTests/inlineAssembly/inlineasm_empty_let.sol b/test/libsolidity/semanticTests/inlineAssembly/inlineasm_empty_let.sol new file mode 100644 index 000000000..250e0ce8a --- /dev/null +++ b/test/libsolidity/semanticTests/inlineAssembly/inlineasm_empty_let.sol @@ -0,0 +1,15 @@ +contract C { + function f() public pure returns (uint a, uint b) { + assembly { + let x + let y, z + a := x + b := z + } + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> 0, 0 diff --git a/test/libsolidity/semanticTests/inlineAssembly/keccak256_assembly.sol b/test/libsolidity/semanticTests/inlineAssembly/keccak256_assembly.sol new file mode 100644 index 000000000..d4034f10b --- /dev/null +++ b/test/libsolidity/semanticTests/inlineAssembly/keccak256_assembly.sol @@ -0,0 +1,12 @@ +contract C { + function f() public pure returns (bytes32 ret) { + assembly { + ret := keccak256(0, 0) + } + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 diff --git a/test/libsolidity/semanticTests/intheritance/access_base_storage.sol b/test/libsolidity/semanticTests/intheritance/access_base_storage.sol new file mode 100644 index 000000000..a083ccd98 --- /dev/null +++ b/test/libsolidity/semanticTests/intheritance/access_base_storage.sol @@ -0,0 +1,30 @@ +contract Base { + uint256 dataBase; + + function getViaBase() public returns (uint256 i) { + return dataBase; + } +} + + +contract Derived is Base { + uint256 dataDerived; + + function setData(uint256 base, uint256 derived) public returns (bool r) { + dataBase = base; + dataDerived = derived; + return true; + } + + function getViaDerived() public returns (uint256 base, uint256 derived) { + base = dataBase; + derived = dataDerived; + } +} + +// ==== +// compileViaYul: also +// ---- +// setData(uint256,uint256): 1, 2 -> true +// getViaBase() -> 1 +// getViaDerived() -> 1, 2 diff --git a/test/libsolidity/semanticTests/intheritance/address_overload_resolution.sol b/test/libsolidity/semanticTests/intheritance/address_overload_resolution.sol new file mode 100644 index 000000000..9b68cc154 --- /dev/null +++ b/test/libsolidity/semanticTests/intheritance/address_overload_resolution.sol @@ -0,0 +1,24 @@ +contract C { + function balance() public returns (uint256) { + return 1; + } + + function transfer(uint256 amount) public returns (uint256) { + return amount; + } +} + + +contract D { + function f() public returns (uint256) { + return (new C()).balance(); + } + + function g() public returns (uint256) { + return (new C()).transfer(5); + } +} + +// ---- +// f() -> 1 +// g() -> 5 diff --git a/test/libsolidity/semanticTests/intheritance/base_access_to_function_type_variables.sol b/test/libsolidity/semanticTests/intheritance/base_access_to_function_type_variables.sol new file mode 100644 index 000000000..753e9bd1e --- /dev/null +++ b/test/libsolidity/semanticTests/intheritance/base_access_to_function_type_variables.sol @@ -0,0 +1,21 @@ +contract C { + function() returns (uint256) internal x; + + function set() public { + C.x = g; + } + + function g() public pure returns (uint256) { + return 2; + } + + function h() public returns (uint256) { + return C.x(); + } +} + +// ---- +// g() -> 2 +// h() -> FAILURE +// set() -> +// h() -> 2 diff --git a/test/libsolidity/semanticTests/intheritance/derived_overload_base_function_direct.sol b/test/libsolidity/semanticTests/intheritance/derived_overload_base_function_direct.sol new file mode 100644 index 000000000..5628501d9 --- /dev/null +++ b/test/libsolidity/semanticTests/intheritance/derived_overload_base_function_direct.sol @@ -0,0 +1,21 @@ +contract B { + function f() public returns (uint256) { + return 10; + } +} + + +contract C is B { + function f(uint256 i) public returns (uint256) { + return 2 * i; + } + + function g() public returns (uint256) { + return f(1); + } +} + +// ==== +// compileViaYul: also +// ---- +// g() -> 2 diff --git a/test/libsolidity/semanticTests/intheritance/derived_overload_base_function_indirect.sol b/test/libsolidity/semanticTests/intheritance/derived_overload_base_function_indirect.sol new file mode 100644 index 000000000..949024f43 --- /dev/null +++ b/test/libsolidity/semanticTests/intheritance/derived_overload_base_function_indirect.sol @@ -0,0 +1,29 @@ +contract A { + function f(uint256 a) public returns (uint256) { + return 2 * a; + } +} + + +contract B { + function f() public returns (uint256) { + return 10; + } +} + + +contract C is A, B { + function g() public returns (uint256) { + return f(); + } + + function h() public returns (uint256) { + return f(1); + } +} + +// ==== +// compileViaYul: also +// ---- +// g() -> 10 +// h() -> 2 diff --git a/test/libsolidity/semanticTests/intheritance/explicit_base_class.sol b/test/libsolidity/semanticTests/intheritance/explicit_base_class.sol new file mode 100644 index 000000000..44553b3f1 --- /dev/null +++ b/test/libsolidity/semanticTests/intheritance/explicit_base_class.sol @@ -0,0 +1,27 @@ +contract BaseBase { + function g() public virtual returns (uint256 r) { + return 1; + } +} + + +contract Base is BaseBase { + function g() public virtual override returns (uint256 r) { + return 2; + } +} + + +contract Derived is Base { + function f() public returns (uint256 r) { + return BaseBase.g(); + } + + function g() public override returns (uint256 r) { + return 3; + } +} + +// ---- +// g() -> 3 +// f() -> 1 diff --git a/test/libsolidity/semanticTests/intheritance/inherited_constant_state_var.sol b/test/libsolidity/semanticTests/intheritance/inherited_constant_state_var.sol new file mode 100644 index 000000000..e25db0dcb --- /dev/null +++ b/test/libsolidity/semanticTests/intheritance/inherited_constant_state_var.sol @@ -0,0 +1,13 @@ +contract A { + uint256 constant x = 7; +} + + +contract B is A { + function f() public returns (uint256) { + return A.x; + } +} + +// ---- +// f() -> 7 diff --git a/test/libsolidity/semanticTests/intheritance/inherited_function.sol b/test/libsolidity/semanticTests/intheritance/inherited_function.sol new file mode 100644 index 000000000..23f9bee37 --- /dev/null +++ b/test/libsolidity/semanticTests/intheritance/inherited_function.sol @@ -0,0 +1,19 @@ +contract A { + function f() internal virtual returns (uint256) { + return 1; + } +} + + +contract B is A { + function f() internal override returns (uint256) { + return 2; + } + + function g() public returns (uint256) { + return A.f(); + } +} + +// ---- +// g() -> 1 diff --git a/test/libsolidity/semanticTests/intheritance/inherited_function_calldata_calldata_interface.sol b/test/libsolidity/semanticTests/intheritance/inherited_function_calldata_calldata_interface.sol new file mode 100644 index 000000000..9812ca520 --- /dev/null +++ b/test/libsolidity/semanticTests/intheritance/inherited_function_calldata_calldata_interface.sol @@ -0,0 +1,25 @@ +interface I { + function f(uint256[] calldata a) external returns (uint256); +} + + +contract A is I { + function f(uint256[] calldata a) external override returns (uint256) { + return 42; + } +} + + +contract B { + function f(uint256[] memory a) public returns (uint256) { + return a[1]; + } + + function g() public returns (uint256) { + I i = I(new A()); + return i.f(new uint256[](2)); + } +} + +// ---- +// g() -> 42 diff --git a/test/libsolidity/semanticTests/intheritance/inherited_function_calldata_memory.sol b/test/libsolidity/semanticTests/intheritance/inherited_function_calldata_memory.sol new file mode 100644 index 000000000..0fd02e8f3 --- /dev/null +++ b/test/libsolidity/semanticTests/intheritance/inherited_function_calldata_memory.sol @@ -0,0 +1,22 @@ +contract A { + function f(uint256[] calldata a) external virtual returns (uint256) { + return a[0]; + } +} + + +contract B is A { + function f(uint256[] memory a) public override returns (uint256) { + return a[1]; + } + + function g() public returns (uint256) { + uint256[] memory m = new uint256[](2); + m[0] = 42; + m[1] = 23; + return A(this).f(m); + } +} + +// ---- +// g() -> 23 diff --git a/test/libsolidity/semanticTests/intheritance/inherited_function_calldata_memory_interface.sol b/test/libsolidity/semanticTests/intheritance/inherited_function_calldata_memory_interface.sol new file mode 100644 index 000000000..9a2c1a1e7 --- /dev/null +++ b/test/libsolidity/semanticTests/intheritance/inherited_function_calldata_memory_interface.sol @@ -0,0 +1,25 @@ +interface I { + function f(uint256[] calldata a) external returns (uint256); +} + + +contract A is I { + function f(uint256[] memory a) public override returns (uint256) { + return 42; + } +} + + +contract B { + function f(uint256[] memory a) public returns (uint256) { + return a[1]; + } + + function g() public returns (uint256) { + I i = I(new A()); + return i.f(new uint256[](2)); + } +} + +// ---- +// g() -> 42 diff --git a/test/libsolidity/semanticTests/intheritance/inherited_function_from_a_library.sol b/test/libsolidity/semanticTests/intheritance/inherited_function_from_a_library.sol new file mode 100644 index 000000000..42d4f711c --- /dev/null +++ b/test/libsolidity/semanticTests/intheritance/inherited_function_from_a_library.sol @@ -0,0 +1,19 @@ +library A { + function f() internal returns (uint256) { + return 1; + } +} + + +contract B { + function f() internal returns (uint256) { + return 2; + } + + function g() public returns (uint256) { + return A.f(); + } +} + +// ---- +// g() -> 1 diff --git a/test/libsolidity/semanticTests/intheritance/overloaded_function_call_resolve_to_first.sol b/test/libsolidity/semanticTests/intheritance/overloaded_function_call_resolve_to_first.sol new file mode 100644 index 000000000..7f65eb4ad --- /dev/null +++ b/test/libsolidity/semanticTests/intheritance/overloaded_function_call_resolve_to_first.sol @@ -0,0 +1,18 @@ +contract test { + function f(uint256 k) public returns (uint256 d) { + return k; + } + + function f(uint256 a, uint256 b) public returns (uint256 d) { + return a + b; + } + + function g() public returns (uint256 d) { + return f(3); + } +} + +// ==== +// compileViaYul: also +// ---- +// g() -> 3 diff --git a/test/libsolidity/semanticTests/intheritance/overloaded_function_call_resolve_to_second.sol b/test/libsolidity/semanticTests/intheritance/overloaded_function_call_resolve_to_second.sol new file mode 100644 index 000000000..bee0e8fa5 --- /dev/null +++ b/test/libsolidity/semanticTests/intheritance/overloaded_function_call_resolve_to_second.sol @@ -0,0 +1,18 @@ +contract test { + function f(uint256 a, uint256 b) public returns (uint256 d) { + return a + b; + } + + function f(uint256 k) public returns (uint256 d) { + return k; + } + + function g() public returns (uint256 d) { + return f(3, 7); + } +} + +// ==== +// compileViaYul: also +// ---- +// g() -> 10 diff --git a/test/libsolidity/semanticTests/intheritance/overloaded_function_call_with_if_else.sol b/test/libsolidity/semanticTests/intheritance/overloaded_function_call_with_if_else.sol new file mode 100644 index 000000000..df437a32c --- /dev/null +++ b/test/libsolidity/semanticTests/intheritance/overloaded_function_call_with_if_else.sol @@ -0,0 +1,20 @@ +contract test { + function f(uint256 a, uint256 b) public returns (uint256 d) { + return a + b; + } + + function f(uint256 k) public returns (uint256 d) { + return k; + } + + function g(bool flag) public returns (uint256 d) { + if (flag) return f(3); + else return f(3, 7); + } +} + +// ==== +// compileViaYul: also +// ---- +// g(bool): true -> 3 +// g(bool): false -> 10 diff --git a/test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base.sol b/test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base.sol new file mode 100644 index 000000000..26de9ce70 --- /dev/null +++ b/test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base.sol @@ -0,0 +1,18 @@ +contract Base { + constructor(uint256 i) public { + m_i = i; + } + + uint256 public m_i; +} + + +contract Derived is Base { + constructor(uint256 i) public Base(i) {} +} + + +contract Final is Derived(4) {} + +// ---- +// m_i() -> 4 diff --git a/test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base_base.sol b/test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base_base.sol new file mode 100644 index 000000000..6349bd814 --- /dev/null +++ b/test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base_base.sol @@ -0,0 +1,23 @@ +contract Base { + constructor(uint256 j) public { + m_i = j; + } + + uint256 public m_i; +} + + +contract Base1 is Base { + constructor(uint256 k) public Base(k) {} +} + + +contract Derived is Base, Base1 { + constructor(uint256 i) public Base1(i) {} +} + + +contract Final is Derived(4) {} + +// ---- +// m_i() -> 4 diff --git a/test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base_base_with_gap.sol b/test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base_base_with_gap.sol new file mode 100644 index 000000000..4556cf5c4 --- /dev/null +++ b/test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base_base_with_gap.sol @@ -0,0 +1,23 @@ +contract Base { + constructor(uint256 i) public { + m_i = i; + } + + uint256 public m_i; +} + + +abstract contract Base1 is Base { + constructor(uint256 k) public {} +} + + +contract Derived is Base, Base1 { + constructor(uint256 i) public Base(i) Base1(7) {} +} + + +contract Final is Derived(4) {} + +// ---- +// m_i() -> 4 diff --git a/test/libsolidity/semanticTests/intheritance/super_in_constructor.sol b/test/libsolidity/semanticTests/intheritance/super_in_constructor.sol new file mode 100644 index 000000000..33e270c9e --- /dev/null +++ b/test/libsolidity/semanticTests/intheritance/super_in_constructor.sol @@ -0,0 +1,35 @@ +contract A { + function f() public virtual returns (uint256 r) { + return 1; + } +} + + +contract B is A { + function f() public virtual override returns (uint256 r) { + return super.f() | 2; + } +} + + +contract C is A { + function f() public virtual override returns (uint256 r) { + return super.f() | 4; + } +} + + +contract D is B, C { + uint256 data; + + constructor() public { + data = super.f() | 8; + } + + function f() public override (B, C) returns (uint256 r) { + return data; + } +} + +// ---- +// f() -> 15 diff --git a/test/libsolidity/semanticTests/intheritance/super_overload.sol b/test/libsolidity/semanticTests/intheritance/super_overload.sol new file mode 100644 index 000000000..6a1f6dc3d --- /dev/null +++ b/test/libsolidity/semanticTests/intheritance/super_overload.sol @@ -0,0 +1,27 @@ +contract A { + function f(uint256 a) public returns (uint256) { + return 2 * a; + } +} + + +contract B { + function f(bool b) public returns (uint256) { + return 10; + } +} + + +contract C is A, B { + function g() public returns (uint256) { + return super.f(true); + } + + function h() public returns (uint256) { + return super.f(1); + } +} + +// ---- +// g() -> 10 +// h() -> 2 diff --git a/test/libsolidity/semanticTests/intheritance/value_for_constructor.sol b/test/libsolidity/semanticTests/intheritance/value_for_constructor.sol new file mode 100644 index 000000000..5cd0bc177 --- /dev/null +++ b/test/libsolidity/semanticTests/intheritance/value_for_constructor.sol @@ -0,0 +1,45 @@ +contract Helper { + bytes3 name; + bool flag; + + constructor(bytes3 x, bool f) public payable { + name = x; + flag = f; + } + + function getName() public returns (bytes3 ret) { + return name; + } + + function getFlag() public returns (bool ret) { + return flag; + } +} + + +contract Main { + Helper h; + + constructor() public payable { + h = (new Helper).value(10)("abc", true); + } + + function getFlag() public returns (bool ret) { + return h.getFlag(); + } + + function getName() public returns (bytes3 ret) { + return h.getName(); + } + + function getBalances() public returns (uint256 me, uint256 them) { + me = address(this).balance; + them = address(h).balance; + } +} + +// ---- +// constructor(), 22 wei -> +// getFlag() -> true +// getName() -> "abc" +// getBalances() -> 12, 10 diff --git a/test/libsolidity/semanticTests/libraries/internal_library_function.sol b/test/libsolidity/semanticTests/libraries/internal_library_function.sol new file mode 100644 index 000000000..a3c8a8700 --- /dev/null +++ b/test/libsolidity/semanticTests/libraries/internal_library_function.sol @@ -0,0 +1,21 @@ +// tests that internal library functions can be called from outside +// and retain the same memory context (i.e. are pulled into the caller's code) +// This has to work without linking, because everything will be inlined. +library L { + function f(uint256[] memory _data) internal { + _data[3] = 2; + } +} + + +contract C { + function f() public returns (uint256) { + uint256[] memory x = new uint256[](7); + x[3] = 8; + L.f(x); + return x[3]; + } +} + +// ---- +// f() -> 2 diff --git a/test/libsolidity/semanticTests/libraries/internal_library_function_bound.sol b/test/libsolidity/semanticTests/libraries/internal_library_function_bound.sol new file mode 100644 index 000000000..f59ec9440 --- /dev/null +++ b/test/libsolidity/semanticTests/libraries/internal_library_function_bound.sol @@ -0,0 +1,26 @@ +// This has to work without linking, because everything will be inlined. +library L { + struct S { + uint256[] data; + } + + function f(S memory _s) internal { + _s.data[3] = 2; + } +} + + +contract C { + using L for L.S; + + function f() public returns (uint256) { + L.S memory x; + x.data = new uint256[](7); + x.data[3] = 8; + x.f(); + return x.data[3]; + } +} + +// ---- +// f() -> 2 diff --git a/test/libsolidity/semanticTests/libraries/internal_library_function_calling_private.sol b/test/libsolidity/semanticTests/libraries/internal_library_function_calling_private.sol new file mode 100644 index 000000000..2283c30ff --- /dev/null +++ b/test/libsolidity/semanticTests/libraries/internal_library_function_calling_private.sol @@ -0,0 +1,26 @@ +// tests that internal library functions that are called from outside and that +// themselves call private functions are still able to (i.e. the private function +// also has to be pulled into the caller's code) +// This has to work without linking, because everything will be inlined. +library L { + function g(uint256[] memory _data) private { + _data[3] = 2; + } + + function f(uint256[] memory _data) internal { + g(_data); + } +} + + +contract C { + function f() public returns (uint256) { + uint256[] memory x = new uint256[](7); + x[3] = 8; + L.f(x); + return x[3]; + } +} + +// ---- +// f() -> 2 diff --git a/test/libsolidity/semanticTests/libraries/internal_library_function_return_var_size.sol b/test/libsolidity/semanticTests/libraries/internal_library_function_return_var_size.sol new file mode 100644 index 000000000..21417b599 --- /dev/null +++ b/test/libsolidity/semanticTests/libraries/internal_library_function_return_var_size.sol @@ -0,0 +1,26 @@ +// This has to work without linking, because everything will be inlined. +library L { + struct S { + uint256[] data; + } + + function f(S memory _s) internal returns (uint256[] memory) { + _s.data[3] = 2; + return _s.data; + } +} + + +contract C { + using L for L.S; + + function f() public returns (uint256) { + L.S memory x; + x.data = new uint256[](7); + x.data[3] = 8; + return x.f()[3]; + } +} + +// ---- +// f() -> 2 diff --git a/test/libsolidity/semanticTests/libraries/library_enum_as_an_expression.sol b/test/libsolidity/semanticTests/libraries/library_enum_as_an_expression.sol new file mode 100644 index 000000000..f24d93c2d --- /dev/null +++ b/test/libsolidity/semanticTests/libraries/library_enum_as_an_expression.sol @@ -0,0 +1,14 @@ +library Arst { + enum Foo {Things, Stuff} +} + + +contract Tsra { + function f() public returns (uint256) { + Arst.Foo; + return 1; + } +} + +// ---- +// f() -> 1 diff --git a/test/libsolidity/semanticTests/libraries/library_struct_as_an_expression.sol b/test/libsolidity/semanticTests/libraries/library_struct_as_an_expression.sol new file mode 100644 index 000000000..d7df52434 --- /dev/null +++ b/test/libsolidity/semanticTests/libraries/library_struct_as_an_expression.sol @@ -0,0 +1,17 @@ +library Arst { + struct Foo { + int256 Things; + int256 Stuff; + } +} + + +contract Tsra { + function f() public returns (uint256) { + Arst.Foo; + return 1; + } +} + +// ---- +// f() -> 1 diff --git a/test/libsolidity/semanticTests/literals/scientific_notation.sol b/test/libsolidity/semanticTests/literals/scientific_notation.sol new file mode 100644 index 000000000..e79fca70b --- /dev/null +++ b/test/libsolidity/semanticTests/literals/scientific_notation.sol @@ -0,0 +1,36 @@ +contract C { + function f() public returns(uint) { + return 2e10 wei; + } + + function g() public returns(uint) { + return 200e-2 wei; + } + + function h() public returns(uint) { + return 2.5e1; + } + + function i() public returns(int) { + return -2e10; + } + + function j() public returns(int) { + return -200e-2; + } + + function k() public returns(int) { + return -2.5e1; + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> 20000000000 +// g() -> 2 +// h() -> 25 +// i() -> -20000000000 +// j() -> -2 +// k() -> -25 + diff --git a/test/libsolidity/semanticTests/modifiers/break_in_modifier.sol b/test/libsolidity/semanticTests/modifiers/break_in_modifier.sol new file mode 100644 index 000000000..1d1036c2c --- /dev/null +++ b/test/libsolidity/semanticTests/modifiers/break_in_modifier.sol @@ -0,0 +1,20 @@ +contract C { + uint256 public x; + modifier run() { + for (uint256 i = 0; i < 10; i++) { + _; + break; + } + } + + function f() public run { + uint256 k = x; + uint256 t = k + 1; + x = t; + } +} + +// ---- +// x() -> 0 +// f() -> +// x() -> 1 diff --git a/test/libsolidity/semanticTests/modifiers/continue_in_modifier.sol b/test/libsolidity/semanticTests/modifiers/continue_in_modifier.sol new file mode 100644 index 000000000..1db0f2e9f --- /dev/null +++ b/test/libsolidity/semanticTests/modifiers/continue_in_modifier.sol @@ -0,0 +1,20 @@ +contract C { + uint256 public x; + modifier run() { + for (uint256 i = 0; i < 10; i++) { + if (i % 2 == 1) continue; + _; + } + } + + function f() public run { + uint256 k = x; + uint256 t = k + 1; + x = t; + } +} + +// ---- +// x() -> 0 +// f() -> +// x() -> 5 diff --git a/test/libsolidity/semanticTests/modifiers/function_modifier.sol b/test/libsolidity/semanticTests/modifiers/function_modifier.sol new file mode 100644 index 000000000..fcb8f64a2 --- /dev/null +++ b/test/libsolidity/semanticTests/modifiers/function_modifier.sol @@ -0,0 +1,13 @@ +contract C { + function getOne() public payable nonFree returns (uint256 r) { + return 1; + } + + modifier nonFree { + if (msg.value > 0) _; + } +} + +// ---- +// getOne() -> 0 +// getOne(), 1 wei -> 1 diff --git a/test/libsolidity/semanticTests/modifiers/function_modifier_calling_functions_in_creation_context.sol b/test/libsolidity/semanticTests/modifiers/function_modifier_calling_functions_in_creation_context.sol new file mode 100644 index 000000000..f4a73ebeb --- /dev/null +++ b/test/libsolidity/semanticTests/modifiers/function_modifier_calling_functions_in_creation_context.sol @@ -0,0 +1,49 @@ +contract A { + uint256 data; + + constructor() public mod1 { + f1(); + } + + function f1() public mod2 { + data |= 0x1; + } + + function f2() public { + data |= 0x20; + } + + function f3() public virtual {} + + modifier mod1 virtual { + f2(); + _; + } + modifier mod2 { + f3(); + if (false) _; + } + + function getData() public returns (uint256 r) { + return data; + } +} + + +contract C is A { + modifier mod1 override { + f4(); + _; + } + + function f3() public override { + data |= 0x300; + } + + function f4() public { + data |= 0x4000; + } +} + +// ---- +// getData() -> 0x4300 diff --git a/test/libsolidity/semanticTests/modifiers/function_modifier_for_constructor.sol b/test/libsolidity/semanticTests/modifiers/function_modifier_for_constructor.sol new file mode 100644 index 000000000..ac99b0cf7 --- /dev/null +++ b/test/libsolidity/semanticTests/modifiers/function_modifier_for_constructor.sol @@ -0,0 +1,27 @@ +contract A { + uint256 data; + + constructor() public mod1 { + data |= 2; + } + + modifier mod1 virtual { + data |= 1; + _; + } + + function getData() public returns (uint256 r) { + return data; + } +} + + +contract C is A { + modifier mod1 override { + data |= 4; + _; + } +} + +// ---- +// getData() -> 6 diff --git a/test/libsolidity/semanticTests/modifiers/function_modifier_library.sol b/test/libsolidity/semanticTests/modifiers/function_modifier_library.sol new file mode 100644 index 000000000..f10ebb0e7 --- /dev/null +++ b/test/libsolidity/semanticTests/modifiers/function_modifier_library.sol @@ -0,0 +1,28 @@ +library L { + struct S { + uint256 v; + } + modifier mod(S storage s) { + s.v++; + _; + } + + function libFun(S storage s) internal mod(s) { + s.v += 0x100; + } +} + + +contract Test { + using L for *; + L.S s; + + function f() public returns (uint256) { + s.libFun(); + L.libFun(s); + return s.v; + } +} + +// ---- +// f() -> 0x202 diff --git a/test/libsolidity/semanticTests/modifiers/function_modifier_library_inheritance.sol b/test/libsolidity/semanticTests/modifiers/function_modifier_library_inheritance.sol new file mode 100644 index 000000000..3d5e97de0 --- /dev/null +++ b/test/libsolidity/semanticTests/modifiers/function_modifier_library_inheritance.sol @@ -0,0 +1,34 @@ +// Tests that virtual lookup for modifiers in libraries does not consider +// the current inheritance hierarchy. +library L { + struct S { + uint256 v; + } + modifier mod(S storage s) { + s.v++; + _; + } + + function libFun(S storage s) internal mod(s) { + s.v += 0x100; + } +} + + +contract Test { + using L for *; + L.S s; + modifier mod(L.S storage) { + revert(); + _; + } + + function f() public returns (uint256) { + s.libFun(); + L.libFun(s); + return s.v; + } +} + +// ---- +// f() -> 0x202 diff --git a/test/libsolidity/semanticTests/modifiers/function_modifier_local_variables.sol b/test/libsolidity/semanticTests/modifiers/function_modifier_local_variables.sol new file mode 100644 index 000000000..1df8b0874 --- /dev/null +++ b/test/libsolidity/semanticTests/modifiers/function_modifier_local_variables.sol @@ -0,0 +1,19 @@ +contract C { + modifier mod1 { + uint8 a = 1; + uint8 b = 2; + _; + } + modifier mod2(bool a) { + if (a) return; + else _; + } + + function f(bool a) public mod1 mod2(a) returns (uint256 r) { + return 3; + } +} + +// ---- +// f(bool): true -> 0 +// f(bool): false -> 3 diff --git a/test/libsolidity/semanticTests/modifiers/function_modifier_loop.sol b/test/libsolidity/semanticTests/modifiers/function_modifier_loop.sol new file mode 100644 index 000000000..0c4c07828 --- /dev/null +++ b/test/libsolidity/semanticTests/modifiers/function_modifier_loop.sol @@ -0,0 +1,13 @@ +contract C { + modifier repeat(uint256 count) { + uint256 i; + for (i = 0; i < count; ++i) _; + } + + function f() public repeat(10) returns (uint256 r) { + r += 1; + } +} + +// ---- +// f() -> 10 diff --git a/test/libsolidity/semanticTests/modifiers/function_modifier_multi_invocation.sol b/test/libsolidity/semanticTests/modifiers/function_modifier_multi_invocation.sol new file mode 100644 index 000000000..124e15970 --- /dev/null +++ b/test/libsolidity/semanticTests/modifiers/function_modifier_multi_invocation.sol @@ -0,0 +1,14 @@ +contract C { + modifier repeat(bool twice) { + if (twice) _; + _; + } + + function f(bool twice) public repeat(twice) returns (uint256 r) { + r += 1; + } +} + +// ---- +// f(bool): false -> 1 +// f(bool): true -> 2 diff --git a/test/libsolidity/semanticTests/modifiers/function_modifier_multi_with_return.sol b/test/libsolidity/semanticTests/modifiers/function_modifier_multi_with_return.sol new file mode 100644 index 000000000..286476820 --- /dev/null +++ b/test/libsolidity/semanticTests/modifiers/function_modifier_multi_with_return.sol @@ -0,0 +1,17 @@ +// Note that return sets the return variable and jumps to the end of the current function or +// modifier code block. +contract C { + modifier repeat(bool twice) { + if (twice) _; + _; + } + + function f(bool twice) public repeat(twice) returns (uint256 r) { + r += 1; + return r; + } +} + +// ---- +// f(bool): false -> 1 +// f(bool): true -> 2 diff --git a/test/libsolidity/semanticTests/modifiers/function_modifier_multiple_times.sol b/test/libsolidity/semanticTests/modifiers/function_modifier_multiple_times.sol new file mode 100644 index 000000000..722334ec9 --- /dev/null +++ b/test/libsolidity/semanticTests/modifiers/function_modifier_multiple_times.sol @@ -0,0 +1,15 @@ +contract C { + uint256 public a; + modifier mod(uint256 x) { + a += x; + _; + } + + function f(uint256 x) public mod(2) mod(5) mod(x) returns (uint256) { + return a; + } +} + +// ---- +// f(uint256): 3 -> 10 +// a() -> 10 diff --git a/test/libsolidity/semanticTests/modifiers/function_modifier_multiple_times_local_vars.sol b/test/libsolidity/semanticTests/modifiers/function_modifier_multiple_times_local_vars.sol new file mode 100644 index 000000000..64354ba5e --- /dev/null +++ b/test/libsolidity/semanticTests/modifiers/function_modifier_multiple_times_local_vars.sol @@ -0,0 +1,18 @@ +contract C { + uint256 public a; + modifier mod(uint256 x) { + uint256 b = x; + a += b; + _; + a -= b; + assert(b == x); + } + + function f(uint256 x) public mod(2) mod(5) mod(x) returns (uint256) { + return a; + } +} + +// ---- +// f(uint256): 3 -> 10 +// a() -> 0 diff --git a/test/libsolidity/semanticTests/modifiers/function_modifier_overriding.sol b/test/libsolidity/semanticTests/modifiers/function_modifier_overriding.sol new file mode 100644 index 000000000..c91869615 --- /dev/null +++ b/test/libsolidity/semanticTests/modifiers/function_modifier_overriding.sol @@ -0,0 +1,19 @@ +contract A { + function f() public mod returns (bool r) { + return true; + } + + modifier mod virtual { + _; + } +} + + +contract C is A { + modifier mod override { + if (false) _; + } +} + +// ---- +// f() -> false diff --git a/test/libsolidity/semanticTests/modifiers/return_does_not_skip_modifier.sol b/test/libsolidity/semanticTests/modifiers/return_does_not_skip_modifier.sol new file mode 100644 index 000000000..c437922e4 --- /dev/null +++ b/test/libsolidity/semanticTests/modifiers/return_does_not_skip_modifier.sol @@ -0,0 +1,16 @@ +contract C { + uint256 public x; + modifier setsx { + _; + x = 9; + } + + function f() public setsx returns (uint256) { + return 2; + } +} + +// ---- +// x() -> 0 +// f() -> 2 +// x() -> 9 diff --git a/test/libsolidity/semanticTests/modifiers/return_in_modifier.sol b/test/libsolidity/semanticTests/modifiers/return_in_modifier.sol new file mode 100644 index 000000000..81fbd794e --- /dev/null +++ b/test/libsolidity/semanticTests/modifiers/return_in_modifier.sol @@ -0,0 +1,20 @@ +contract C { + uint256 public x; + modifier run() { + for (uint256 i = 1; i < 10; i++) { + if (i == 5) return; + _; + } + } + + function f() public run { + uint256 k = x; + uint256 t = k + 1; + x = t; + } +} + +// ---- +// x() -> 0 +// f() -> +// x() -> 4 diff --git a/test/libsolidity/semanticTests/modifiers/stacked_return_with_modifiers.sol b/test/libsolidity/semanticTests/modifiers/stacked_return_with_modifiers.sol new file mode 100644 index 000000000..1d1036c2c --- /dev/null +++ b/test/libsolidity/semanticTests/modifiers/stacked_return_with_modifiers.sol @@ -0,0 +1,20 @@ +contract C { + uint256 public x; + modifier run() { + for (uint256 i = 0; i < 10; i++) { + _; + break; + } + } + + function f() public run { + uint256 k = x; + uint256 t = k + 1; + x = t; + } +} + +// ---- +// x() -> 0 +// f() -> +// x() -> 1 diff --git a/test/libsolidity/semanticTests/reverts/assert_require.sol b/test/libsolidity/semanticTests/reverts/assert_require.sol new file mode 100644 index 000000000..6bd146a7a --- /dev/null +++ b/test/libsolidity/semanticTests/reverts/assert_require.sol @@ -0,0 +1,24 @@ +contract C { + function f() public { + assert(false); + } + + function g(bool val) public returns (bool) { + assert(val == true); + return true; + } + + function h(bool val) public returns (bool) { + require(val); + return true; + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> FAILURE +// g(bool): false -> FAILURE +// g(bool): true -> true +// h(bool): false -> FAILURE +// h(bool): true -> true diff --git a/test/libsolidity/semanticTests/reverts/invalid_enum_as_external_arg.sol b/test/libsolidity/semanticTests/reverts/invalid_enum_as_external_arg.sol new file mode 100644 index 000000000..d0adf2785 --- /dev/null +++ b/test/libsolidity/semanticTests/reverts/invalid_enum_as_external_arg.sol @@ -0,0 +1,20 @@ +contract C { + enum X {A, B} + + function tested(X x) public returns (uint256) { + return 1; + } + + function test() public returns (uint256) { + X garbled; + + assembly { + garbled := 5 + } + + return this.tested(garbled); + } +} + +// ---- +// test() -> FAILURE # should throw # diff --git a/test/libsolidity/semanticTests/reverts/invalid_enum_as_external_ret.sol b/test/libsolidity/semanticTests/reverts/invalid_enum_as_external_ret.sol new file mode 100644 index 000000000..6bdf14298 --- /dev/null +++ b/test/libsolidity/semanticTests/reverts/invalid_enum_as_external_ret.sol @@ -0,0 +1,32 @@ +contract C { + enum X {A, B} + + function test_return() public returns (X) { + X garbled; + assembly { + garbled := 5 + } + return garbled; + } + + function test_inline_assignment() public returns (X _ret) { + assembly { + _ret := 5 + } + } + + function test_assignment() public returns (X _ret) { + X tmp; + assembly { + tmp := 5 + } + _ret = tmp; + } +} + +// ==== +// compileViaYul: also +// ---- +// test_return() -> FAILURE # both should throw # +// test_inline_assignment() -> FAILURE +// test_assignment() -> FAILURE diff --git a/test/libsolidity/semanticTests/reverts/invalid_enum_compared.sol b/test/libsolidity/semanticTests/reverts/invalid_enum_compared.sol new file mode 100644 index 000000000..17ee32bb8 --- /dev/null +++ b/test/libsolidity/semanticTests/reverts/invalid_enum_compared.sol @@ -0,0 +1,29 @@ +contract C { + enum X {A, B} + + function test_eq() public returns (bool) { + X garbled; + assembly { + garbled := 5 + } + return garbled == garbled; + } + + function test_eq_ok() public returns (bool) { + X garbled = X.A; + return garbled == garbled; + } + + function test_neq() public returns (bool) { + X garbled; + assembly { + garbled := 5 + } + return garbled != garbled; + } +} + +// ---- +// test_eq_ok() -> 1 +// test_eq() -> FAILURE # both should throw # +// test_neq() -> FAILURE diff --git a/test/libsolidity/semanticTests/reverts/invalid_enum_stored.sol b/test/libsolidity/semanticTests/reverts/invalid_enum_stored.sol new file mode 100644 index 000000000..2b90451ec --- /dev/null +++ b/test/libsolidity/semanticTests/reverts/invalid_enum_stored.sol @@ -0,0 +1,23 @@ +contract C { + enum X {A, B} + X public x; + + function test_store() public returns (uint256) { + X garbled = X.A; + assembly { + garbled := 5 + } + x = garbled; + return 1; + } + + function test_store_ok() public returns (uint256) { + x = X.A; + return 1; + } +} + +// ---- +// test_store_ok() -> 1 +// x() -> 0 +// test_store() -> FAILURE # should throw # diff --git a/test/libsolidity/semanticTests/reverts/invalid_instruction.sol b/test/libsolidity/semanticTests/reverts/invalid_instruction.sol new file mode 100644 index 000000000..839296ca1 --- /dev/null +++ b/test/libsolidity/semanticTests/reverts/invalid_instruction.sol @@ -0,0 +1,12 @@ +contract C { + function f() public { + assembly { + invalid() + } + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> FAILURE diff --git a/test/libsolidity/semanticTests/reverts/revert.sol b/test/libsolidity/semanticTests/reverts/revert.sol new file mode 100644 index 000000000..eae49c799 --- /dev/null +++ b/test/libsolidity/semanticTests/reverts/revert.sol @@ -0,0 +1,21 @@ +contract C { + uint256 public a = 42; + + function f() public { + a = 1; + revert(); + } + + function g() public { + a = 1; + assembly { + revert(0, 0) + } + } +} + +// ---- +// f() -> FAILURE +// a() -> 42 +// g() -> FAILURE +// a() -> 42 diff --git a/test/libsolidity/semanticTests/reverts/simple_throw.sol b/test/libsolidity/semanticTests/reverts/simple_throw.sol new file mode 100644 index 000000000..ad88deca6 --- /dev/null +++ b/test/libsolidity/semanticTests/reverts/simple_throw.sol @@ -0,0 +1,11 @@ +contract Test { + function f(uint256 x) public returns (uint256) { + if (x > 10) return x + 10; + else revert(); + return 2; + } +} + +// ---- +// f(uint256): 11 -> 21 +// f(uint256): 1 -> FAILURE diff --git a/test/libsolidity/semanticTests/shifts/shift_cleanup.sol b/test/libsolidity/semanticTests/shifts/shift_cleanup.sol new file mode 100644 index 000000000..81296ba95 --- /dev/null +++ b/test/libsolidity/semanticTests/shifts/shift_cleanup.sol @@ -0,0 +1,11 @@ +contract C { + function f() public returns (uint16 x) { + x = 0xffff; + x += 32; + x <<= 8; + x >>= 16; + } +} + +// ---- +// f() -> 0x0 diff --git a/test/libsolidity/semanticTests/shifts/shift_cleanup_garbled.sol b/test/libsolidity/semanticTests/shifts/shift_cleanup_garbled.sol new file mode 100644 index 000000000..cc81c15e4 --- /dev/null +++ b/test/libsolidity/semanticTests/shifts/shift_cleanup_garbled.sol @@ -0,0 +1,11 @@ +contract C { + function f() public returns (uint8 x) { + assembly { + x := 0xffff + } + x >>= 8; + } +} + +// ---- +// f() -> 0x0 diff --git a/test/libsolidity/semanticTests/shifts/shift_constant_left.sol b/test/libsolidity/semanticTests/shifts/shift_constant_left.sol new file mode 100644 index 000000000..4c6f3737f --- /dev/null +++ b/test/libsolidity/semanticTests/shifts/shift_constant_left.sol @@ -0,0 +1,6 @@ +contract C { + uint256 public a = 0x42 << 8; +} + +// ---- +// a() -> 0x4200 diff --git a/test/libsolidity/semanticTests/shifts/shift_constant_left_assignment.sol b/test/libsolidity/semanticTests/shifts/shift_constant_left_assignment.sol new file mode 100644 index 000000000..e5a4152b5 --- /dev/null +++ b/test/libsolidity/semanticTests/shifts/shift_constant_left_assignment.sol @@ -0,0 +1,9 @@ +contract C { + function f() public returns (uint256 a) { + a = 0x42; + a <<= 8; + } +} + +// ---- +// f() -> 0x4200 diff --git a/test/libsolidity/semanticTests/shifts/shift_constant_right.sol b/test/libsolidity/semanticTests/shifts/shift_constant_right.sol new file mode 100644 index 000000000..766a8522e --- /dev/null +++ b/test/libsolidity/semanticTests/shifts/shift_constant_right.sol @@ -0,0 +1,6 @@ +contract C { + uint256 public a = 0x4200 >> 8; +} + +// ---- +// a() -> 0x42 diff --git a/test/libsolidity/semanticTests/shifts/shift_constant_right_assignment.sol b/test/libsolidity/semanticTests/shifts/shift_constant_right_assignment.sol new file mode 100644 index 000000000..0f36c10ee --- /dev/null +++ b/test/libsolidity/semanticTests/shifts/shift_constant_right_assignment.sol @@ -0,0 +1,9 @@ +contract C { + function f() public returns (uint256 a) { + a = 0x4200; + a >>= 8; + } +} + +// ---- +// f() -> 0x42 diff --git a/test/libsolidity/semanticTests/shifts/shift_left.sol b/test/libsolidity/semanticTests/shifts/shift_left.sol new file mode 100644 index 000000000..15d2a972a --- /dev/null +++ b/test/libsolidity/semanticTests/shifts/shift_left.sol @@ -0,0 +1,13 @@ +contract C { + function f(uint256 a, uint256 b) public returns (uint256) { + return a << b; + } +} + +// ---- +// f(uint256,uint256): 0x4266, 0x0 -> 0x4266 +// f(uint256,uint256): 0x4266, 0x8 -> 0x426600 +// f(uint256,uint256): 0x4266, 0x10 -> 0x42660000 +// f(uint256,uint256): 0x4266, 0x11 -> 0x84cc0000 +// f(uint256,uint256): 0x4266, 0xf0 -> 0x4266000000000000000000000000000000000000000000000000000000000000 +// f(uint256,uint256): 0x4266, 0x100 -> 0 diff --git a/test/libsolidity/semanticTests/shifts/shift_left_assignment.sol b/test/libsolidity/semanticTests/shifts/shift_left_assignment.sol new file mode 100644 index 000000000..06cb38606 --- /dev/null +++ b/test/libsolidity/semanticTests/shifts/shift_left_assignment.sol @@ -0,0 +1,14 @@ +contract C { + function f(uint256 a, uint256 b) public returns (uint256) { + a <<= b; + return a; + } +} + +// ---- +// f(uint256,uint256): 0x4266, 0x0 -> 0x4266 +// f(uint256,uint256): 0x4266, 0x8 -> 0x426600 +// f(uint256,uint256): 0x4266, 0x10 -> 0x42660000 +// f(uint256,uint256): 0x4266, 0x11 -> 0x84cc0000 +// f(uint256,uint256): 0x4266, 0xf0 -> 0x4266000000000000000000000000000000000000000000000000000000000000 +// f(uint256,uint256): 0x4266, 0x100 -> 0 diff --git a/test/libsolidity/semanticTests/shifts/shift_left_assignment_different_type.sol b/test/libsolidity/semanticTests/shifts/shift_left_assignment_different_type.sol new file mode 100644 index 000000000..5cc15c1a8 --- /dev/null +++ b/test/libsolidity/semanticTests/shifts/shift_left_assignment_different_type.sol @@ -0,0 +1,13 @@ +contract C { + function f(uint256 a, uint8 b) public returns (uint256) { + a <<= b; + return a; + } +} + +// ---- +// f(uint256,uint8): 0x4266, 0x0 -> 0x4266 +// f(uint256,uint8): 0x4266, 0x8 -> 0x426600 +// f(uint256,uint8): 0x4266, 0x10 -> 0x42660000 +// f(uint256,uint8): 0x4266, 0x11 -> 0x84cc0000 +// f(uint256,uint8): 0x4266, 0xf0 -> 0x4266000000000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/semanticTests/shifts/shift_left_larger_type.sol b/test/libsolidity/semanticTests/shifts/shift_left_larger_type.sol new file mode 100644 index 000000000..99ff376d6 --- /dev/null +++ b/test/libsolidity/semanticTests/shifts/shift_left_larger_type.sol @@ -0,0 +1,11 @@ +// This basically tests proper cleanup and conversion. It should not convert x to int8. +contract C { + function f() public returns (int8) { + uint8 x = 254; + int8 y = 1; + return y << x; + } +} + +// ---- +// f() -> 0 diff --git a/test/libsolidity/semanticTests/shifts/shift_left_uint32.sol b/test/libsolidity/semanticTests/shifts/shift_left_uint32.sol new file mode 100644 index 000000000..0f35077b1 --- /dev/null +++ b/test/libsolidity/semanticTests/shifts/shift_left_uint32.sol @@ -0,0 +1,12 @@ +contract C { + function f(uint32 a, uint32 b) public returns (uint256) { + return a << b; + } +} + +// ---- +// f(uint32,uint32): 0x4266, 0x0 -> 0x4266 +// f(uint32,uint32): 0x4266, 0x8 -> 0x426600 +// f(uint32,uint32): 0x4266, 0x10 -> 0x42660000 +// f(uint32,uint32): 0x4266, 0x11 -> 0x84cc0000 +// f(uint32,uint32): 0x4266, 0x20 -> 0 diff --git a/test/libsolidity/semanticTests/shifts/shift_left_uint8.sol b/test/libsolidity/semanticTests/shifts/shift_left_uint8.sol new file mode 100644 index 000000000..3070314f8 --- /dev/null +++ b/test/libsolidity/semanticTests/shifts/shift_left_uint8.sol @@ -0,0 +1,9 @@ +contract C { + function f(uint8 a, uint8 b) public returns (uint256) { + return a << b; + } +} + +// ---- +// f(uint8,uint8): 0x66, 0x0 -> 0x66 +// f(uint8,uint8): 0x66, 0x8 -> 0 diff --git a/test/libsolidity/semanticTests/shifts/shift_negative_constant_left.sol b/test/libsolidity/semanticTests/shifts/shift_negative_constant_left.sol new file mode 100644 index 000000000..b92fb2229 --- /dev/null +++ b/test/libsolidity/semanticTests/shifts/shift_negative_constant_left.sol @@ -0,0 +1,6 @@ +contract C { + int256 public a = -0x42 << 8; +} + +// ---- +// a() -> -16896 diff --git a/test/libsolidity/semanticTests/shifts/shift_negative_constant_right.sol b/test/libsolidity/semanticTests/shifts/shift_negative_constant_right.sol new file mode 100644 index 000000000..b08463333 --- /dev/null +++ b/test/libsolidity/semanticTests/shifts/shift_negative_constant_right.sol @@ -0,0 +1,6 @@ +contract C { + int256 public a = -0x4200 >> 8; +} + +// ---- +// a() -> -66 diff --git a/test/libsolidity/semanticTests/shifts/shift_negative_rvalue.sol b/test/libsolidity/semanticTests/shifts/shift_negative_rvalue.sol new file mode 100644 index 000000000..77c18c44b --- /dev/null +++ b/test/libsolidity/semanticTests/shifts/shift_negative_rvalue.sol @@ -0,0 +1,13 @@ +contract C { + function f(int256 a, int256 b) public returns (int256) { + return a << b; + } + + function g(int256 a, int256 b) public returns (int256) { + return a >> b; + } +} + +// ---- +// f(int256,int256): 1, -1 -> FAILURE +// g(int256,int256): 1, -1 -> FAILURE diff --git a/test/libsolidity/semanticTests/shifts/shift_negative_rvalue_assignment.sol b/test/libsolidity/semanticTests/shifts/shift_negative_rvalue_assignment.sol new file mode 100644 index 000000000..e63a9a57e --- /dev/null +++ b/test/libsolidity/semanticTests/shifts/shift_negative_rvalue_assignment.sol @@ -0,0 +1,15 @@ +contract C { + function f(int256 a, int256 b) public returns (int256) { + a <<= b; + return a; + } + + function g(int256 a, int256 b) public returns (int256) { + a >>= b; + return a; + } +} + +// ---- +// f(int256,int256): 1, -1 -> FAILURE +// g(int256,int256): 1, -1 -> FAILURE diff --git a/test/libsolidity/semanticTests/shifts/shift_overflow.sol b/test/libsolidity/semanticTests/shifts/shift_overflow.sol new file mode 100644 index 000000000..f1b4bca0a --- /dev/null +++ b/test/libsolidity/semanticTests/shifts/shift_overflow.sol @@ -0,0 +1,16 @@ +contract C { + function leftU(uint8 x, uint8 y) public returns (uint8) { + return x << y; + } + + function leftS(int8 x, int8 y) public returns (int8) { + return x << y; + } +} + +// ---- +// leftU(uint8,uint8): 255, 8 -> 0 +// leftU(uint8,uint8): 255, 1 -> 254 +// leftU(uint8,uint8): 255, 0 -> 255 +// leftS(int8,int8): 1, 7 -> -128 # Result is -128 and output is sign-extended, not zero-padded. # +// leftS(int8,int8): 1, 6 -> 64 diff --git a/test/libsolidity/semanticTests/shifts/shift_right.sol b/test/libsolidity/semanticTests/shifts/shift_right.sol new file mode 100644 index 000000000..d78d18aba --- /dev/null +++ b/test/libsolidity/semanticTests/shifts/shift_right.sol @@ -0,0 +1,12 @@ +contract C { + function f(uint256 a, uint256 b) public returns (uint256) { + return a >> b; + } +} + +// ---- +// f(uint256,uint256): 0x4266, 0x0 -> 0x4266 +// f(uint256,uint256): 0x4266, 0x8 -> 0x42 +// f(uint256,uint256): 0x4266, 0x10 -> 0 +// f(uint256,uint256): 0x4266, 0x11 -> 0 +// f(uint256,uint256): 57896044618658097711785492504343953926634992332820282019728792003956564819968, 5 -> 1809251394333065553493296640760748560207343510400633813116524750123642650624 diff --git a/test/libsolidity/semanticTests/shifts/shift_right_assignment.sol b/test/libsolidity/semanticTests/shifts/shift_right_assignment.sol new file mode 100644 index 000000000..cfee67301 --- /dev/null +++ b/test/libsolidity/semanticTests/shifts/shift_right_assignment.sol @@ -0,0 +1,12 @@ +contract C { + function f(uint256 a, uint256 b) public returns (uint256) { + a >>= b; + return a; + } +} + +// ---- +// f(uint256,uint256): 0x4266, 0x0 -> 0x4266 +// f(uint256,uint256): 0x4266, 0x8 -> 0x42 +// f(uint256,uint256): 0x4266, 0x10 -> 0 +// f(uint256,uint256): 0x4266, 0x11 -> 0 diff --git a/test/libsolidity/semanticTests/shifts/shift_right_assignment_signed.sol b/test/libsolidity/semanticTests/shifts/shift_right_assignment_signed.sol new file mode 100644 index 000000000..ba819fbce --- /dev/null +++ b/test/libsolidity/semanticTests/shifts/shift_right_assignment_signed.sol @@ -0,0 +1,12 @@ +contract C { + function f(int256 a, int256 b) public returns (int256) { + a >>= b; + return a; + } +} + +// ---- +// f(int256,int256): 0x4266, 0x0 -> 0x4266 +// f(int256,int256): 0x4266, 0x8 -> 0x42 +// f(int256,int256): 0x4266, 0x10 -> 0 +// f(int256,int256): 0x4266, 0x11 -> 0 diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_literal.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_literal.sol new file mode 100644 index 000000000..2ae9647e2 --- /dev/null +++ b/test/libsolidity/semanticTests/shifts/shift_right_negative_literal.sol @@ -0,0 +1,65 @@ +contract C { + function f1() public pure returns (bool) { + return (-4266 >> 0) == -4266; + } + + function f2() public pure returns (bool) { + return (-4266 >> 1) == -2133; + } + + function f3() public pure returns (bool) { + return (-4266 >> 4) == -267; + } + + function f4() public pure returns (bool) { + return (-4266 >> 8) == -17; + } + + function f5() public pure returns (bool) { + return (-4266 >> 16) == -1; + } + + function f6() public pure returns (bool) { + return (-4266 >> 17) == -1; + } + + function g1() public pure returns (bool) { + return (-4267 >> 0) == -4267; + } + + function g2() public pure returns (bool) { + return (-4267 >> 1) == -2134; + } + + function g3() public pure returns (bool) { + return (-4267 >> 4) == -267; + } + + function g4() public pure returns (bool) { + return (-4267 >> 8) == -17; + } + + function g5() public pure returns (bool) { + return (-4267 >> 16) == -1; + } + + function g6() public pure returns (bool) { + return (-4267 >> 17) == -1; + } +} + +// ==== +// compileViaYul: also +// ---- +// f1() -> true +// f2() -> true +// f3() -> true +// f4() -> true +// f5() -> true +// f6() -> true +// g1() -> true +// g2() -> true +// g3() -> true +// g4() -> true +// g5() -> true +// g6() -> true diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue.sol new file mode 100644 index 000000000..73aae5bc9 --- /dev/null +++ b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue.sol @@ -0,0 +1,19 @@ +contract C { + function f(int256 a, int256 b) public returns (int256) { + return a >> b; + } +} + +// ---- +// f(int256,int256): -4266, 0 -> -4266 +// f(int256,int256): -4266, 1 -> -2133 +// f(int256,int256): -4266, 4 -> -267 +// f(int256,int256): -4266, 8 -> -17 +// f(int256,int256): -4266, 16 -> -1 +// f(int256,int256): -4266, 17 -> -1 +// f(int256,int256): -4267, 0 -> -4267 +// f(int256,int256): -4267, 1 -> -2134 +// f(int256,int256): -4267, 4 -> -267 +// f(int256,int256): -4267, 8 -> -17 +// f(int256,int256): -4267, 16 -> -1 +// f(int256,int256): -4267, 17 -> -1 diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_assignment.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_assignment.sol new file mode 100644 index 000000000..7f3beb59f --- /dev/null +++ b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_assignment.sol @@ -0,0 +1,20 @@ +contract C { + function f(int256 a, int256 b) public returns (int256) { + a >>= b; + return a; + } +} + +// ---- +// f(int256,int256): -4266, 0 -> -4266 +// f(int256,int256): -4266, 1 -> -2133 +// f(int256,int256): -4266, 4 -> -267 +// f(int256,int256): -4266, 8 -> -17 +// f(int256,int256): -4266, 16 -> -1 +// f(int256,int256): -4266, 17 -> -1 +// f(int256,int256): -4267, 0 -> -4267 +// f(int256,int256): -4267, 1 -> -2134 +// f(int256,int256): -4267, 4 -> -267 +// f(int256,int256): -4267, 8 -> -17 +// f(int256,int256): -4267, 16 -> -1 +// f(int256,int256): -4267, 17 -> -1 diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int16.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int16.sol new file mode 100644 index 000000000..24ab54123 --- /dev/null +++ b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int16.sol @@ -0,0 +1,19 @@ +contract C { + function f(int16 a, int16 b) public returns (int256) { + return a >> b; + } +} + +// ---- +// f(int16,int16): -4266, 0 -> -4266 +// f(int16,int16): -4266, 1 -> -2133 +// f(int16,int16): -4266, 4 -> -267 +// f(int16,int16): -4266, 8 -> -17 +// f(int16,int16): -4266, 16 -> -1 +// f(int16,int16): -4266, 17 -> -1 +// f(int16,int16): -4267, 0 -> -4267 +// f(int16,int16): -4267, 1 -> -2134 +// f(int16,int16): -4267, 4 -> -267 +// f(int16,int16): -4267, 8 -> -17 +// f(int16,int16): -4267, 16 -> -1 +// f(int16,int16): -4267, 17 -> -1 diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int32.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int32.sol new file mode 100644 index 000000000..7ff669dc9 --- /dev/null +++ b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int32.sol @@ -0,0 +1,19 @@ +contract C { + function f(int32 a, int32 b) public returns (int256) { + return a >> b; + } +} + +// ---- +// f(int32,int32): -4266, 0 -> -4266 +// f(int32,int32): -4266, 1 -> -2133 +// f(int32,int32): -4266, 4 -> -267 +// f(int32,int32): -4266, 8 -> -17 +// f(int32,int32): -4266, 16 -> -1 +// f(int32,int32): -4266, 17 -> -1 +// f(int32,int32): -4267, 0 -> -4267 +// f(int32,int32): -4267, 1 -> -2134 +// f(int32,int32): -4267, 4 -> -267 +// f(int32,int32): -4267, 8 -> -17 +// f(int32,int32): -4267, 16 -> -1 +// f(int32,int32): -4267, 17 -> -1 diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int8.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int8.sol new file mode 100644 index 000000000..c6424f141 --- /dev/null +++ b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int8.sol @@ -0,0 +1,19 @@ +contract C { + function f(int8 a, int8 b) public returns (int256) { + return a >> b; + } +} + +// ---- +// f(int8,int8): -66, 0 -> -66 +// f(int8,int8): -66, 1 -> -33 +// f(int8,int8): -66, 4 -> -5 +// f(int8,int8): -66, 8 -> -1 +// f(int8,int8): -66, 16 -> -1 +// f(int8,int8): -66, 17 -> -1 +// f(int8,int8): -67, 0 -> -67 +// f(int8,int8): -67, 1 -> -34 +// f(int8,int8): -67, 4 -> -5 +// f(int8,int8): -67, 8 -> -1 +// f(int8,int8): -67, 16 -> -1 +// f(int8,int8): -67, 17 -> -1 diff --git a/test/libsolidity/semanticTests/shifts/shift_right_uint32.sol b/test/libsolidity/semanticTests/shifts/shift_right_uint32.sol new file mode 100644 index 000000000..03573d985 --- /dev/null +++ b/test/libsolidity/semanticTests/shifts/shift_right_uint32.sol @@ -0,0 +1,11 @@ +contract C { + function f(uint32 a, uint32 b) public returns (uint256) { + return a >> b; + } +} + +// ---- +// f(uint32,uint32): 0x4266, 0x0 -> 0x4266 +// f(uint32,uint32): 0x4266, 0x8 -> 0x42 +// f(uint32,uint32): 0x4266, 0x10 -> 0 +// f(uint32,uint32): 0x4266, 0x11 -> 0 diff --git a/test/libsolidity/semanticTests/shifts/shift_right_uint8.sol b/test/libsolidity/semanticTests/shifts/shift_right_uint8.sol new file mode 100644 index 000000000..8457b10e1 --- /dev/null +++ b/test/libsolidity/semanticTests/shifts/shift_right_uint8.sol @@ -0,0 +1,9 @@ +contract C { + function f(uint8 a, uint8 b) public returns (uint256) { + return a >> b; + } +} + +// ---- +// f(uint8,uint8): 0x66, 0x0 -> 0x66 +// f(uint8,uint8): 0x66, 0x8 -> 0x0 diff --git a/test/libsolidity/semanticTests/shifts.sol b/test/libsolidity/semanticTests/shifts/shifts.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts.sol rename to test/libsolidity/semanticTests/shifts/shifts.sol diff --git a/test/libsolidity/semanticTests/storage/packed_functions.sol b/test/libsolidity/semanticTests/storage/packed_functions.sol new file mode 100644 index 000000000..4a49a614f --- /dev/null +++ b/test/libsolidity/semanticTests/storage/packed_functions.sol @@ -0,0 +1,48 @@ +contract C { + // these should take the same slot + function() internal returns (uint) a; + function() external returns (uint) b; + function() external returns (uint) c; + function() internal returns (uint) d; + uint8 public x; + + function set() public { + x = 2; + d = g; + c = this.h; + b = this.h; + a = g; + } + + function t1() public returns (uint256) { + return a(); + } + + function t2() public returns (uint256) { + return b(); + } + + function t3() public returns (uint256) { + return a(); + } + + function t4() public returns (uint256) { + return b(); + } + + function g() public returns (uint256) { + return 7; + } + + function h() public returns (uint256) { + return 8; + } +} + +// ---- +// set() -> +// t1() -> 7 +// t2() -> 8 +// t3() -> 7 +// t4() -> 8 +// x() -> 2 diff --git a/test/libsolidity/semanticTests/storage/packed_storage_overflow.sol b/test/libsolidity/semanticTests/storage/packed_storage_overflow.sol new file mode 100644 index 000000000..9b20dbfd2 --- /dev/null +++ b/test/libsolidity/semanticTests/storage/packed_storage_overflow.sol @@ -0,0 +1,16 @@ +contract C { + uint16 x = 0x1234; + uint16 a = 0xffff; + uint16 b; + + function f() public returns (uint256, uint256, uint256, uint256) { + a++; + uint256 c = b; + delete b; + a -= 2; + return (x, c, b, a); + } +} + +// ---- +// f() -> 0x1234, 0x0, 0x0, 0xfffe diff --git a/test/libsolidity/semanticTests/storage/packed_storage_signed.sol b/test/libsolidity/semanticTests/storage/packed_storage_signed.sol new file mode 100644 index 000000000..8db0c757e --- /dev/null +++ b/test/libsolidity/semanticTests/storage/packed_storage_signed.sol @@ -0,0 +1,22 @@ +contract C { + int8 a; + uint8 b; + int8 c; + uint8 d; + + function test() + public + returns (uint256 x1, uint256 x2, uint256 x3, uint256 x4) + { + a = -2; + b = -uint8(a) * 2; + c = a * int8(120) * int8(121); + x1 = uint256(a); + x2 = b; + x3 = uint256(c); + x4 = d; + } +} + +// ---- +// test() -> -2, 4, -112, 0 diff --git a/test/libsolidity/semanticTests/storage/packed_storage_structs_bytes.sol b/test/libsolidity/semanticTests/storage/packed_storage_structs_bytes.sol new file mode 100644 index 000000000..daeee6ba6 --- /dev/null +++ b/test/libsolidity/semanticTests/storage/packed_storage_structs_bytes.sol @@ -0,0 +1,45 @@ +contract C { + struct s1 { + bytes1 a; + bytes1 b; + bytes10 c; + bytes9 d; + bytes10 e; + } + struct s2 { + bytes1 a; + s1 inner; + bytes1 b; + bytes1 c; + } + bytes1 x; + s2 data; + bytes1 y; + + function test() public returns (bool) { + x = 0x01; + data.a = 0x02; + data.inner.a = 0x03; + data.inner.b = 0x04; + data.inner.c = "1234567890"; + data.inner.d = "123456789"; + data.inner.e = "abcdefghij"; + data.b = 0x05; + data.c = bytes1(0x06); + y = 0x07; + return + x == 0x01 && + data.a == 0x02 && + data.inner.a == 0x03 && + data.inner.b == 0x04 && + data.inner.c == "1234567890" && + data.inner.d == "123456789" && + data.inner.e == "abcdefghij" && + data.b == 0x05 && + data.c == bytes1(0x06) && + y == 0x07; + } +} + +// ---- +// test() -> true diff --git a/test/libsolidity/semanticTests/storage/packed_storage_structs_enum.sol b/test/libsolidity/semanticTests/storage/packed_storage_structs_enum.sol new file mode 100644 index 000000000..9c9f778f0 --- /dev/null +++ b/test/libsolidity/semanticTests/storage/packed_storage_structs_enum.sol @@ -0,0 +1,33 @@ +contract C { + enum small {A, B, C, D} + enum larger {A, B, C, D, E} + struct str { + small a; + small b; + larger c; + larger d; + } + str data; + + function test() public returns (uint256) { + data.a = small.B; + if (data.a != small.B) return 2; + data.b = small.C; + if (data.b != small.C) return 3; + data.c = larger.D; + if (data.c != larger.D) return 4; + if (data.a != small.B) return 5; + data.a = small.C; + if (data.a != small.C) return 6; + if (data.b != small.C) return 7; + data.b = small.D; + if (data.b != small.D) return 8; + if (data.c != larger.D) return 9; + data.c = larger.B; + if (data.c != larger.B) return 10; + return 1; + } +} + +// ---- +// test() -> 1 diff --git a/test/libsolidity/semanticTests/storage/packed_storage_structs_uint.sol b/test/libsolidity/semanticTests/storage/packed_storage_structs_uint.sol new file mode 100644 index 000000000..8c91576f5 --- /dev/null +++ b/test/libsolidity/semanticTests/storage/packed_storage_structs_uint.sol @@ -0,0 +1,30 @@ +contract C { + struct str { + uint8 a; + uint16 b; + uint248 c; + } + str data; + + function test() public returns (uint256) { + data.a = 2; + if (data.a != 2) return 2; + data.b = 0xabcd; + if (data.b != 0xabcd) return 3; + data.c = 0x1234567890; + if (data.c != 0x1234567890) return 4; + if (data.a != 2) return 5; + data.a = 8; + if (data.a != 8) return 6; + if (data.b != 0xabcd) return 7; + data.b = 0xdcab; + if (data.b != 0xdcab) return 8; + if (data.c != 0x1234567890) return 9; + data.c = 0x9876543210; + if (data.c != 0x9876543210) return 10; + return 1; + } +} + +// ---- +// test() -> 1 diff --git a/test/libsolidity/semanticTests/structs/calldata/calldata_struct.sol b/test/libsolidity/semanticTests/structs/calldata/calldata_struct.sol new file mode 100644 index 000000000..a7ecf2bd0 --- /dev/null +++ b/test/libsolidity/semanticTests/structs/calldata/calldata_struct.sol @@ -0,0 +1,17 @@ +pragma experimental ABIEncoderV2; + + +contract C { + struct S { + uint256 a; + uint256 b; + } + + function f(S calldata s) external pure returns (uint256 a, uint256 b) { + a = s.a; + b = s.b; + } +} + +// ---- +// f((uint256,uint256)): 42, 23 -> 42, 23 diff --git a/test/libsolidity/semanticTests/structs/calldata/calldata_struct_and_ints.sol b/test/libsolidity/semanticTests/structs/calldata/calldata_struct_and_ints.sol new file mode 100644 index 000000000..c3b8249e8 --- /dev/null +++ b/test/libsolidity/semanticTests/structs/calldata/calldata_struct_and_ints.sol @@ -0,0 +1,20 @@ +pragma experimental ABIEncoderV2; + + +contract C { + struct S { + uint256 a; + uint256 b; + } + + function f(uint256 a, S calldata s, uint256 b) + external + pure + returns (uint256, uint256, uint256, uint256) + { + return (a, s.a, s.b, b); + } +} + +// ---- +// f(uint256,(uint256,uint256),uint256): 1, 2, 3, 4 -> 1, 2, 3, 4 diff --git a/test/libsolidity/semanticTests/structs/calldata/calldata_struct_array_member.sol b/test/libsolidity/semanticTests/structs/calldata/calldata_struct_array_member.sol new file mode 100644 index 000000000..3e8613fad --- /dev/null +++ b/test/libsolidity/semanticTests/structs/calldata/calldata_struct_array_member.sol @@ -0,0 +1,24 @@ +pragma experimental ABIEncoderV2; + + +contract C { + struct S { + uint256 a; + uint256[2] b; + uint256 c; + } + + function f(S calldata s) + external + pure + returns (uint256 a, uint256 b0, uint256 b1, uint256 c) + { + a = s.a; + b0 = s.b[0]; + b1 = s.b[1]; + c = s.c; + } +} + +// ---- +// f((uint256,uint256[2],uint256)): 42, 1, 2, 23 -> 42, 1, 2, 23 diff --git a/test/libsolidity/semanticTests/structs/calldata/calldata_struct_to_memory.sol b/test/libsolidity/semanticTests/structs/calldata/calldata_struct_to_memory.sol new file mode 100644 index 000000000..db8171a20 --- /dev/null +++ b/test/libsolidity/semanticTests/structs/calldata/calldata_struct_to_memory.sol @@ -0,0 +1,17 @@ +pragma experimental ABIEncoderV2; + + +contract C { + struct S { + uint256 a; + uint256 b; + } + + function f(S calldata s) external pure returns (uint256, uint256) { + S memory m = s; + return (m.a, m.b); + } +} + +// ---- +// f((uint256,uint256)): 42, 23 -> 42, 23 diff --git a/test/libsolidity/semanticTests/structs/calldata/calldata_structs.sol b/test/libsolidity/semanticTests/structs/calldata/calldata_structs.sol new file mode 100644 index 000000000..4139c1073 --- /dev/null +++ b/test/libsolidity/semanticTests/structs/calldata/calldata_structs.sol @@ -0,0 +1,27 @@ +pragma experimental ABIEncoderV2; + + +contract C { + struct S1 { + uint256 a; + uint256 b; + } + struct S2 { + uint256 a; + } + + function f(S1 calldata s1, S2 calldata s2, S1 calldata s3) + external + pure + returns (uint256 a, uint256 b, uint256 c, uint256 d, uint256 e) + { + a = s1.a; + b = s1.b; + c = s2.a; + d = s3.a; + e = s3.b; + } +} + +// ---- +// f((uint256,uint256),(uint256),(uint256,uint256)): 1, 2, 3, 4, 5 -> 1, 2, 3, 4, 5 diff --git a/test/libsolidity/semanticTests/structs/lone_struct_array_type.sol b/test/libsolidity/semanticTests/structs/lone_struct_array_type.sol new file mode 100644 index 000000000..829345d2e --- /dev/null +++ b/test/libsolidity/semanticTests/structs/lone_struct_array_type.sol @@ -0,0 +1,16 @@ +contract C { + struct s { + uint256 a; + uint256 b; + } + + function f() public returns (uint256) { + s[7][]; // This is only the type, should not have any effect + return 3; + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> 3 diff --git a/test/libsolidity/semanticTests/structs/memory_structs_as_function_args.sol b/test/libsolidity/semanticTests/structs/memory_structs_as_function_args.sol new file mode 100644 index 000000000..1173a3796 --- /dev/null +++ b/test/libsolidity/semanticTests/structs/memory_structs_as_function_args.sol @@ -0,0 +1,32 @@ +contract Test { + struct S { + uint8 x; + uint16 y; + uint256 z; + } + + function test() public returns (uint256 x, uint256 y, uint256 z) { + S memory data = combine(1, 2, 3); + x = extract(data, 0); + y = extract(data, 1); + z = extract(data, 2); + } + + function extract(S memory s, uint256 which) internal returns (uint256 x) { + if (which == 0) return s.x; + else if (which == 1) return s.y; + else return s.z; + } + + function combine(uint8 x, uint16 y, uint256 z) + internal + returns (S memory s) + { + s.x = x; + s.y = y; + s.z = z; + } +} + +// ---- +// test() -> 1, 2, 3 diff --git a/test/libsolidity/semanticTests/structs/memory_structs_nested.sol b/test/libsolidity/semanticTests/structs/memory_structs_nested.sol new file mode 100644 index 000000000..f5c41a232 --- /dev/null +++ b/test/libsolidity/semanticTests/structs/memory_structs_nested.sol @@ -0,0 +1,42 @@ +contract Test { + struct S { + uint8 x; + uint16 y; + uint256 z; + } + struct X { + uint8 x; + S s; + } + + function test() + public + returns (uint256 a, uint256 x, uint256 y, uint256 z) + { + X memory d = combine(1, 2, 3, 4); + a = extract(d, 0); + x = extract(d, 1); + y = extract(d, 2); + z = extract(d, 3); + } + + function extract(X memory s, uint256 which) internal returns (uint256 x) { + if (which == 0) return s.x; + else if (which == 1) return s.s.x; + else if (which == 2) return s.s.y; + else return s.s.z; + } + + function combine(uint8 a, uint8 x, uint16 y, uint256 z) + internal + returns (X memory s) + { + s.x = a; + s.s.x = x; + s.s.y = y; + s.s.z = z; + } +} + +// ---- +// test() -> 1, 2, 3, 4 diff --git a/test/libsolidity/semanticTests/structs/memory_structs_read_write.sol b/test/libsolidity/semanticTests/structs/memory_structs_read_write.sol new file mode 100644 index 000000000..105f59909 --- /dev/null +++ b/test/libsolidity/semanticTests/structs/memory_structs_read_write.sol @@ -0,0 +1,56 @@ +contract Test { + struct S { + uint8 x; + uint16 y; + uint256 z; + uint8[2] a; + } + S[5] data; + + function testInit() + public + returns (uint8 x, uint16 y, uint256 z, uint8 a, bool flag) + { + S[2] memory d; + x = d[0].x; + y = d[0].y; + z = d[0].z; + a = d[0].a[1]; + flag = true; + } + + function testCopyRead() + public + returns (uint8 x, uint16 y, uint256 z, uint8 a) + { + data[2].x = 1; + data[2].y = 2; + data[2].z = 3; + data[2].a[1] = 4; + S memory s = data[2]; + x = s.x; + y = s.y; + z = s.z; + a = s.a[1]; + } + + function testAssign() + public + returns (uint8 x, uint16 y, uint256 z, uint8 a) + { + S memory s; + s.x = 1; + s.y = 2; + s.z = 3; + s.a[1] = 4; + x = s.x; + y = s.y; + z = s.z; + a = s.a[1]; + } +} + +// ---- +// testInit() -> 0, 0, 0, 0, true +// testCopyRead() -> 1, 2, 3, 4 +// testAssign() -> 1, 2, 3, 4 diff --git a/test/libsolidity/semanticTests/structs/memory_structs_with_mappings.sol b/test/libsolidity/semanticTests/structs/memory_structs_with_mappings.sol new file mode 100644 index 000000000..3aaa354f8 --- /dev/null +++ b/test/libsolidity/semanticTests/structs/memory_structs_with_mappings.sol @@ -0,0 +1,24 @@ +contract Test { + struct S { + uint8 a; + mapping(uint256 => uint256) b; + uint8 c; + } + S s; + + function f() public returns (uint256) { + S memory x; + if (x.a != 0 || x.c != 0) return 1; + x.a = 4; + x.c = 5; + s = x; + if (s.a != 4 || s.c != 5) return 2; + x = S(2, 3); + if (x.a != 2 || x.c != 3) return 3; + x = s; + if (s.a != 4 || s.c != 5) return 4; + } +} + +// ---- +// f() -> 0 diff --git a/test/libsolidity/semanticTests/structs/recursive_structs.sol b/test/libsolidity/semanticTests/structs/recursive_structs.sol new file mode 100644 index 000000000..da568a255 --- /dev/null +++ b/test/libsolidity/semanticTests/structs/recursive_structs.sol @@ -0,0 +1,19 @@ +contract C { + struct S { + S[] x; + } + S sstorage; + + function f() public returns (uint256) { + S memory s; + s.x = new S[](10); + delete s; + // TODO Uncomment after implemented. + // sstorage.x.push(); + delete sstorage; + return 1; + } +} + +// ---- +// f() -> 1 diff --git a/test/libsolidity/semanticTests/structs/struct_assign_reference_to_struct.sol b/test/libsolidity/semanticTests/structs/struct_assign_reference_to_struct.sol new file mode 100644 index 000000000..8591131be --- /dev/null +++ b/test/libsolidity/semanticTests/structs/struct_assign_reference_to_struct.sol @@ -0,0 +1,36 @@ +contract test { + struct testStruct { + uint256 m_value; + } + testStruct data1; + testStruct data2; + testStruct data3; + + constructor() public { + data1.m_value = 2; + } + + function assign() + public + returns ( + uint256 ret_local, + uint256 ret_global, + uint256 ret_global3, + uint256 ret_global1 + ) + { + testStruct storage x = data1; //x is a reference data1.m_value == 2 as well as x.m_value = 2 + data2 = data1; // should copy data. data2.m_value == 2 + + ret_local = x.m_value; // = 2 + ret_global = data2.m_value; // = 2 + + x.m_value = 3; + data3 = x; //should copy the data. data3.m_value == 3 + ret_global3 = data3.m_value; // = 3 + ret_global1 = data1.m_value; // = 3. Changed due to the assignment to x.m_value + } +} + +// ---- +// assign() -> 2, 2, 3, 3 diff --git a/test/libsolidity/semanticTests/structs/struct_copy.sol b/test/libsolidity/semanticTests/structs/struct_copy.sol new file mode 100644 index 000000000..f6c35f7da --- /dev/null +++ b/test/libsolidity/semanticTests/structs/struct_copy.sol @@ -0,0 +1,48 @@ +contract c { + struct Nested { + uint256 x; + uint256 y; + } + struct Struct { + uint256 a; + mapping(uint256 => Struct) b; + Nested nested; + uint256 c; + } + mapping(uint256 => Struct) data; + + function set(uint256 k) public returns (bool) { + data[k].a = 1; + data[k].nested.x = 3; + data[k].nested.y = 4; + data[k].c = 2; + return true; + } + + function copy(uint256 from, uint256 to) public returns (bool) { + data[to] = data[from]; + return true; + } + + function retrieve(uint256 k) + public + returns (uint256 a, uint256 x, uint256 y, uint256 c) + { + a = data[k].a; + x = data[k].nested.x; + y = data[k].nested.y; + c = data[k].c; + } +} + +// ---- +// set(uint256): 7 -> true +// retrieve(uint256): 7 -> 1, 3, 4, 2 +// copy(uint256,uint256): 7, 8 -> true +// retrieve(uint256): 7 -> 1, 3, 4, 2 +// retrieve(uint256): 8 -> 1, 3, 4, 2 +// copy(uint256,uint256): 0, 7 -> true +// retrieve(uint256): 7 -> 0, 0, 0, 0 +// retrieve(uint256): 8 -> 1, 3, 4, 2 +// copy(uint256,uint256): 7, 8 -> true +// retrieve(uint256): 8 -> 0, 0, 0, 0 diff --git a/test/libsolidity/semanticTests/structs/struct_copy_via_local.sol b/test/libsolidity/semanticTests/structs/struct_copy_via_local.sol new file mode 100644 index 000000000..a1cfcac05 --- /dev/null +++ b/test/libsolidity/semanticTests/structs/struct_copy_via_local.sol @@ -0,0 +1,19 @@ +contract c { + struct Struct { + uint256 a; + uint256 b; + } + Struct data1; + Struct data2; + + function test() public returns (bool) { + data1.a = 1; + data1.b = 2; + Struct memory x = data1; + data2 = x; + return data2.a == data1.a && data2.b == data1.b; + } +} + +// ---- +// test() -> true diff --git a/test/libsolidity/semanticTests/structs/struct_delete_member.sol b/test/libsolidity/semanticTests/structs/struct_delete_member.sol new file mode 100644 index 000000000..fbaf7b6d9 --- /dev/null +++ b/test/libsolidity/semanticTests/structs/struct_delete_member.sol @@ -0,0 +1,20 @@ +contract test { + struct testStruct { + uint256 m_value; + } + testStruct data1; + + constructor() public { + data1.m_value = 2; + } + + function deleteMember() public returns (uint256 ret_value) { + testStruct storage x = data1; //should not copy the data. data1.m_value == 2 but x.m_value = 0 + x.m_value = 4; + delete x.m_value; + ret_value = data1.m_value; + } +} + +// ---- +// deleteMember() -> 0 diff --git a/test/libsolidity/semanticTests/structs/struct_delete_struct_in_mapping.sol b/test/libsolidity/semanticTests/structs/struct_delete_struct_in_mapping.sol new file mode 100644 index 000000000..59d79da9f --- /dev/null +++ b/test/libsolidity/semanticTests/structs/struct_delete_struct_in_mapping.sol @@ -0,0 +1,18 @@ +contract test { + struct testStruct { + uint256 m_value; + } + mapping(uint256 => testStruct) campaigns; + + constructor() public { + campaigns[0].m_value = 2; + } + + function deleteIt() public returns (uint256) { + delete campaigns[0]; + return campaigns[0].m_value; + } +} + +// ---- +// deleteIt() -> 0 diff --git a/test/libsolidity/semanticTests/structs/struct_named_constructor.sol b/test/libsolidity/semanticTests/structs/struct_named_constructor.sol new file mode 100644 index 000000000..5368b090e --- /dev/null +++ b/test/libsolidity/semanticTests/structs/struct_named_constructor.sol @@ -0,0 +1,14 @@ +contract C { + struct S { + uint256 a; + bool x; + } + S public s; + + constructor() public { + s = S({a: 1, x: true}); + } +} + +// ---- +// s() -> 1, true diff --git a/test/libsolidity/semanticTests/variables/public_state_overridding_dynamic_struct.sol b/test/libsolidity/semanticTests/variables/public_state_overridding_dynamic_struct.sol new file mode 100644 index 000000000..f6fa4d45e --- /dev/null +++ b/test/libsolidity/semanticTests/variables/public_state_overridding_dynamic_struct.sol @@ -0,0 +1,24 @@ +pragma experimental ABIEncoderV2; + +struct S { uint256 v; string s; } + +contract A +{ + function test() external virtual returns (uint256 v, string memory s) + { + v = 42; + s = "test"; + } +} +contract X is A +{ + S public override test; + + function set() public { test.v = 2; test.s = "statevar"; } +} + + +// ---- +// test() -> 0, 64, 0 +// set() -> +// test() -> 2, 0x40, 8, "statevar" diff --git a/test/libsolidity/semanticTests/variables/public_state_overridding_mapping_to_dynamic_struct.sol b/test/libsolidity/semanticTests/variables/public_state_overridding_mapping_to_dynamic_struct.sol new file mode 100644 index 000000000..404013ee6 --- /dev/null +++ b/test/libsolidity/semanticTests/variables/public_state_overridding_mapping_to_dynamic_struct.sol @@ -0,0 +1,26 @@ +pragma experimental ABIEncoderV2; + +struct S { uint256 v; string s; } + +contract A +{ + function test(uint256 x) external virtual returns (uint256 v, string memory s) + { + v = x; + s = "test"; + } +} +contract X is A +{ + mapping(uint256 => S) public override test; + + function set() public { test[42].v = 2; test[42].s = "statevar"; } +} + + +// ---- +// test(uint256): 0 -> 0, 64, 0 +// test(uint256): 42 -> 0, 64, 0 +// set() -> +// test(uint256): 0 -> 0, 64, 0 +// test(uint256): 42 -> 2, 0x40, 8, "statevar" diff --git a/test/libsolidity/semanticTests/various/assignment_to_const_var_involving_expression.sol b/test/libsolidity/semanticTests/various/assignment_to_const_var_involving_expression.sol new file mode 100644 index 000000000..b83b1c598 --- /dev/null +++ b/test/libsolidity/semanticTests/various/assignment_to_const_var_involving_expression.sol @@ -0,0 +1,10 @@ +contract C { + uint256 constant x = 0x123 + 0x456; + + function f() public returns (uint256) { + return x + 1; + } +} + +// ---- +// f() -> 0x57a diff --git a/test/libsolidity/semanticTests/various/balance.sol b/test/libsolidity/semanticTests/various/balance.sol new file mode 100644 index 000000000..d6a80dbf9 --- /dev/null +++ b/test/libsolidity/semanticTests/various/balance.sol @@ -0,0 +1,13 @@ +contract test { + constructor() public payable {} + + function getBalance() public returns (uint256 balance) { + return address(this).balance; + } +} + +// ==== +// compileViaYul: also +// ---- +// constructor(), 23 wei -> +// getBalance() -> 23 diff --git a/test/libsolidity/semanticTests/various/byte_optimization_bug.sol b/test/libsolidity/semanticTests/various/byte_optimization_bug.sol new file mode 100644 index 000000000..3d94e4333 --- /dev/null +++ b/test/libsolidity/semanticTests/various/byte_optimization_bug.sol @@ -0,0 +1,19 @@ +contract C { + function f(uint256 x) public returns (uint256 a) { + assembly { + a := byte(x, 31) + } + } + + function g(uint256 x) public returns (uint256 a) { + assembly { + a := byte(31, x) + } + } +} + +// ==== +// compileViaYul: also +// ---- +// f(uint256): 2 -> 0 +// g(uint256): 2 -> 2 diff --git a/test/libsolidity/semanticTests/various/code_access_content.sol b/test/libsolidity/semanticTests/various/code_access_content.sol new file mode 100644 index 000000000..2c115d6c8 --- /dev/null +++ b/test/libsolidity/semanticTests/various/code_access_content.sol @@ -0,0 +1,42 @@ +contract D { + bytes32 public x; + + constructor() public { + bytes32 codeHash; + assembly { + let size := codesize() + codecopy(mload(0x40), 0, size) + codeHash := keccak256(mload(0x40), size) + } + x = codeHash; + } +} + + +contract C { + function testRuntime() public returns (bool) { + D d = new D(); + bytes32 runtimeHash = keccak256(type(D).runtimeCode); + bytes32 otherHash; + uint256 size; + assembly { + size := extcodesize(d) + extcodecopy(d, mload(0x40), 0, size) + otherHash := keccak256(mload(0x40), size) + } + require(size == type(D).runtimeCode.length); + require(runtimeHash == otherHash); + return true; + } + + function testCreation() public returns (bool) { + D d = new D(); + bytes32 creationHash = keccak256(type(D).creationCode); + require(creationHash == d.x()); + return true; + } +} + +// ---- +// testRuntime() -> true +// testCreation() -> true diff --git a/test/libsolidity/semanticTests/various/code_access_create.sol b/test/libsolidity/semanticTests/various/code_access_create.sol new file mode 100644 index 000000000..3fbcf6132 --- /dev/null +++ b/test/libsolidity/semanticTests/various/code_access_create.sol @@ -0,0 +1,26 @@ +contract D { + uint256 x; + + constructor() public { + x = 7; + } + + function f() public view returns (uint256) { + return x; + } +} + + +contract C { + function test() public returns (uint256) { + bytes memory c = type(D).creationCode; + D d; + assembly { + d := create(0, add(c, 0x20), mload(c)) + } + return d.f(); + } +} + +// ---- +// test() -> 7 diff --git a/test/libsolidity/semanticTests/various/code_access_padding.sol b/test/libsolidity/semanticTests/various/code_access_padding.sol new file mode 100644 index 000000000..ecad28a16 --- /dev/null +++ b/test/libsolidity/semanticTests/various/code_access_padding.sol @@ -0,0 +1,19 @@ +contract D { + function f() public pure returns (uint256) { + return 7; + } +} + + +contract C { + function diff() public pure returns (uint256 remainder) { + bytes memory a = type(D).creationCode; + bytes memory b = type(D).runtimeCode; + assembly { + remainder := mod(sub(b, a), 0x20) + } + } +} + +// ---- +// diff() -> 0 # This checks that the allocation function pads to multiples of 32 bytes # diff --git a/test/libsolidity/semanticTests/various/contract_binary_dependencies.sol b/test/libsolidity/semanticTests/various/contract_binary_dependencies.sol new file mode 100644 index 000000000..f1220d351 --- /dev/null +++ b/test/libsolidity/semanticTests/various/contract_binary_dependencies.sol @@ -0,0 +1,20 @@ +contract A { + function f() public { + new B(); + } +} + + +contract B { + function f() public {} +} + + +contract C { + function f() public { + new B(); + } +} + +// ---- +// constructor() -> diff --git a/test/libsolidity/semanticTests/various/crazy_elementary_typenames_on_stack.sol b/test/libsolidity/semanticTests/various/crazy_elementary_typenames_on_stack.sol new file mode 100644 index 000000000..fdd7aa32e --- /dev/null +++ b/test/libsolidity/semanticTests/various/crazy_elementary_typenames_on_stack.sol @@ -0,0 +1,15 @@ +contract C { + function f() public returns (uint256 r) { + uint256; + uint256; + uint256; + uint256; + int256 x = -7; + return uint256(x); + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> -7 diff --git a/test/libsolidity/semanticTests/various/cross_contract_types.sol b/test/libsolidity/semanticTests/various/cross_contract_types.sol new file mode 100644 index 000000000..47842cc03 --- /dev/null +++ b/test/libsolidity/semanticTests/various/cross_contract_types.sol @@ -0,0 +1,17 @@ +contract Lib { + struct S { + uint256 a; + uint256 b; + } +} + + +contract Test { + function f() public returns (uint256 r) { + Lib.S memory x = Lib.S({a: 2, b: 3}); + r = x.b; + } +} + +// ---- +// f() -> 3 diff --git a/test/libsolidity/semanticTests/various/decayed_tuple.sol b/test/libsolidity/semanticTests/various/decayed_tuple.sol new file mode 100644 index 000000000..b00942cb3 --- /dev/null +++ b/test/libsolidity/semanticTests/various/decayed_tuple.sol @@ -0,0 +1,10 @@ +contract C { + function f() public returns (uint256) { + uint256 x = 1; + (x) = 2; + return x; + } +} + +// ---- +// f() -> 2 diff --git a/test/libsolidity/semanticTests/various/destructuring_assignment.sol b/test/libsolidity/semanticTests/various/destructuring_assignment.sol new file mode 100644 index 000000000..0c8dc3835 --- /dev/null +++ b/test/libsolidity/semanticTests/various/destructuring_assignment.sol @@ -0,0 +1,36 @@ +contract C { + uint256 x = 7; + bytes data; + uint256[] y; + uint256[] arrayData; + + function returnsArray() public returns (uint256[] memory) { + arrayData = new uint256[](9); + arrayData[2] = 5; + arrayData[7] = 4; + return arrayData; + } + + function f(bytes memory s) public returns (uint256) { + uint256 loc; + uint256[] memory memArray; + (loc, x, y, data, arrayData[3]) = (8, 4, returnsArray(), s, 2); + if (loc != 8) return 1; + if (x != 4) return 2; + if (y.length != 9) return 3; + if (y[2] != 5) return 4; + if (y[7] != 4) return 5; + if (data.length != s.length) return 6; + if (data[3] != s[3]) return 7; + if (arrayData[3] != 2) return 8; + (memArray, loc) = (arrayData, 3); + if (loc != 3) return 9; + if (memArray.length != arrayData.length) return 10; + bytes memory memBytes; + (x, memBytes, y[2], , ) = (456, s, 789, 101112, 131415); + if (x != 456 || memBytes.length != s.length || y[2] != 789) return 11; + } +} + +// ---- +// f(bytes): 0x20, 0x5, "abcde" -> 0 diff --git a/test/libsolidity/semanticTests/various/empty_name_return_parameter.sol b/test/libsolidity/semanticTests/various/empty_name_return_parameter.sol new file mode 100644 index 000000000..d1ea9ab34 --- /dev/null +++ b/test/libsolidity/semanticTests/various/empty_name_return_parameter.sol @@ -0,0 +1,10 @@ +contract test { + function f(uint256 k) public returns (uint256) { + return k; + } +} + +// ==== +// compileViaYul: also +// ---- +// f(uint256): 9 -> 9 diff --git a/test/libsolidity/semanticTests/various/external_types_in_calls.sol b/test/libsolidity/semanticTests/various/external_types_in_calls.sol new file mode 100644 index 000000000..9906bd52b --- /dev/null +++ b/test/libsolidity/semanticTests/various/external_types_in_calls.sol @@ -0,0 +1,28 @@ +contract C1 { + C1 public bla; + + constructor(C1 x) public { + bla = x; + } +} + + +contract C { + function test() public returns (C1 x, C1 y) { + C1 c = new C1(C1(9)); + x = c.bla(); + y = this.t1(C1(7)); + } + + function t1(C1 a) public returns (C1) { + return a; + } + + function t2() public returns (C1) { + return C1(9); + } +} + +// ---- +// test() -> 9, 7 +// t2() -> 9 diff --git a/test/libsolidity/semanticTests/various/flipping_sign_tests.sol b/test/libsolidity/semanticTests/various/flipping_sign_tests.sol new file mode 100644 index 000000000..8309615a5 --- /dev/null +++ b/test/libsolidity/semanticTests/various/flipping_sign_tests.sol @@ -0,0 +1,10 @@ +contract test { + function f() public returns (bool) { + int256 x = -2**255; + assert(-x == x); + return true; + } +} + +// ---- +// f() -> true diff --git a/test/libsolidity/semanticTests/various/gasleft_decrease.sol b/test/libsolidity/semanticTests/various/gasleft_decrease.sol new file mode 100644 index 000000000..8de56296e --- /dev/null +++ b/test/libsolidity/semanticTests/various/gasleft_decrease.sol @@ -0,0 +1,20 @@ +contract C { + uint256 v; + + function f() public returns (bool) { + uint256 startGas = gasleft(); + v++; + assert(startGas > gasleft()); + return true; + } + + function g() public returns (bool) { + uint256 startGas = gasleft(); + assert(startGas > gasleft()); + return true; + } +} + +// ---- +// f() -> true +// g() -> true diff --git a/test/libsolidity/semanticTests/various/gasleft_shadow_resolution.sol b/test/libsolidity/semanticTests/various/gasleft_shadow_resolution.sol new file mode 100644 index 000000000..00c0eabed --- /dev/null +++ b/test/libsolidity/semanticTests/various/gasleft_shadow_resolution.sol @@ -0,0 +1,14 @@ +contract C { + function gasleft() public returns (uint256) { + return 0; + } + + function f() public returns (uint256) { + return gasleft(); + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> 0 diff --git a/test/libsolidity/semanticTests/various/inline_member_init.sol b/test/libsolidity/semanticTests/various/inline_member_init.sol new file mode 100644 index 000000000..5dca66d80 --- /dev/null +++ b/test/libsolidity/semanticTests/various/inline_member_init.sol @@ -0,0 +1,19 @@ +contract test { + constructor() public { + m_b = 6; + m_c = 8; + } + + uint256 m_a = 5; + uint256 m_b; + uint256 m_c = 7; + + function get() public returns (uint256 a, uint256 b, uint256 c) { + a = m_a; + b = m_b; + c = m_c; + } +} + +// ---- +// get() -> 5, 6, 8 diff --git a/test/libsolidity/semanticTests/various/inline_member_init_inheritence.sol b/test/libsolidity/semanticTests/various/inline_member_init_inheritence.sol new file mode 100644 index 000000000..53f5b3718 --- /dev/null +++ b/test/libsolidity/semanticTests/various/inline_member_init_inheritence.sol @@ -0,0 +1,24 @@ +contract Base { + constructor() public {} + + uint256 m_base = 5; + + function getBMember() public returns (uint256 i) { + return m_base; + } +} + + +contract Derived is Base { + constructor() public {} + + uint256 m_derived = 6; + + function getDMember() public returns (uint256 i) { + return m_derived; + } +} + +// ---- +// getBMember() -> 5 +// getDMember() -> 6 diff --git a/test/libsolidity/semanticTests/various/inline_tuple_with_rational_numbers.sol b/test/libsolidity/semanticTests/various/inline_tuple_with_rational_numbers.sol new file mode 100644 index 000000000..e350a11d3 --- /dev/null +++ b/test/libsolidity/semanticTests/various/inline_tuple_with_rational_numbers.sol @@ -0,0 +1,9 @@ +contract c { + function f() public returns (int8) { + int8[5] memory foo3 = [int8(1), -1, 0, 0, 0]; + return foo3[0]; + } +} + +// ---- +// f() -> 1 diff --git a/test/libsolidity/semanticTests/various/iszero_bnot_correct.sol b/test/libsolidity/semanticTests/various/iszero_bnot_correct.sol new file mode 100644 index 000000000..743825d60 --- /dev/null +++ b/test/libsolidity/semanticTests/various/iszero_bnot_correct.sol @@ -0,0 +1,19 @@ +// A long time ago, some opcodes were renamed, which involved the opcodes +// "iszero" and "not". +contract C { + function f() public returns (bool) { + bytes32 x = bytes32(uint256(1)); + assembly { + x := not(x) + } + if (x != ~bytes32(uint256(1))) return false; + assembly { + x := iszero(x) + } + if (x != bytes32(0)) return false; + return true; + } +} + +// ---- +// f() -> true diff --git a/test/libsolidity/semanticTests/various/literal_empty_string.sol b/test/libsolidity/semanticTests/various/literal_empty_string.sol new file mode 100644 index 000000000..bf4da5409 --- /dev/null +++ b/test/libsolidity/semanticTests/various/literal_empty_string.sol @@ -0,0 +1,20 @@ +contract C { + bytes32 public x; + uint256 public a; + + function f(bytes32 _x, uint256 _a) public { + x = _x; + a = _a; + } + + function g() public { + this.f("", 2); + } +} + +// ---- +// x() -> 0 +// a() -> 0 +// g() -> +// x() -> 0 +// a() -> 2 diff --git a/test/libsolidity/semanticTests/various/memory_overwrite.sol b/test/libsolidity/semanticTests/various/memory_overwrite.sol new file mode 100644 index 000000000..7312509e2 --- /dev/null +++ b/test/libsolidity/semanticTests/various/memory_overwrite.sol @@ -0,0 +1,10 @@ +contract C { + function f() public returns (bytes memory x) { + x = "12345"; + x[3] = 0x61; + x[0] = 0x62; + } +} + +// ---- +// f() -> 0x20, 5, "b23a5" diff --git a/test/libsolidity/semanticTests/various/multi_variable_declaration.sol b/test/libsolidity/semanticTests/various/multi_variable_declaration.sol new file mode 100644 index 000000000..6f79442e7 --- /dev/null +++ b/test/libsolidity/semanticTests/various/multi_variable_declaration.sol @@ -0,0 +1,47 @@ +contract C { + function g() public returns (uint256 a, uint256 b, uint256 c) { + a = 1; + b = 2; + c = 3; + } + + function h() public returns (uint256 a, uint256 b, uint256 c, uint256 d) { + a = 1; + b = 2; + c = 3; + d = 4; + } + + function f1() public returns (bool) { + (uint256 x, uint256 y, uint256 z) = g(); + if (x != 1 || y != 2 || z != 3) return false; + (, uint256 a, ) = g(); + if (a != 2) return false; + (uint256 b, , ) = g(); + if (b != 1) return false; + (, , uint256 c) = g(); + if (c != 3) return false; + return true; + } + + function f2() public returns (bool) { + (uint256 a1, , uint256 a3, ) = h(); + if (a1 != 1 || a3 != 3) return false; + (uint256 b1, uint256 b2, , ) = h(); + if (b1 != 1 || b2 != 2) return false; + (, uint256 c2, uint256 c3, ) = h(); + if (c2 != 2 || c3 != 3) return false; + (, , uint256 d3, uint256 d4) = h(); + if (d3 != 3 || d4 != 4) return false; + (uint256 e1, , uint256 e3, uint256 e4) = h(); + if (e1 != 1 || e3 != 3 || e4 != 4) return false; + return true; + } + + function f() public returns (bool) { + return f1() && f2(); + } +} + +// ---- +// f() -> true diff --git a/test/libsolidity/semanticTests/various/negative_stack_height.sol b/test/libsolidity/semanticTests/various/negative_stack_height.sol new file mode 100644 index 000000000..d5074dc91 --- /dev/null +++ b/test/libsolidity/semanticTests/various/negative_stack_height.sol @@ -0,0 +1,63 @@ +contract C { + mapping(uint256 => Invoice) public invoices; + struct Invoice { + uint256 AID; + bool Aboola; + bool Aboolc; + bool exists; + } + + function nredit(uint256 startindex) + public + pure + returns ( + uint256[500] memory CIDs, + uint256[500] memory dates, + uint256[500] memory RIDs, + bool[500] memory Cboolas, + uint256[500] memory amounts + ) + {} + + function return500InvoicesByDates( + uint256 begindate, + uint256 enddate, + uint256 startindex + ) + public + view + returns ( + uint256[500] memory AIDs, + bool[500] memory Aboolas, + uint256[500] memory dates, + bytes32[3][500] memory Abytesas, + bytes32[3][500] memory bytesbs, + bytes32[2][500] memory bytescs, + uint256[500] memory amounts, + bool[500] memory Aboolbs, + bool[500] memory Aboolcs + ) + {} + + function return500PaymentsByDates( + uint256 begindate, + uint256 enddate, + uint256 startindex + ) + public + view + returns ( + uint256[500] memory BIDs, + uint256[500] memory dates, + uint256[500] memory RIDs, + bool[500] memory Bboolas, + bytes32[3][500] memory bytesbs, + bytes32[2][500] memory bytescs, + uint256[500] memory amounts, + bool[500] memory Bboolbs + ) + {} +} + +// ---- +// constructor() -> diff --git a/test/libsolidity/semanticTests/various/nested_calldata_struct.sol b/test/libsolidity/semanticTests/various/nested_calldata_struct.sol new file mode 100644 index 000000000..f02fda353 --- /dev/null +++ b/test/libsolidity/semanticTests/various/nested_calldata_struct.sol @@ -0,0 +1,26 @@ +pragma experimental ABIEncoderV2; + + +contract C { + struct S1 { + uint256 a; + uint256 b; + } + struct S2 { + uint256 a; + uint256 b; + S1 s; + uint256 c; + } + + function f(S2 calldata s) + external + pure + returns (uint256 a, uint256 b, uint256 sa, uint256 sb, uint256 c) + { + return (s.a, s.b, s.s.a, s.s.b, s.c); + } +} + +// ---- +// f((uint256,uint256,(uint256,uint256),uint256)): 1, 2, 3, 4, 5 -> 1, 2, 3, 4, 5 diff --git a/test/libsolidity/semanticTests/various/nested_calldata_struct_to_memory.sol b/test/libsolidity/semanticTests/various/nested_calldata_struct_to_memory.sol new file mode 100644 index 000000000..e0a25a857 --- /dev/null +++ b/test/libsolidity/semanticTests/various/nested_calldata_struct_to_memory.sol @@ -0,0 +1,27 @@ +pragma experimental ABIEncoderV2; + + +contract C { + struct S1 { + uint256 a; + uint256 b; + } + struct S2 { + uint256 a; + uint256 b; + S1 s; + uint256 c; + } + + function f(S2 calldata s) + external + pure + returns (uint256 a, uint256 b, uint256 sa, uint256 sb, uint256 c) + { + S2 memory m = s; + return (m.a, m.b, m.s.a, m.s.b, m.c); + } +} + +// ---- +// f((uint256,uint256,(uint256,uint256),uint256)): 1, 2, 3, 4, 5 -> 1, 2, 3, 4, 5 diff --git a/test/libsolidity/semanticTests/various/positive_integers_to_signed.sol b/test/libsolidity/semanticTests/various/positive_integers_to_signed.sol new file mode 100644 index 000000000..9ba67b198 --- /dev/null +++ b/test/libsolidity/semanticTests/various/positive_integers_to_signed.sol @@ -0,0 +1,10 @@ +contract test { + int8 public x = 2; + int8 public y = 127; + int16 public q = 250; +} + +// ---- +// x() -> 2 +// y() -> 127 +// q() -> 250 diff --git a/test/libsolidity/semanticTests/various/senders_balance.sol b/test/libsolidity/semanticTests/various/senders_balance.sol new file mode 100644 index 000000000..0c84352b6 --- /dev/null +++ b/test/libsolidity/semanticTests/various/senders_balance.sol @@ -0,0 +1,20 @@ +contract C { + function f() public view returns (uint256) { + return msg.sender.balance; + } +} + + +contract D { + C c = new C(); + + constructor() public payable {} + + function f() public view returns (uint256) { + return c.f(); + } +} + +// ---- +// constructor(), 27 wei -> +// f() -> 27 diff --git a/test/libsolidity/semanticTests/various/single_copy_with_multiple_inheritance.sol b/test/libsolidity/semanticTests/various/single_copy_with_multiple_inheritance.sol new file mode 100644 index 000000000..0864121de --- /dev/null +++ b/test/libsolidity/semanticTests/various/single_copy_with_multiple_inheritance.sol @@ -0,0 +1,35 @@ +contract Base { + uint256 data; + + function setData(uint256 i) public { + data = i; + } + + function getViaBase() public returns (uint256 i) { + return data; + } +} + + +contract A is Base { + function setViaA(uint256 i) public { + setData(i); + } +} + + +contract B is Base { + function getViaB() public returns (uint256 i) { + return getViaBase(); + } +} + + +contract Derived is Base, B, A {} + +// ==== +// compileViaYul: also +// ---- +// getViaB() -> 0 +// setViaA(uint256): 23 -> +// getViaB() -> 23 diff --git a/test/libsolidity/semanticTests/various/skip_dynamic_types.sol b/test/libsolidity/semanticTests/various/skip_dynamic_types.sol new file mode 100644 index 000000000..350ea2622 --- /dev/null +++ b/test/libsolidity/semanticTests/various/skip_dynamic_types.sol @@ -0,0 +1,15 @@ +// The EVM cannot provide access to dynamically-sized return values, so we have to skip them. +contract C { + function f() public returns (uint256, uint256[] memory, uint256) { + return (7, new uint256[](2), 8); + } + + function g() public returns (uint256, uint256) { + // Previous implementation "moved" b to the second place and did not skip. + (uint256 a, , uint256 b) = this.f(); + return (a, b); + } +} + +// ---- +// g() -> 7, 8 diff --git a/test/libsolidity/semanticTests/various/skip_dynamic_types_for_structs.sol b/test/libsolidity/semanticTests/various/skip_dynamic_types_for_structs.sol new file mode 100644 index 000000000..3b80cf973 --- /dev/null +++ b/test/libsolidity/semanticTests/various/skip_dynamic_types_for_structs.sol @@ -0,0 +1,22 @@ +// For accessors, the dynamic types are already removed in the external signature itself. +contract C { + struct S { + uint256 x; + string a; // this is present in the accessor + uint256[] b; // this is not present + uint256 y; + } + S public s; + + function g() public returns (uint256, uint256) { + s.x = 2; + s.a = "abc"; + s.b = [7, 8, 9]; + s.y = 6; + (uint256 x, , uint256 y) = this.s(); + return (x, y); + } +} + +// ---- +// g() -> 2, 6 diff --git a/test/libsolidity/semanticTests/various/state_variable_local_variable_mixture.sol b/test/libsolidity/semanticTests/various/state_variable_local_variable_mixture.sol new file mode 100644 index 000000000..585914c80 --- /dev/null +++ b/test/libsolidity/semanticTests/various/state_variable_local_variable_mixture.sol @@ -0,0 +1,11 @@ +contract A { + uint256 x = 1; + uint256 y = 2; + + function a() public returns (uint256 x) { + x = A.y; + } +} + +// ---- +// a() -> 2 diff --git a/test/libsolidity/semanticTests/various/state_variable_under_contract_name.sol b/test/libsolidity/semanticTests/various/state_variable_under_contract_name.sol new file mode 100644 index 000000000..6bef6f85a --- /dev/null +++ b/test/libsolidity/semanticTests/various/state_variable_under_contract_name.sol @@ -0,0 +1,10 @@ +contract Scope { + uint256 stateVar = 42; + + function getStateVar() public view returns (uint256 stateVar) { + stateVar = Scope.stateVar; + } +} + +// ---- +// getStateVar() -> 42 diff --git a/test/libsolidity/semanticTests/various/storage_string_as_mapping_key_without_variable.sol b/test/libsolidity/semanticTests/various/storage_string_as_mapping_key_without_variable.sol new file mode 100644 index 000000000..7a8a2c276 --- /dev/null +++ b/test/libsolidity/semanticTests/various/storage_string_as_mapping_key_without_variable.sol @@ -0,0 +1,11 @@ +contract Test { + mapping(string => uint256) data; + + function f() public returns (uint256) { + data["abc"] = 2; + return data["abc"]; + } +} + +// ---- +// f() -> 2 diff --git a/test/libsolidity/semanticTests/various/store_bytes.sol b/test/libsolidity/semanticTests/various/store_bytes.sol new file mode 100644 index 000000000..99eb1acff --- /dev/null +++ b/test/libsolidity/semanticTests/various/store_bytes.sol @@ -0,0 +1,14 @@ +// this test just checks that the copy loop does not mess up the stack +contract C { + function save() public returns (uint256 r) { + r = 23; + savedData = msg.data; + r = 24; + } + + bytes savedData; +} + +// ---- +// save() -> 24 # empty copy loop # +// save(): "abcdefg" -> 24 diff --git a/test/libsolidity/semanticTests/various/string_tuples.sol b/test/libsolidity/semanticTests/various/string_tuples.sol new file mode 100644 index 000000000..3269d97c0 --- /dev/null +++ b/test/libsolidity/semanticTests/various/string_tuples.sol @@ -0,0 +1,17 @@ +contract C { + function f() public returns (string memory, uint256) { + return ("abc", 8); + } + + function g() public returns (string memory, string memory) { + return (h(), "def"); + } + + function h() public returns (string memory) { + return ("abc"); + } +} + +// ---- +// f() -> 0x40, 0x8, 0x3, "abc" +// g() -> 0x40, 0x80, 0x3, "abc", 0x3, "def" diff --git a/test/libsolidity/semanticTests/various/super.sol b/test/libsolidity/semanticTests/various/super.sol new file mode 100644 index 000000000..16e4257e1 --- /dev/null +++ b/test/libsolidity/semanticTests/various/super.sol @@ -0,0 +1,29 @@ +contract A { + function f() public virtual returns (uint256 r) { + return 1; + } +} + + +contract B is A { + function f() public virtual override returns (uint256 r) { + return super.f() | 2; + } +} + + +contract C is A { + function f() public virtual override returns (uint256 r) { + return super.f() | 4; + } +} + + +contract D is B, C { + function f() public override(B, C) returns (uint256 r) { + return super.f() | 8; + } +} + +// ---- +// f() -> 15 diff --git a/test/libsolidity/semanticTests/various/super_alone.sol b/test/libsolidity/semanticTests/various/super_alone.sol new file mode 100644 index 000000000..623f25330 --- /dev/null +++ b/test/libsolidity/semanticTests/various/super_alone.sol @@ -0,0 +1,10 @@ +contract A { + function f() public { + super; + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> diff --git a/test/libsolidity/semanticTests/various/swap_in_storage_overwrite.sol b/test/libsolidity/semanticTests/various/swap_in_storage_overwrite.sol new file mode 100644 index 000000000..59907b476 --- /dev/null +++ b/test/libsolidity/semanticTests/various/swap_in_storage_overwrite.sol @@ -0,0 +1,34 @@ +// This tests a swap in storage which does not work as one +// might expect because we do not have temporary storage. +// (x, y) = (y, x) is the same as +// y = x; +// x = y; +contract c { + struct S { + uint256 a; + uint256 b; + } + S public x; + S public y; + + function set() public { + x.a = 1; + x.b = 2; + y.a = 3; + y.b = 4; + } + + function swap() public { + (x, y) = (y, x); + } +} + +// ---- +// x() -> 0, 0 +// y() -> 0, 0 +// set() -> +// x() -> 1, 2 +// y() -> 3, 4 +// swap() -> +// x() -> 1, 2 +// y() -> 1, 2 diff --git a/test/libsolidity/semanticTests/various/test_underscore_in_hex.sol b/test/libsolidity/semanticTests/various/test_underscore_in_hex.sol new file mode 100644 index 000000000..1f12ba390 --- /dev/null +++ b/test/libsolidity/semanticTests/various/test_underscore_in_hex.sol @@ -0,0 +1,11 @@ +contract test { + function f(bool cond) public pure returns (uint256) { + uint32 x = 0x1234_ab; + uint256 y = 0x1234_abcd_1234; + return cond ? x : y; + } +} +// ---- +// f(bool): true -> 0x1234ab +// f(bool): false -> 0x1234abcd1234 + diff --git a/test/libsolidity/semanticTests/various/tuples.sol b/test/libsolidity/semanticTests/various/tuples.sol new file mode 100644 index 000000000..00fcd6f9a --- /dev/null +++ b/test/libsolidity/semanticTests/various/tuples.sol @@ -0,0 +1,30 @@ +contract C { + uint256[] data; + uint256[] m_c; + + function g() internal returns (uint256 a, uint256 b, uint256[] storage c) { + return (1, 2, data); + } + + function h() external returns (uint256 a, uint256 b) { + return (5, 6); + } + + function f() public returns (uint256) { + data.push(3); + uint256 a; + uint256 b; + (a, b) = this.h(); + if (a != 5 || b != 6) return 1; + uint256[] storage c = m_c; + (a, b, c) = g(); + if (a != 1 || b != 2 || c[0] != 3) return 2; + (a, b) = (b, a); + if (a != 2 || b != 1) return 3; + (a, , b, , ) = (8, 9, 10, 11, 12); + if (a != 8 || b != 10) return 4; + } +} + +// ---- +// f() -> 0 diff --git a/test/libsolidity/semanticTests/various/typed_multi_variable_declaration.sol b/test/libsolidity/semanticTests/various/typed_multi_variable_declaration.sol new file mode 100644 index 000000000..1ab8586fc --- /dev/null +++ b/test/libsolidity/semanticTests/various/typed_multi_variable_declaration.sol @@ -0,0 +1,26 @@ +contract C { + struct S { + uint256 x; + } + S s; + + function g() internal returns (uint256, S storage, uint256) { + s.x = 7; + return (1, s, 2); + } + + function f() public returns (bool) { + (uint256 x1, S storage y1, uint256 z1) = g(); + if (x1 != 1 || y1.x != 7 || z1 != 2) return false; + (, S storage y2, ) = g(); + if (y2.x != 7) return false; + (uint256 x2, , ) = g(); + if (x2 != 1) return false; + (, , uint256 z2) = g(); + if (z2 != 2) return false; + return true; + } +} + +// ---- +// f() -> true diff --git a/test/libsolidity/semanticTests/various/value_complex.sol b/test/libsolidity/semanticTests/various/value_complex.sol new file mode 100644 index 000000000..19d11342f --- /dev/null +++ b/test/libsolidity/semanticTests/various/value_complex.sol @@ -0,0 +1,23 @@ +contract helper { + function getBalance() public payable returns (uint256 myBalance) { + return address(this).balance; + } +} + + +contract test { + helper h; + + constructor() public payable { + h = new helper(); + } + + function sendAmount(uint256 amount) public payable returns (uint256 bal) { + uint256 someStackElement = 20; + return h.getBalance.value(amount).gas(1000).value(amount + 3)(); + } +} + +// ---- +// constructor(), 20 wei -> +// sendAmount(uint256): 5 -> 8 diff --git a/test/libsolidity/semanticTests/various/value_insane.sol b/test/libsolidity/semanticTests/various/value_insane.sol new file mode 100644 index 000000000..d74a0f7f4 --- /dev/null +++ b/test/libsolidity/semanticTests/various/value_insane.sol @@ -0,0 +1,22 @@ +contract helper { + function getBalance() public payable returns (uint256 myBalance) { + return address(this).balance; + } +} + + +contract test { + helper h; + + constructor() public payable { + h = new helper(); + } + + function sendAmount(uint256 amount) public returns (uint256 bal) { + return h.getBalance.value(amount).gas(1000).value(amount + 3)(); // overwrite value + } +} + +// ---- +// constructor(), 20 wei -> +// sendAmount(uint256): 5 -> 8 diff --git a/test/libsolidity/semanticTests/various/write_storage_external.sol b/test/libsolidity/semanticTests/various/write_storage_external.sol new file mode 100644 index 000000000..0bbe52248 --- /dev/null +++ b/test/libsolidity/semanticTests/various/write_storage_external.sol @@ -0,0 +1,40 @@ +contract C { + uint256 public x; + + function f(uint256 y) public payable { + x = y; + } + + function g(uint256 y) external { + x = y; + } + + function h() public { + this.g(12); + } +} + + +contract D { + C c = new C(); + + function f() public payable returns (uint256) { + c.g(3); + return c.x(); + } + + function g() public returns (uint256) { + c.g(8); + return c.x(); + } + + function h() public returns (uint256) { + c.h(); + return c.x(); + } +} + +// ---- +// f() -> 3 +// g() -> 8 +// h() -> 12 diff --git a/test/libsolidity/semanticTests/viaYul/array_2d_assignment.sol b/test/libsolidity/semanticTests/viaYul/array_2d_assignment.sol new file mode 100644 index 000000000..ff9c03cbe --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/array_2d_assignment.sol @@ -0,0 +1,14 @@ +contract C { + function f(uint n) public pure returns (uint) { + uint[][] memory a = new uint[][](2); + for (uint i = 0; i < 2; ++i) + a[i] = new uint[](3); + a[1][1] = n; + uint[] memory b = a[1]; + return b[1]; + } +} +// ==== +// compileViaYul: also +// ---- +// f(uint256): 42 -> 42 diff --git a/test/libsolidity/semanticTests/viaYul/array_2d_new.sol b/test/libsolidity/semanticTests/viaYul/array_2d_new.sol new file mode 100644 index 000000000..bfc8b2013 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/array_2d_new.sol @@ -0,0 +1,12 @@ +contract C { + function f(uint n) public pure returns (uint) { + uint[][] memory a = new uint[][](2); + for (uint i = 0; i < 2; ++i) + a[i] = new uint[](3); + return a[0][0] = n; + } +} +// ==== +// compileViaYul: also +// ---- +// f(uint256): 42 -> 42 diff --git a/test/libsolidity/semanticTests/viaYul/array_3d_assignment.sol b/test/libsolidity/semanticTests/viaYul/array_3d_assignment.sol new file mode 100644 index 000000000..a2b3de54f --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/array_3d_assignment.sol @@ -0,0 +1,19 @@ +contract C { + function f(uint n) public pure returns (uint) { + uint[][][] memory a = new uint[][][](2); + for (uint i = 0; i < 2; ++i) + { + a[i] = new uint[][](3); + for (uint j = 0; j < 3; ++j) + a[i][j] = new uint[](4); + } + a[1][1][1] = n; + uint[][] memory b = a[1]; + uint[] memory c = b[1]; + return c[1]; + } +} +// ==== +// compileViaYul: also +// ---- +// f(uint256): 42 -> 42 diff --git a/test/libsolidity/semanticTests/viaYul/array_3d_new.sol b/test/libsolidity/semanticTests/viaYul/array_3d_new.sol new file mode 100644 index 000000000..c3ff22ca3 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/array_3d_new.sol @@ -0,0 +1,16 @@ +contract C { + function f(uint n) public pure returns (uint) { + uint[][][] memory a = new uint[][][](2); + for (uint i = 0; i < 2; ++i) + { + a[i] = new uint[][](3); + for (uint j = 0; j < 3; ++j) + a[i][j] = new uint[](4); + } + return a[1][1][1] = n; + } +} +// ==== +// compileViaYul: also +// ---- +// f(uint256): 42 -> 42 diff --git a/test/libsolidity/semanticTests/viaYul/calldata_array_index_range_access.sol b/test/libsolidity/semanticTests/viaYul/calldata_array_index_range_access.sol new file mode 100644 index 000000000..d0e4ee595 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/calldata_array_index_range_access.sol @@ -0,0 +1,45 @@ +pragma experimental ABIEncoderV2; +contract C { + function f(uint256[] calldata x, uint256 s, uint256 e) external returns (uint256) { + return uint256[](x[s:e]).length; + } + function f(uint256[] calldata x, uint256 s, uint256 e, uint256 ss, uint256 ee) external returns (uint256) { + return uint256[](x[s:e][ss:ee]).length; + } + function f_s_only(uint256[] calldata x, uint256 s) external returns (uint256) { + return uint256[](x[s:]).length; + } + function f_e_only(uint256[] calldata x, uint256 e) external returns (uint256) { + return uint256[](x[:e]).length; + } + function g(uint256[] calldata x, uint256 s, uint256 e, uint256 idx) external returns (uint256) { + return uint256[](x[s:e])[idx]; + } + function gg(uint256[] calldata x, uint256 s, uint256 e, uint256 idx) external returns (uint256) { + return x[s:e][idx]; + } + function gg_s_only(uint256[] calldata x, uint256 s, uint256 idx) external returns (uint256) { + return x[s:][idx]; + } + function gg_e_only(uint256[] calldata x, uint256 e, uint256 idx) external returns (uint256) { + return x[:e][idx]; + } +} +// ==== +// compileViaYul: also +// ---- +// f(uint256[],uint256,uint256): 0x60, 2, 4, 5, 1, 2, 3, 4, 5 -> 2 +// f(uint256[],uint256,uint256): 0x60, 2, 6, 5, 1, 2, 3, 4, 5 -> FAILURE +// f(uint256[],uint256,uint256): 0x60, 3, 3, 5, 1, 2, 3, 4, 5 -> 0 +// f(uint256[],uint256,uint256): 0x60, 4, 3, 5, 1, 2, 3, 4, 5 -> FAILURE +// f(uint256[],uint256,uint256): 0x60, 0, 3, 5, 1, 2, 3, 4, 5 -> 3 +// f(uint256[],uint256,uint256,uint256,uint256): 0xA0, 1, 3, 1, 2, 5, 1, 2, 3, 4, 5 -> 1 +// f(uint256[],uint256,uint256,uint256,uint256): 0xA0, 1, 3, 1, 4, 5, 1, 2, 3, 4, 5 -> FAILURE +// f_s_only(uint256[],uint256): 0x40, 2, 5, 1, 2, 3, 4, 5 -> 3 +// f_s_only(uint256[],uint256): 0x40, 6, 5, 1, 2, 3, 4, 5 -> FAILURE +// f_e_only(uint256[],uint256): 0x40, 3, 5, 1, 2, 3, 4, 5 -> 3 +// f_e_only(uint256[],uint256): 0x40, 6, 5, 1, 2, 3, 4, 5 -> FAILURE +// g(uint256[],uint256,uint256,uint256): 0x80, 2, 4, 1, 5, 1, 2, 3, 4, 5 -> 4 +// g(uint256[],uint256,uint256,uint256): 0x80, 2, 4, 3, 5, 1, 2, 3, 4, 5 -> FAILURE +// gg(uint256[],uint256,uint256,uint256): 0x80, 2, 4, 1, 5, 1, 2, 3, 4, 5 -> 4 +// gg(uint256[],uint256,uint256,uint256): 0x80, 2, 4, 3, 5, 1, 2, 3, 4, 5 -> FAILURE diff --git a/test/libsolidity/semanticTests/viaYul/detect_mod_zero.sol b/test/libsolidity/semanticTests/viaYul/detect_mod_zero.sol index d8defa17a..6340c71c3 100644 --- a/test/libsolidity/semanticTests/viaYul/detect_mod_zero.sol +++ b/test/libsolidity/semanticTests/viaYul/detect_mod_zero.sol @@ -7,7 +7,7 @@ contract C { } } // ==== -// compileViaYul: only +// compileViaYul: true // ---- // f(uint256,uint256): 10, 3 -> 1 // f(uint256,uint256): 10, 2 -> 0 diff --git a/test/libsolidity/semanticTests/viaYul/detect_mod_zero_signed.sol b/test/libsolidity/semanticTests/viaYul/detect_mod_zero_signed.sol index 9164bf06c..d93e18d06 100644 --- a/test/libsolidity/semanticTests/viaYul/detect_mod_zero_signed.sol +++ b/test/libsolidity/semanticTests/viaYul/detect_mod_zero_signed.sol @@ -7,7 +7,7 @@ contract C { } } // ==== -// compileViaYul: only +// compileViaYul: true // ---- // f(int256,int256): 10, 3 -> 1 // f(int256,int256): 10, 2 -> 0 diff --git a/test/libsolidity/semanticTests/viaYul/keccak.sol b/test/libsolidity/semanticTests/viaYul/keccak.sol index 887faf9e4..58c37ebd6 100644 --- a/test/libsolidity/semanticTests/viaYul/keccak.sol +++ b/test/libsolidity/semanticTests/viaYul/keccak.sol @@ -8,7 +8,7 @@ contract C { } } // ==== -// compileViaYul: only +// compileViaYul: true // ---- // keccak1() -> 0x64e604787cbf194841e7b68d7cd28786f6c9a0a3ab9f8b0a0e87cb4387ab0107 // keccak2() -> 0x64e604787cbf194841e7b68d7cd28786f6c9a0a3ab9f8b0a0e87cb4387ab0107 diff --git a/test/libsolidity/semanticTests/viaYul/mapping_string_key.sol b/test/libsolidity/semanticTests/viaYul/mapping_string_key.sol new file mode 100644 index 000000000..880522d60 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/mapping_string_key.sol @@ -0,0 +1,10 @@ +contract C { + mapping (string => uint) map; + function set(string memory s) public { + map[s]; + } +} +// ==== +// compileViaYul: true +// ---- +// set(string): 0x20, 32, "01234567890123456789012345678901" -> diff --git a/test/libsolidity/semanticTests/viaYul/string_format.sol b/test/libsolidity/semanticTests/viaYul/string_format.sol index 2d9d71d7c..98e4d1081 100644 --- a/test/libsolidity/semanticTests/viaYul/string_format.sol +++ b/test/libsolidity/semanticTests/viaYul/string_format.sol @@ -5,7 +5,7 @@ contract C { function h() external pure returns (bytes4) { return 0xcafecafe; } } // ==== -// compileViaYul: only +// compileViaYul: true // ---- // f1() -> 0x20, 6, left(0x616263616263) // f2() -> 32, 47, 44048183223289766195424279195050628400112610419087780792899004030957505095210, 18165586057823232067963737336409268114628061002662705707816940456850361417728 diff --git a/test/libsolidity/semanticTests/virtualFunctions/virtual_function_calls.sol b/test/libsolidity/semanticTests/virtualFunctions/virtual_function_calls.sol new file mode 100644 index 000000000..33d151f82 --- /dev/null +++ b/test/libsolidity/semanticTests/virtualFunctions/virtual_function_calls.sol @@ -0,0 +1,22 @@ +contract Base { + function f() public returns (uint256 i) { + return g(); + } + + function g() public virtual returns (uint256 i) { + return 1; + } +} + + +contract Derived is Base { + function g() public override returns (uint256 i) { + return 2; + } +} + +// ==== +// compileViaYul: also +// ---- +// g() -> 2 +// f() -> 2 diff --git a/test/libsolidity/semanticTests/virtualFunctions/virtual_function_usage_in_constructor_arguments.sol b/test/libsolidity/semanticTests/virtualFunctions/virtual_function_usage_in_constructor_arguments.sol new file mode 100644 index 000000000..590294f15 --- /dev/null +++ b/test/libsolidity/semanticTests/virtualFunctions/virtual_function_usage_in_constructor_arguments.sol @@ -0,0 +1,32 @@ +contract BaseBase { + uint256 m_a; + + constructor(uint256 a) public { + m_a = a; + } + + function overridden() public virtual returns (uint256 r) { + return 1; + } + + function g() public returns (uint256 r) { + return overridden(); + } +} + + +contract Base is BaseBase(BaseBase.g()) {} + + +contract Derived is Base { + function getA() public returns (uint256 r) { + return m_a; + } + + function overridden() public override returns (uint256 r) { + return 2; + } +} + +// ---- +// getA() -> 2 diff --git a/test/libsolidity/syntaxTests/immutable/as_function_param.sol b/test/libsolidity/syntaxTests/immutable/as_function_param.sol new file mode 100644 index 000000000..3636b0aef --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/as_function_param.sol @@ -0,0 +1,5 @@ +contract C { + function f(uint immutable) public pure {} +} +// ---- +// DeclarationError: (28-42): The "immutable" keyword can only be used for state variables. diff --git a/test/libsolidity/syntaxTests/immutable/assembly.sol b/test/libsolidity/syntaxTests/immutable/assembly.sol new file mode 100644 index 000000000..7b98b67c6 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/assembly.sol @@ -0,0 +1,11 @@ +contract C { + uint immutable x; + function f() public view { + uint t; + assembly { + t := x + } + } +} +// ---- +// TypeError: (118-119): Assembly access to immutable variables is not supported. diff --git a/test/libsolidity/syntaxTests/immutable/double_specifier.sol b/test/libsolidity/syntaxTests/immutable/double_specifier.sol new file mode 100644 index 000000000..39f0f1e76 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/double_specifier.sol @@ -0,0 +1,7 @@ +contract C { + uint immutable immutable x; + uint immutable constant x; +} +// ---- +// ParserError: (32-41): Constantness already set to "immutable" +// ParserError: (64-72): Constantness already set to "immutable" diff --git a/test/libsolidity/syntaxTests/immutable/getter.sol b/test/libsolidity/syntaxTests/immutable/getter.sol new file mode 100644 index 000000000..7740f8643 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/getter.sol @@ -0,0 +1,5 @@ +contract C { + uint immutable public x; +} +// ---- +// UnimplementedFeatureError: NONE diff --git a/test/libsolidity/syntaxTests/immutable/immutable_basic.sol b/test/libsolidity/syntaxTests/immutable/immutable_basic.sol new file mode 100644 index 000000000..b4960f25b --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/immutable_basic.sol @@ -0,0 +1,3 @@ +contract C { + uint immutable x; +} \ No newline at end of file diff --git a/test/libsolidity/syntaxTests/immutable/non-value_type.sol b/test/libsolidity/syntaxTests/immutable/non-value_type.sol new file mode 100644 index 000000000..67398ce20 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/non-value_type.sol @@ -0,0 +1,5 @@ +contract C { + uint[] immutable x; +} +// ---- +// TypeError: (17-35): Immutable variables cannot have a non-value type. diff --git a/test/libsolidity/syntaxTests/inheritance/override/public_var_override_mapping_to_dynamic_struct.sol b/test/libsolidity/syntaxTests/inheritance/override/public_var_override_mapping_to_dynamic_struct.sol new file mode 100644 index 000000000..d02284aef --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/override/public_var_override_mapping_to_dynamic_struct.sol @@ -0,0 +1,12 @@ +pragma experimental ABIEncoderV2; + +abstract contract C { + struct S { + uint256 x; + string y; + } + function f(address x) external virtual returns (uint256, string memory); +} +contract D is C { + mapping(address => S) public override f; +} diff --git a/test/libsolidity/syntaxTests/inheritance/override/public_var_override_struct_with_memory_element.sol b/test/libsolidity/syntaxTests/inheritance/override/public_var_override_struct_with_memory_element.sol new file mode 100644 index 000000000..4e6e02598 --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/override/public_var_override_struct_with_memory_element.sol @@ -0,0 +1,13 @@ +pragma experimental ABIEncoderV2; + +abstract contract C { + struct S { + uint256 x; + string y; + } + + function f() external virtual returns (uint256, string memory); +} +contract D is C { + S public override f; +} diff --git a/test/libsolidity/syntaxTests/inlineAssembly/const_from_non_const.sol b/test/libsolidity/syntaxTests/inlineAssembly/const_from_non_const.sol new file mode 100644 index 000000000..fbd5ab6ee --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/const_from_non_const.sol @@ -0,0 +1,12 @@ +contract C { + bool nc = false; + bool constant c = nc; + function f() public { + assembly { + let t := c + } + } +} +// ---- +// TypeError: (52-54): Initial value for constant variable has to be compile-time constant. +// TypeError: (112-113): Only direct number constants and references to such constants are supported by inline assembly. diff --git a/test/libsolidity/syntaxTests/inlineAssembly/const_from_this.sol b/test/libsolidity/syntaxTests/inlineAssembly/const_from_this.sol new file mode 100644 index 000000000..563d47851 --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/const_from_this.sol @@ -0,0 +1,12 @@ +contract C { + bool constant c = this; + function f() public { + assembly { + let t := c + } + } +} +// ---- +// TypeError: (33-37): Type contract C is not implicitly convertible to expected type bool. +// TypeError: (33-37): Initial value for constant variable has to be compile-time constant. +// TypeError: (95-96): Only direct number constants and references to such constants are supported by inline assembly. diff --git a/test/libsolidity/syntaxTests/viewPureChecker/immutable.sol b/test/libsolidity/syntaxTests/viewPureChecker/immutable.sol new file mode 100644 index 000000000..1c0e7a46f --- /dev/null +++ b/test/libsolidity/syntaxTests/viewPureChecker/immutable.sol @@ -0,0 +1,8 @@ +contract B { + uint immutable x; + function f() public pure returns (uint) { + return x; + } +} +// ---- +// TypeError: (96-97): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view". diff --git a/test/libyul/Common.cpp b/test/libyul/Common.cpp index ff1517eec..ee6d77dab 100644 --- a/test/libyul/Common.cpp +++ b/test/libyul/Common.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -106,3 +107,51 @@ string yul::test::format(string const& _source, bool _yul) { return yul::AsmPrinter()(*parse(_source, _yul).first); } + +namespace +{ +std::map const validDialects = { + { + "evm", + [](langutil::EVMVersion _evmVersion) -> yul::Dialect const& + { return yul::EVMDialect::strictAssemblyForEVMObjects(_evmVersion); } + }, + { + "evmTyped", + [](langutil::EVMVersion _evmVersion) -> yul::Dialect const& + { return yul::EVMDialectTyped::instance(_evmVersion); } + }, + { + "yul", + [](langutil::EVMVersion) -> yul::Dialect const& + { return yul::Dialect::yulDeprecated(); } + }, + { + "ewasm", + [](langutil::EVMVersion) -> yul::Dialect const& + { return yul::WasmDialect::instance(); } + } +}; + +vector validDialectNames() +{ + vector names{size(validDialects), ""}; + transform(begin(validDialects), end(validDialects), names.begin(), [](auto const& dialect) { return dialect.first; }); + + return names; +} +} + +yul::Dialect const& yul::test::dialect(std::string const& _name, langutil::EVMVersion _evmVersion) +{ + if (!validDialects.count(_name)) + BOOST_THROW_EXCEPTION(runtime_error{ + "Invalid Dialect \"" + + _name + + "\". Valid dialects are " + + util::joinHumanReadable(validDialectNames(), ", ", " and ") + + "." + }); + + return validDialects.at(_name)(_evmVersion); +} diff --git a/test/libyul/Common.h b/test/libyul/Common.h index 0b154e69c..b5f175ac2 100644 --- a/test/libyul/Common.h +++ b/test/libyul/Common.h @@ -23,6 +23,8 @@ #include +#include + #include #include #include @@ -53,4 +55,6 @@ parse(std::string const& _source, Dialect const& _dialect, langutil::ErrorList& Block disambiguate(std::string const& _source, bool _yul = true); std::string format(std::string const& _source, bool _yul = true); +solidity::yul::Dialect const& dialect(std::string const& _name, langutil::EVMVersion _evmVersion); + } diff --git a/test/libyul/EwasmTranslationTest.cpp b/test/libyul/EwasmTranslationTest.cpp index fdee56bda..a545b6124 100644 --- a/test/libyul/EwasmTranslationTest.cpp +++ b/test/libyul/EwasmTranslationTest.cpp @@ -48,17 +48,11 @@ using namespace solidity::frontend::test; using namespace std; -EwasmTranslationTest::EwasmTranslationTest(string const& _filename) +EwasmTranslationTest::EwasmTranslationTest(string const& _filename): + EVMVersionRestrictedTestCase(_filename) { - boost::filesystem::path path(_filename); - - ifstream file(_filename); - if (!file) - BOOST_THROW_EXCEPTION(runtime_error("Cannot open test case: \"" + _filename + "\".")); - file.exceptions(ios::badbit); - - m_source = parseSourceAndSettings(file); - m_expectation = parseSimpleExpectations(file); + m_source = m_reader.source(); + m_expectation = m_reader.simpleExpectations(); } TestCase::TestResult EwasmTranslationTest::run(ostream& _stream, string const& _linePrefix, bool const _formatted) diff --git a/test/libyul/FunctionSideEffects.cpp b/test/libyul/FunctionSideEffects.cpp index 2d74d5501..db3a39df0 100644 --- a/test/libyul/FunctionSideEffects.cpp +++ b/test/libyul/FunctionSideEffects.cpp @@ -60,15 +60,11 @@ string toString(SideEffects const& _sideEffects) } } -FunctionSideEffects::FunctionSideEffects(string const& _filename) +FunctionSideEffects::FunctionSideEffects(string const& _filename): + TestCase(_filename) { - ifstream file(_filename); - if (!file) - BOOST_THROW_EXCEPTION(runtime_error("Cannot open test input: \"" + _filename + "\".")); - file.exceptions(ios::badbit); - - m_source = parseSourceAndSettings(file); - m_expectation = parseSimpleExpectations(file); + m_source = m_reader.source(); + m_expectation = m_reader.simpleExpectations(); } TestCase::TestResult FunctionSideEffects::run(ostream& _stream, string const& _linePrefix, bool _formatted) diff --git a/test/libyul/ObjectCompilerTest.cpp b/test/libyul/ObjectCompilerTest.cpp index f1b284042..9dd589748 100644 --- a/test/libyul/ObjectCompilerTest.cpp +++ b/test/libyul/ObjectCompilerTest.cpp @@ -38,23 +38,12 @@ using namespace solidity::frontend; using namespace solidity::frontend::test; using namespace std; -ObjectCompilerTest::ObjectCompilerTest(string const& _filename) +ObjectCompilerTest::ObjectCompilerTest(string const& _filename): + TestCase(_filename) { - boost::filesystem::path path(_filename); - - ifstream file(_filename); - if (!file) - BOOST_THROW_EXCEPTION(runtime_error("Cannot open test case: \"" + _filename + "\".")); - file.exceptions(ios::badbit); - - m_source = parseSourceAndSettings(file); - if (m_settings.count("optimize")) - { - m_optimize = true; - m_validatedSettings["optimize"] = "true"; - m_settings.erase("optimize"); - } - m_expectation = parseSimpleExpectations(file); + m_source = m_reader.source(); + m_optimize = m_reader.boolSetting("optimize", false); + m_expectation = m_reader.simpleExpectations(); } TestCase::TestResult ObjectCompilerTest::run(ostream& _stream, string const& _linePrefix, bool const _formatted) diff --git a/test/libyul/SyntaxTest.cpp b/test/libyul/SyntaxTest.cpp index 75e38c844..05accb695 100644 --- a/test/libyul/SyntaxTest.cpp +++ b/test/libyul/SyntaxTest.cpp @@ -19,61 +19,22 @@ #include #include -#include -#include -#include - #include #include +#include #include +#include + using namespace std; using namespace solidity; using namespace solidity::util; using namespace solidity::langutil; using namespace solidity::yul::test; -namespace -{ -std::map const validDialects = { - { - "evm", - [](langutil::EVMVersion _evmVersion) -> yul::Dialect const& - { return yul::EVMDialect::strictAssemblyForEVM(_evmVersion); } - }, - { - "evmTyped", - [](langutil::EVMVersion _evmVersion) -> yul::Dialect const& - { return yul::EVMDialectTyped::instance(_evmVersion); } - }, - { - "yul", - [](langutil::EVMVersion) -> yul::Dialect const& - { return yul::Dialect::yulDeprecated(); } - }, - { - "ewasm", - [](langutil::EVMVersion) -> yul::Dialect const& - { return yul::WasmDialect::instance(); } - } -}; - -vector validDialectNames() -{ - vector names{size(validDialects), ""}; - transform(begin(validDialects), end(validDialects), names.begin(), [](auto const& dialect) { return dialect.first; }); - - return names; -} -} - void SyntaxTest::parseAndAnalyze() { - string dialectName = m_validatedSettings.count("dialect") ? m_validatedSettings["dialect"] : "evmTyped"; - - yul::Dialect const& dialect = validDialects.at(dialectName)(m_evmVersion); - if (m_sources.size() != 1) BOOST_THROW_EXCEPTION(runtime_error{"Expected only one source for yul test."}); @@ -84,12 +45,12 @@ void SyntaxTest::parseAndAnalyze() ErrorReporter errorReporter{errorList}; auto scanner = make_shared(CharStream(source, name)); - auto parserResult = yul::Parser(errorReporter, dialect).parse(scanner, false); + auto parserResult = yul::Parser(errorReporter, *m_dialect).parse(scanner, false); if (parserResult) { yul::AsmAnalysisInfo analysisInfo; - yul::AsmAnalyzer(analysisInfo, errorReporter, dialect).analyze(*parserResult); + yul::AsmAnalyzer(analysisInfo, errorReporter, *m_dialect).analyze(*parserResult); } for (auto const& error: errorList) @@ -114,23 +75,9 @@ void SyntaxTest::parseAndAnalyze() } -void SyntaxTest::validateSettings() +SyntaxTest::SyntaxTest(string const& _filename, langutil::EVMVersion _evmVersion): + CommonSyntaxTest(_filename, _evmVersion) { - CommonSyntaxTest::validateSettings(); - - if (!m_settings.count("dialect")) - return; - - string const dialect = m_settings["dialect"]; - m_validatedSettings["dialect"] = dialect; - m_settings.erase("dialect"); - - if (!validDialects.count(dialect)) - BOOST_THROW_EXCEPTION(runtime_error{ - "Invalid Dialect \"" + - dialect + - "\". Valid dialects are " + - joinHumanReadable(validDialectNames(), ", ", " and ") + - "." - }); + string dialectName = m_reader.stringSetting("dialect", "evmTyped"); + m_dialect = &dialect(dialectName, solidity::test::CommonOptions::get().evmVersion()); } diff --git a/test/libyul/SyntaxTest.h b/test/libyul/SyntaxTest.h index 087a6326c..b4c838b54 100644 --- a/test/libyul/SyntaxTest.h +++ b/test/libyul/SyntaxTest.h @@ -36,15 +36,13 @@ public: { return std::make_unique(_config.filename, _config.evmVersion); } - SyntaxTest(std::string const& _filename, langutil::EVMVersion _evmVersion): - CommonSyntaxTest(_filename, _evmVersion) {} + SyntaxTest(std::string const& _filename, langutil::EVMVersion _evmVersion); virtual ~SyntaxTest() {} - - /// Validates the settings, i.e. moves them from m_settings to m_validatedSettings. - /// Throws a runtime exception if any setting is left at this class (i.e. unknown setting). - void validateSettings() override; protected: void parseAndAnalyze() override; + +private: + Dialect const* m_dialect = nullptr; }; } diff --git a/test/libyul/YulInterpreterTest.cpp b/test/libyul/YulInterpreterTest.cpp index f37d18383..937ffb57e 100644 --- a/test/libyul/YulInterpreterTest.cpp +++ b/test/libyul/YulInterpreterTest.cpp @@ -45,17 +45,11 @@ using namespace solidity::frontend; using namespace solidity::frontend::test; using namespace std; -YulInterpreterTest::YulInterpreterTest(string const& _filename) +YulInterpreterTest::YulInterpreterTest(string const& _filename): + EVMVersionRestrictedTestCase(_filename) { - boost::filesystem::path path(_filename); - - ifstream file(_filename); - if (!file) - BOOST_THROW_EXCEPTION(runtime_error("Cannot open test case: \"" + _filename + "\".")); - file.exceptions(ios::badbit); - - m_source = parseSourceAndSettings(file); - m_expectation = parseSimpleExpectations(file); + m_source = m_reader.source(); + m_expectation = m_reader.simpleExpectations(); } TestCase::TestResult YulInterpreterTest::run(ostream& _stream, string const& _linePrefix, bool const _formatted) diff --git a/test/libyul/YulOptimizerTest.cpp b/test/libyul/YulOptimizerTest.cpp index e488460fc..9458174ed 100644 --- a/test/libyul/YulOptimizerTest.cpp +++ b/test/libyul/YulOptimizerTest.cpp @@ -89,7 +89,8 @@ using namespace solidity::frontend; using namespace solidity::frontend::test; using namespace std; -YulOptimizerTest::YulOptimizerTest(string const& _filename) +YulOptimizerTest::YulOptimizerTest(string const& _filename): + EVMVersionRestrictedTestCase(_filename) { boost::filesystem::path path(_filename); @@ -97,38 +98,12 @@ YulOptimizerTest::YulOptimizerTest(string const& _filename) BOOST_THROW_EXCEPTION(runtime_error("Filename path has to contain a directory: \"" + _filename + "\".")); m_optimizerStep = std::prev(std::prev(path.end()))->string(); - ifstream file(_filename); - soltestAssert(file, "Cannot open test contract: \"" + _filename + "\"."); - file.exceptions(ios::badbit); + m_source = m_reader.source(); - m_source = parseSourceAndSettings(file); - if (m_settings.count("dialect")) - { - auto dialectName = m_settings["dialect"]; - if (dialectName == "yul") - m_dialect = &Dialect::yulDeprecated(); - else if (dialectName == "ewasm") - m_dialect = &WasmDialect::instance(); - else if (dialectName == "evm") - m_dialect = &EVMDialect::strictAssemblyForEVMObjects(solidity::test::CommonOptions::get().evmVersion()); - else if (dialectName == "evmTyped") - m_dialect = &EVMDialectTyped::instance(solidity::test::CommonOptions::get().evmVersion()); - else - BOOST_THROW_EXCEPTION(runtime_error("Invalid dialect " + dialectName)); + auto dialectName = m_reader.stringSetting("dialect", "evm"); + m_dialect = &dialect(dialectName, solidity::test::CommonOptions::get().evmVersion()); - m_validatedSettings["dialect"] = dialectName; - m_settings.erase("dialect"); - } - else - m_dialect = &EVMDialect::strictAssemblyForEVMObjects(solidity::test::CommonOptions::get().evmVersion()); - - if (m_settings.count("step")) - { - m_validatedSettings["step"] = m_settings["step"]; - m_settings.erase("step"); - } - - m_expectation = parseSimpleExpectations(file); + m_expectation = m_reader.simpleExpectations(); } TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _linePrefix, bool const _formatted) @@ -375,21 +350,8 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line return TestResult::FatalError; } - m_obtainedResult = AsmPrinter{*m_dialect}(*m_ast) + "\n"; + m_obtainedResult = "step: " + m_optimizerStep + "\n\n" + AsmPrinter{ *m_dialect }(*m_ast) + "\n"; - if (m_optimizerStep != m_validatedSettings["step"]) - { - string nextIndentLevel = _linePrefix + " "; - AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::CYAN}) << - _linePrefix << - "Invalid optimizer step. Given: \"" << - m_validatedSettings["step"] << - "\", should be: \"" << - m_optimizerStep << - "\"." << - endl; - return TestResult::FatalError; - } if (m_expectation != m_obtainedResult) { string nextIndentLevel = _linePrefix + " "; @@ -408,12 +370,6 @@ void YulOptimizerTest::printSource(ostream& _stream, string const& _linePrefix, printIndented(_stream, m_source, _linePrefix); } -void YulOptimizerTest::printUpdatedSettings(ostream& _stream, const string& _linePrefix, const bool _formatted) -{ - m_validatedSettings["step"] = m_optimizerStep; - EVMVersionRestrictedTestCase::printUpdatedSettings(_stream, _linePrefix, _formatted); -} - void YulOptimizerTest::printUpdatedExpectations(ostream& _stream, string const& _linePrefix) const { printIndented(_stream, m_obtainedResult, _linePrefix); diff --git a/test/libyul/YulOptimizerTest.h b/test/libyul/YulOptimizerTest.h index 41e38fca0..99e239e3b 100644 --- a/test/libyul/YulOptimizerTest.h +++ b/test/libyul/YulOptimizerTest.h @@ -57,7 +57,6 @@ public: TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool const _formatted = false) override; void printSource(std::ostream& _stream, std::string const &_linePrefix = "", bool const _formatted = false) const override; - void printUpdatedSettings(std::ostream &_stream, std::string const &_linePrefix = "", bool const _formatted = false) override; void printUpdatedExpectations(std::ostream& _stream, std::string const& _linePrefix) const override; private: diff --git a/test/libyul/yulOptimizerTests/blockFlattener/basic.yul b/test/libyul/yulOptimizerTests/blockFlattener/basic.yul index 8558737cf..e57617436 100644 --- a/test/libyul/yulOptimizerTests/blockFlattener/basic.yul +++ b/test/libyul/yulOptimizerTests/blockFlattener/basic.yul @@ -8,9 +8,9 @@ } let z := mload(2) } -// ==== -// step: blockFlattener // ---- +// step: blockFlattener +// // { // let _1 := mload(0) // let f_a := mload(1) diff --git a/test/libyul/yulOptimizerTests/blockFlattener/for_stmt.yul b/test/libyul/yulOptimizerTests/blockFlattener/for_stmt.yul index dfb88a178..a5be68a7c 100644 --- a/test/libyul/yulOptimizerTests/blockFlattener/for_stmt.yul +++ b/test/libyul/yulOptimizerTests/blockFlattener/for_stmt.yul @@ -3,9 +3,9 @@ a := add(a, 1) } } -// ==== -// step: blockFlattener // ---- +// step: blockFlattener +// // { // for { let a := 1 } iszero(eq(a, 10)) { a := add(a, 1) } // { a := add(a, 1) } diff --git a/test/libyul/yulOptimizerTests/blockFlattener/if_stmt.yul b/test/libyul/yulOptimizerTests/blockFlattener/if_stmt.yul index ca5055ac9..f31c5f979 100644 --- a/test/libyul/yulOptimizerTests/blockFlattener/if_stmt.yul +++ b/test/libyul/yulOptimizerTests/blockFlattener/if_stmt.yul @@ -8,9 +8,9 @@ } let t := add(3, 9) } -// ==== -// step: blockFlattener // ---- +// step: blockFlattener +// // { // if add(mload(7), sload(mload(3))) // { diff --git a/test/libyul/yulOptimizerTests/blockFlattener/many_nested_blocks.yul b/test/libyul/yulOptimizerTests/blockFlattener/many_nested_blocks.yul index a397000e4..d7fd4b45a 100644 --- a/test/libyul/yulOptimizerTests/blockFlattener/many_nested_blocks.yul +++ b/test/libyul/yulOptimizerTests/blockFlattener/many_nested_blocks.yul @@ -14,9 +14,9 @@ a := add(a, c) } } -// ==== -// step: blockFlattener // ---- +// step: blockFlattener +// // { // let a := 3 // let b := 4 diff --git a/test/libyul/yulOptimizerTests/blockFlattener/switch_stmt.yul b/test/libyul/yulOptimizerTests/blockFlattener/switch_stmt.yul index f3243296b..0b2a8245d 100644 --- a/test/libyul/yulOptimizerTests/blockFlattener/switch_stmt.yul +++ b/test/libyul/yulOptimizerTests/blockFlattener/switch_stmt.yul @@ -5,9 +5,9 @@ default { a := 3 { a := 4 } } a := 5 } -// ==== -// step: blockFlattener // ---- +// step: blockFlattener +// // { // let a := 1 // switch calldataload(0) diff --git a/test/libyul/yulOptimizerTests/circularReferencesPruner/called_from_non_function.yul b/test/libyul/yulOptimizerTests/circularReferencesPruner/called_from_non_function.yul index 07eca2709..739ba78bf 100644 --- a/test/libyul/yulOptimizerTests/circularReferencesPruner/called_from_non_function.yul +++ b/test/libyul/yulOptimizerTests/circularReferencesPruner/called_from_non_function.yul @@ -5,9 +5,9 @@ function h() -> z { z := g() } a := h() } -// ==== -// step: circularReferencesPruner // ---- +// step: circularReferencesPruner +// // { // let a // a := h() diff --git a/test/libyul/yulOptimizerTests/circularReferencesPruner/nested_different_names.yul b/test/libyul/yulOptimizerTests/circularReferencesPruner/nested_different_names.yul index 0630fe35f..ac04f96a8 100644 --- a/test/libyul/yulOptimizerTests/circularReferencesPruner/nested_different_names.yul +++ b/test/libyul/yulOptimizerTests/circularReferencesPruner/nested_different_names.yul @@ -8,7 +8,7 @@ function d() -> w { w := c() } } } -// ==== -// step: circularReferencesPruner // ---- +// step: circularReferencesPruner +// // { } diff --git a/test/libyul/yulOptimizerTests/circularReferencesPruner/nested_same_name.yul b/test/libyul/yulOptimizerTests/circularReferencesPruner/nested_same_name.yul index 9873c717f..02ac2317d 100644 --- a/test/libyul/yulOptimizerTests/circularReferencesPruner/nested_same_name.yul +++ b/test/libyul/yulOptimizerTests/circularReferencesPruner/nested_same_name.yul @@ -8,7 +8,7 @@ function y() -> x { x := z() } } } -// ==== -// step: circularReferencesPruner // ---- +// step: circularReferencesPruner +// // { } diff --git a/test/libyul/yulOptimizerTests/circularReferencesPruner/trivial.yul b/test/libyul/yulOptimizerTests/circularReferencesPruner/trivial.yul index c0fe6834a..4398bc29f 100644 --- a/test/libyul/yulOptimizerTests/circularReferencesPruner/trivial.yul +++ b/test/libyul/yulOptimizerTests/circularReferencesPruner/trivial.yul @@ -2,7 +2,7 @@ function f() -> x { x := g() } function g() -> x { x := f() } } -// ==== -// step: circularReferencesPruner // ---- +// step: circularReferencesPruner +// // { } diff --git a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/branches_for.yul b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/branches_for.yul index a077efcf1..ac4ed1b05 100644 --- a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/branches_for.yul +++ b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/branches_for.yul @@ -6,9 +6,9 @@ } mstore(1, codesize()) } -// ==== -// step: commonSubexpressionEliminator // ---- +// step: commonSubexpressionEliminator +// // { // let a := 1 // let b := codesize() diff --git a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/branches_if.yul b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/branches_if.yul index e664aa781..8de646ae3 100644 --- a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/branches_if.yul +++ b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/branches_if.yul @@ -3,9 +3,9 @@ if b { b := 1 } let c := 1 } -// ==== -// step: commonSubexpressionEliminator // ---- +// step: commonSubexpressionEliminator +// // { // let b := 1 // if b { b := b } diff --git a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/case2.yul b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/case2.yul index ab08c0dee..3a51b6626 100644 --- a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/case2.yul +++ b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/case2.yul @@ -23,9 +23,9 @@ p_1 := add(array, _22) } } -// ==== -// step: commonSubexpressionEliminator // ---- +// step: commonSubexpressionEliminator +// // { // let _13 := 0x20 // let _14 := allocate(_13) diff --git a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/clear_not_needed.yul b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/clear_not_needed.yul index 89075e3bb..d0e124f6b 100644 --- a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/clear_not_needed.yul +++ b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/clear_not_needed.yul @@ -7,9 +7,9 @@ a := 9 sstore(x, 3) } -// ==== -// step: commonSubexpressionEliminator // ---- +// step: commonSubexpressionEliminator +// // { // let a := calldataload(0) // let x := calldataload(0x20) diff --git a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/function_scopes.yul b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/function_scopes.yul index 957232a8f..1fd8f84f1 100644 --- a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/function_scopes.yul +++ b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/function_scopes.yul @@ -23,9 +23,9 @@ let _11 := array_index_access(x, _10) mstore(_11, _9) } -// ==== -// step: commonSubexpressionEliminator // ---- +// step: commonSubexpressionEliminator +// // { // function allocate(size) -> p // { diff --git a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/loop.yul b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/loop.yul index 4725a444e..2848ef3f1 100644 --- a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/loop.yul +++ b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/loop.yul @@ -35,9 +35,9 @@ } sstore(_1, sum_50) } -// ==== -// step: commonSubexpressionEliminator // ---- +// step: commonSubexpressionEliminator +// // { // let _1 := 0 // let _33 := calldataload(_1) diff --git a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/movable_functions.yul b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/movable_functions.yul index 3b3e65dbd..ac0fa0f52 100644 --- a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/movable_functions.yul +++ b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/movable_functions.yul @@ -7,9 +7,9 @@ let c := double_with_se(i) let d := double_with_se(i) } -// ==== -// step: commonSubexpressionEliminator // ---- +// step: commonSubexpressionEliminator +// // { // function double(x) -> y // { y := add(x, x) } diff --git a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/non_movable_instr.yul b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/non_movable_instr.yul index 42b4274ce..a9f5664ec 100644 --- a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/non_movable_instr.yul +++ b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/non_movable_instr.yul @@ -2,9 +2,9 @@ let a := mload(1) let b := mload(1) } -// ==== -// step: commonSubexpressionEliminator // ---- +// step: commonSubexpressionEliminator +// // { // let a := mload(1) // let b := mload(1) diff --git a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/non_movable_instr2.yul b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/non_movable_instr2.yul index 6fee35665..ed8916e63 100644 --- a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/non_movable_instr2.yul +++ b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/non_movable_instr2.yul @@ -2,9 +2,9 @@ let a := gas() let b := gas() } -// ==== -// step: commonSubexpressionEliminator // ---- +// step: commonSubexpressionEliminator +// // { // let a := gas() // let b := gas() diff --git a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/object_access.yul b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/object_access.yul index 4c1e0feeb..0f723c6c1 100644 --- a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/object_access.yul +++ b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/object_access.yul @@ -14,9 +14,9 @@ object "main" { } data "abc" "Hello, World!" } -// ==== -// step: commonSubexpressionEliminator // ---- +// step: commonSubexpressionEliminator +// // { // let r := "abc" // let a := datasize("abc") diff --git a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/scopes.yul b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/scopes.yul index 44d08679f..5e5b79696 100644 --- a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/scopes.yul +++ b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/scopes.yul @@ -10,9 +10,9 @@ mstore(0, calldataload(0)) mstore(0, x) } -// ==== -// step: commonSubexpressionEliminator // ---- +// step: commonSubexpressionEliminator +// // { // let a := 10 // let x := 20 diff --git a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/smoke.yul b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/smoke.yul index 2457b3b56..ab0d0a1ea 100644 --- a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/smoke.yul +++ b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/smoke.yul @@ -1,5 +1,5 @@ { } -// ==== -// step: commonSubexpressionEliminator // ---- +// step: commonSubexpressionEliminator +// // { } diff --git a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/trivial.yul b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/trivial.yul index 1fdc65d43..c64fc93f9 100644 --- a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/trivial.yul +++ b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/trivial.yul @@ -2,9 +2,9 @@ let a := mul(1, codesize()) let b := mul(1, codesize()) } -// ==== -// step: commonSubexpressionEliminator // ---- +// step: commonSubexpressionEliminator +// // { // let a := mul(1, codesize()) // let b := a diff --git a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/unassigned_return.yul b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/unassigned_return.yul index 178b8c523..46bf80eb7 100644 --- a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/unassigned_return.yul +++ b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/unassigned_return.yul @@ -9,9 +9,9 @@ let b := 0 sstore(a, b) } -// ==== -// step: commonSubexpressionEliminator // ---- +// step: commonSubexpressionEliminator +// // { // function f() -> x // { diff --git a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/unassigned_variables.yul b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/unassigned_variables.yul index 0012af037..ab14e0425 100644 --- a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/unassigned_variables.yul +++ b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/unassigned_variables.yul @@ -5,9 +5,9 @@ let b mstore(sub(a, b), 7) } -// ==== -// step: commonSubexpressionEliminator // ---- +// step: commonSubexpressionEliminator +// // { // let a // let b diff --git a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/variable_for_variable.yul b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/variable_for_variable.yul index 9f1bda665..52198a173 100644 --- a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/variable_for_variable.yul +++ b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/variable_for_variable.yul @@ -12,9 +12,9 @@ a := b mstore(2, a) } -// ==== -// step: commonSubexpressionEliminator // ---- +// step: commonSubexpressionEliminator +// // { // let a := mload(0) // let b := add(a, 7) diff --git a/test/libyul/yulOptimizerTests/conditionalSimplifier/add_correct_type.yul b/test/libyul/yulOptimizerTests/conditionalSimplifier/add_correct_type.yul index f0b46072f..c7cc17fc8 100644 --- a/test/libyul/yulOptimizerTests/conditionalSimplifier/add_correct_type.yul +++ b/test/libyul/yulOptimizerTests/conditionalSimplifier/add_correct_type.yul @@ -6,8 +6,9 @@ } // ==== // dialect: yul -// step: conditionalSimplifier // ---- +// step: conditionalSimplifier +// // { // let y:bool := false // for { } true { } diff --git a/test/libyul/yulOptimizerTests/conditionalSimplifier/add_correct_type_wasm.yul b/test/libyul/yulOptimizerTests/conditionalSimplifier/add_correct_type_wasm.yul index ab523246e..de92aad7a 100644 --- a/test/libyul/yulOptimizerTests/conditionalSimplifier/add_correct_type_wasm.yul +++ b/test/libyul/yulOptimizerTests/conditionalSimplifier/add_correct_type_wasm.yul @@ -6,8 +6,9 @@ } // ==== // dialect: ewasm -// step: conditionalSimplifier // ---- +// step: conditionalSimplifier +// // { // let y:i32 := 0:i32 // for { } true { } diff --git a/test/libyul/yulOptimizerTests/conditionalSimplifier/clear_after_if_break.yul b/test/libyul/yulOptimizerTests/conditionalSimplifier/clear_after_if_break.yul index 00c46fcdf..d49ec0709 100644 --- a/test/libyul/yulOptimizerTests/conditionalSimplifier/clear_after_if_break.yul +++ b/test/libyul/yulOptimizerTests/conditionalSimplifier/clear_after_if_break.yul @@ -4,9 +4,9 @@ if y { break } } } -// ==== -// step: conditionalSimplifier // ---- +// step: conditionalSimplifier +// // { // let y := mload(0x20) // for { } and(y, 8) { pop(y) } diff --git a/test/libyul/yulOptimizerTests/conditionalSimplifier/clear_after_if_continue.yul b/test/libyul/yulOptimizerTests/conditionalSimplifier/clear_after_if_continue.yul index 1e6b0828a..9246c162b 100644 --- a/test/libyul/yulOptimizerTests/conditionalSimplifier/clear_after_if_continue.yul +++ b/test/libyul/yulOptimizerTests/conditionalSimplifier/clear_after_if_continue.yul @@ -4,9 +4,9 @@ if y { continue } } } -// ==== -// step: conditionalSimplifier // ---- +// step: conditionalSimplifier +// // { // let y := mload(0x20) // for { } and(y, 8) { pop(y) } diff --git a/test/libyul/yulOptimizerTests/conditionalSimplifier/clear_before_for_condition.yul b/test/libyul/yulOptimizerTests/conditionalSimplifier/clear_before_for_condition.yul index e936287db..35ba33c6e 100644 --- a/test/libyul/yulOptimizerTests/conditionalSimplifier/clear_before_for_condition.yul +++ b/test/libyul/yulOptimizerTests/conditionalSimplifier/clear_before_for_condition.yul @@ -7,9 +7,9 @@ x := 2 } } -// ==== -// step: conditionalSimplifier // ---- +// step: conditionalSimplifier +// // { // let x := mload(0) // let y := mload(0) diff --git a/test/libyul/yulOptimizerTests/conditionalSimplifier/clear_before_for_post.yul b/test/libyul/yulOptimizerTests/conditionalSimplifier/clear_before_for_post.yul index c541590bd..4207525c7 100644 --- a/test/libyul/yulOptimizerTests/conditionalSimplifier/clear_before_for_post.yul +++ b/test/libyul/yulOptimizerTests/conditionalSimplifier/clear_before_for_post.yul @@ -8,9 +8,9 @@ } sstore(0, x) } -// ==== -// step: conditionalSimplifier // ---- +// step: conditionalSimplifier +// // { // let x // for { } x { sstore(1, x) } diff --git a/test/libyul/yulOptimizerTests/conditionalSimplifier/no_opt_if_break_is_not_last.yul b/test/libyul/yulOptimizerTests/conditionalSimplifier/no_opt_if_break_is_not_last.yul index 101407783..6aa3ba57d 100644 --- a/test/libyul/yulOptimizerTests/conditionalSimplifier/no_opt_if_break_is_not_last.yul +++ b/test/libyul/yulOptimizerTests/conditionalSimplifier/no_opt_if_break_is_not_last.yul @@ -7,9 +7,9 @@ sstore(10, x) } } -// ==== -// step: conditionalSimplifier // ---- +// step: conditionalSimplifier +// // { // let x := mload(0) // for { } 1 { } diff --git a/test/libyul/yulOptimizerTests/conditionalSimplifier/no_opt_inside_if.yul b/test/libyul/yulOptimizerTests/conditionalSimplifier/no_opt_inside_if.yul index 86983b316..ef262b2e6 100644 --- a/test/libyul/yulOptimizerTests/conditionalSimplifier/no_opt_inside_if.yul +++ b/test/libyul/yulOptimizerTests/conditionalSimplifier/no_opt_inside_if.yul @@ -3,9 +3,9 @@ if x { sstore(0, x) } sstore(1, x) } -// ==== -// step: conditionalSimplifier // ---- +// step: conditionalSimplifier +// // { // let x := mload(0) // if x { sstore(0, x) } diff --git a/test/libyul/yulOptimizerTests/conditionalSimplifier/opt_after_terminating_if.yul b/test/libyul/yulOptimizerTests/conditionalSimplifier/opt_after_terminating_if.yul index ca8bbba87..0326a5c3a 100644 --- a/test/libyul/yulOptimizerTests/conditionalSimplifier/opt_after_terminating_if.yul +++ b/test/libyul/yulOptimizerTests/conditionalSimplifier/opt_after_terminating_if.yul @@ -3,9 +3,9 @@ if x { sstore(0, x) revert(0, 0) } sstore(1, x) } -// ==== -// step: conditionalSimplifier // ---- +// step: conditionalSimplifier +// // { // let x := mload(0) // if x diff --git a/test/libyul/yulOptimizerTests/conditionalSimplifier/opt_switch.yul b/test/libyul/yulOptimizerTests/conditionalSimplifier/opt_switch.yul index 1f4da9eea..58a43c0d2 100644 --- a/test/libyul/yulOptimizerTests/conditionalSimplifier/opt_switch.yul +++ b/test/libyul/yulOptimizerTests/conditionalSimplifier/opt_switch.yul @@ -7,9 +7,9 @@ pop(x) } -// ==== -// step: conditionalSimplifier // ---- +// step: conditionalSimplifier +// // { // let x := calldataload(0) // switch x diff --git a/test/libyul/yulOptimizerTests/conditionalSimplifier/smoke.yul b/test/libyul/yulOptimizerTests/conditionalSimplifier/smoke.yul index f37bf3d01..17e4d03a2 100644 --- a/test/libyul/yulOptimizerTests/conditionalSimplifier/smoke.yul +++ b/test/libyul/yulOptimizerTests/conditionalSimplifier/smoke.yul @@ -1,5 +1,5 @@ { } -// ==== -// step: conditionalSimplifier // ---- +// step: conditionalSimplifier +// // { } diff --git a/test/libyul/yulOptimizerTests/conditionalUnsimplifier/clear_after_if_break.yul b/test/libyul/yulOptimizerTests/conditionalUnsimplifier/clear_after_if_break.yul index 01b301610..a12f171c6 100644 --- a/test/libyul/yulOptimizerTests/conditionalUnsimplifier/clear_after_if_break.yul +++ b/test/libyul/yulOptimizerTests/conditionalUnsimplifier/clear_after_if_break.yul @@ -5,9 +5,9 @@ y := 0 } } -// ==== -// step: conditionalUnsimplifier // ---- +// step: conditionalUnsimplifier +// // { // let y := mload(0x20) // for { } and(y, 8) { pop(y) } diff --git a/test/libyul/yulOptimizerTests/conditionalUnsimplifier/clear_after_if_continue.yul b/test/libyul/yulOptimizerTests/conditionalUnsimplifier/clear_after_if_continue.yul index d4014c2b0..86f99e298 100644 --- a/test/libyul/yulOptimizerTests/conditionalUnsimplifier/clear_after_if_continue.yul +++ b/test/libyul/yulOptimizerTests/conditionalUnsimplifier/clear_after_if_continue.yul @@ -5,9 +5,9 @@ y := 0 } } -// ==== -// step: conditionalUnsimplifier // ---- +// step: conditionalUnsimplifier +// // { // let y := mload(0x20) // for { } and(y, 8) { pop(y) } diff --git a/test/libyul/yulOptimizerTests/conditionalUnsimplifier/clear_before_for_condition.yul b/test/libyul/yulOptimizerTests/conditionalUnsimplifier/clear_before_for_condition.yul index de41539f0..2ea623e7a 100644 --- a/test/libyul/yulOptimizerTests/conditionalUnsimplifier/clear_before_for_condition.yul +++ b/test/libyul/yulOptimizerTests/conditionalUnsimplifier/clear_before_for_condition.yul @@ -9,9 +9,9 @@ x := 2 } } -// ==== -// step: conditionalUnsimplifier // ---- +// step: conditionalUnsimplifier +// // { // let x := mload(0) // let y := mload(0) diff --git a/test/libyul/yulOptimizerTests/conditionalUnsimplifier/clear_before_for_post.yul b/test/libyul/yulOptimizerTests/conditionalUnsimplifier/clear_before_for_post.yul index d84611352..a7fadc434 100644 --- a/test/libyul/yulOptimizerTests/conditionalUnsimplifier/clear_before_for_post.yul +++ b/test/libyul/yulOptimizerTests/conditionalUnsimplifier/clear_before_for_post.yul @@ -7,9 +7,9 @@ } sstore(0, x) } -// ==== -// step: conditionalUnsimplifier // ---- +// step: conditionalUnsimplifier +// // { // let x // for { } x { sstore(1, x) } diff --git a/test/libyul/yulOptimizerTests/conditionalUnsimplifier/no_opt_if_break_is_not_last.yul b/test/libyul/yulOptimizerTests/conditionalUnsimplifier/no_opt_if_break_is_not_last.yul index a697c6d25..e5342b2a6 100644 --- a/test/libyul/yulOptimizerTests/conditionalUnsimplifier/no_opt_if_break_is_not_last.yul +++ b/test/libyul/yulOptimizerTests/conditionalUnsimplifier/no_opt_if_break_is_not_last.yul @@ -9,9 +9,9 @@ sstore(10, x) } } -// ==== -// step: conditionalUnsimplifier // ---- +// step: conditionalUnsimplifier +// // { // let x := mload(0) // for { } 1 { } diff --git a/test/libyul/yulOptimizerTests/conditionalUnsimplifier/no_opt_inside_if.yul b/test/libyul/yulOptimizerTests/conditionalUnsimplifier/no_opt_inside_if.yul index 830ae064c..8c94644ce 100644 --- a/test/libyul/yulOptimizerTests/conditionalUnsimplifier/no_opt_inside_if.yul +++ b/test/libyul/yulOptimizerTests/conditionalUnsimplifier/no_opt_inside_if.yul @@ -4,9 +4,9 @@ x := 0 sstore(1, x) } -// ==== -// step: conditionalUnsimplifier // ---- +// step: conditionalUnsimplifier +// // { // let x := mload(0) // if x { sstore(0, x) } diff --git a/test/libyul/yulOptimizerTests/conditionalUnsimplifier/opt_after_terminating_if.yul b/test/libyul/yulOptimizerTests/conditionalUnsimplifier/opt_after_terminating_if.yul index 13ffc0bac..d90e1fc4b 100644 --- a/test/libyul/yulOptimizerTests/conditionalUnsimplifier/opt_after_terminating_if.yul +++ b/test/libyul/yulOptimizerTests/conditionalUnsimplifier/opt_after_terminating_if.yul @@ -4,9 +4,9 @@ x := 0 sstore(1, x) } -// ==== -// step: conditionalUnsimplifier // ---- +// step: conditionalUnsimplifier +// // { // let x := mload(0) // if x diff --git a/test/libyul/yulOptimizerTests/conditionalUnsimplifier/opt_switch.yul b/test/libyul/yulOptimizerTests/conditionalUnsimplifier/opt_switch.yul index 107b2923b..361b0f77b 100644 --- a/test/libyul/yulOptimizerTests/conditionalUnsimplifier/opt_switch.yul +++ b/test/libyul/yulOptimizerTests/conditionalUnsimplifier/opt_switch.yul @@ -8,9 +8,9 @@ pop(x) } -// ==== -// step: conditionalUnsimplifier // ---- +// step: conditionalUnsimplifier +// // { // let x := calldataload(0) // switch x diff --git a/test/libyul/yulOptimizerTests/conditionalUnsimplifier/smoke.yul b/test/libyul/yulOptimizerTests/conditionalUnsimplifier/smoke.yul index cb88da72b..176d7fd57 100644 --- a/test/libyul/yulOptimizerTests/conditionalUnsimplifier/smoke.yul +++ b/test/libyul/yulOptimizerTests/conditionalUnsimplifier/smoke.yul @@ -1,5 +1,5 @@ { } -// ==== -// step: conditionalUnsimplifier // ---- +// step: conditionalUnsimplifier +// // { } diff --git a/test/libyul/yulOptimizerTests/constantOptimiser/difficult.yul b/test/libyul/yulOptimizerTests/constantOptimiser/difficult.yul index 47b76fa7c..a7c4126ac 100644 --- a/test/libyul/yulOptimizerTests/constantOptimiser/difficult.yul +++ b/test/libyul/yulOptimizerTests/constantOptimiser/difficult.yul @@ -4,9 +4,9 @@ let z := 0xffff0000ffff0000ffff0000ffff0000ff00ff00ffff0000ffff0000ffff0000 let w := 0xffffffff000000ffffef000001feff000067ffefff0000ff230002ffee00fff7 } -// ==== -// step: constantOptimiser // ---- +// step: constantOptimiser +// // { // let x := 0xff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00 // let y := 0x1100ff00ff00ff001100ff00ff001100ff00ff001100ff00ff001100ff001100 diff --git a/test/libyul/yulOptimizerTests/constantOptimiser/gaps.yul b/test/libyul/yulOptimizerTests/constantOptimiser/gaps.yul index 6371638eb..82dccdab4 100644 --- a/test/libyul/yulOptimizerTests/constantOptimiser/gaps.yul +++ b/test/libyul/yulOptimizerTests/constantOptimiser/gaps.yul @@ -7,8 +7,9 @@ } // ==== // EVMVersion: >=constantinople -// step: constantOptimiser // ---- +// step: constantOptimiser +// // { // let a := shl(172, 1) // let x := add(shl(248, 17), 0xffffffffffffffffffffffff23) diff --git a/test/libyul/yulOptimizerTests/constantOptimiser/smallNumbers.yul b/test/libyul/yulOptimizerTests/constantOptimiser/smallNumbers.yul index 0315fdab8..af8a08886 100644 --- a/test/libyul/yulOptimizerTests/constantOptimiser/smallNumbers.yul +++ b/test/libyul/yulOptimizerTests/constantOptimiser/smallNumbers.yul @@ -4,9 +4,9 @@ for { let i := 0xff00 } lt(i, 2) { i := add(i, 3) } { } } -// ==== -// step: constantOptimiser // ---- +// step: constantOptimiser +// // { // let x := 8 // let y := 0xffff diff --git a/test/libyul/yulOptimizerTests/controlFlowSimplifier/empty_if_movable_condition.yul b/test/libyul/yulOptimizerTests/controlFlowSimplifier/empty_if_movable_condition.yul index 87450d939..bf74a266c 100644 --- a/test/libyul/yulOptimizerTests/controlFlowSimplifier/empty_if_movable_condition.yul +++ b/test/libyul/yulOptimizerTests/controlFlowSimplifier/empty_if_movable_condition.yul @@ -1,7 +1,7 @@ { let a := mload(0) if a {} } -// ==== -// step: controlFlowSimplifier // ---- +// step: controlFlowSimplifier +// // { // let a := mload(0) // pop(a) diff --git a/test/libyul/yulOptimizerTests/controlFlowSimplifier/empty_if_non_movable_condition.yul b/test/libyul/yulOptimizerTests/controlFlowSimplifier/empty_if_non_movable_condition.yul index 737ff7bf1..a204e6cec 100644 --- a/test/libyul/yulOptimizerTests/controlFlowSimplifier/empty_if_non_movable_condition.yul +++ b/test/libyul/yulOptimizerTests/controlFlowSimplifier/empty_if_non_movable_condition.yul @@ -1,5 +1,5 @@ { if mload(0) {} } -// ==== -// step: controlFlowSimplifier // ---- +// step: controlFlowSimplifier +// // { pop(mload(0)) } diff --git a/test/libyul/yulOptimizerTests/controlFlowSimplifier/remove_leave.yul b/test/libyul/yulOptimizerTests/controlFlowSimplifier/remove_leave.yul index af7726df9..f0bf4b7c2 100644 --- a/test/libyul/yulOptimizerTests/controlFlowSimplifier/remove_leave.yul +++ b/test/libyul/yulOptimizerTests/controlFlowSimplifier/remove_leave.yul @@ -3,9 +3,9 @@ function g() -> x { leave x := 7 } function h() -> x { if x { leave } } } -// ==== -// step: controlFlowSimplifier // ---- +// step: controlFlowSimplifier +// // { // function f() -> x // { x := 7 } diff --git a/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_only_default.yul b/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_only_default.yul index 16e718d2e..f52551ab4 100644 --- a/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_only_default.yul +++ b/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_only_default.yul @@ -1,9 +1,9 @@ { switch mload(0) default { mstore(1, 2) } } -// ==== -// step: controlFlowSimplifier // ---- +// step: controlFlowSimplifier +// // { // pop(mload(0)) // { mstore(1, 2) } diff --git a/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_remove_empty_all.yul b/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_remove_empty_all.yul index fb2434ec7..a04b87ae6 100644 --- a/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_remove_empty_all.yul +++ b/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_remove_empty_all.yul @@ -10,9 +10,9 @@ case 1 { } default { } } -// ==== -// step: controlFlowSimplifier // ---- +// step: controlFlowSimplifier +// // { // let y := 200 // pop(add(y, 4)) diff --git a/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_remove_empty_case.yul b/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_remove_empty_case.yul index 4b4f2cc0c..03879b263 100644 --- a/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_remove_empty_case.yul +++ b/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_remove_empty_case.yul @@ -5,9 +5,9 @@ case 1 { y := 9 } case 2 { y := 10 } } -// ==== -// step: controlFlowSimplifier // ---- +// step: controlFlowSimplifier +// // { // let y := 200 // switch calldataload(0) diff --git a/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_remove_empty_cases.yul b/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_remove_empty_cases.yul index 57beacaa1..223760723 100644 --- a/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_remove_empty_cases.yul +++ b/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_remove_empty_cases.yul @@ -5,9 +5,9 @@ case 1 { y := 9 } default { } } -// ==== -// step: controlFlowSimplifier // ---- +// step: controlFlowSimplifier +// // { // let y := 200 // if eq(1, calldataload(0)) { y := 9 } diff --git a/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_remove_empty_default_case.yul b/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_remove_empty_default_case.yul index c5c4e44a7..7c6283a8f 100644 --- a/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_remove_empty_default_case.yul +++ b/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_remove_empty_default_case.yul @@ -5,9 +5,9 @@ case 2 { y := 10 } default { } } -// ==== -// step: controlFlowSimplifier // ---- +// step: controlFlowSimplifier +// // { // let y := 200 // switch calldataload(0) diff --git a/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_to_if.yul b/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_to_if.yul index 4a3558b65..b314cd96d 100644 --- a/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_to_if.yul +++ b/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_to_if.yul @@ -1,9 +1,9 @@ { switch calldataload(0) case 2 { mstore(0, 0) } } -// ==== -// step: controlFlowSimplifier // ---- +// step: controlFlowSimplifier +// // { // if eq(2, calldataload(0)) { mstore(0, 0) } // } diff --git a/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for.yul b/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for.yul index 6f7390d53..8e48e2b65 100644 --- a/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for.yul +++ b/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for.yul @@ -4,9 +4,9 @@ break } } -// ==== -// step: controlFlowSimplifier // ---- +// step: controlFlowSimplifier +// // { // if calldatasize() { mstore(4, 5) } // } diff --git a/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_nested.yul b/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_nested.yul index 2b6397269..7bf16956e 100644 --- a/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_nested.yul +++ b/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_nested.yul @@ -8,9 +8,9 @@ break } } -// ==== -// step: controlFlowSimplifier // ---- +// step: controlFlowSimplifier +// // { // for { } calldatasize() { mstore(8, 9) } // { diff --git a/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_nested_reversed.yul b/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_nested_reversed.yul index 5412a7952..806a8ebcb 100644 --- a/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_nested_reversed.yul +++ b/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_nested_reversed.yul @@ -7,9 +7,9 @@ break } } -// ==== -// step: controlFlowSimplifier // ---- +// step: controlFlowSimplifier +// // { // if calldatasize() // { diff --git a/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_revert.yul b/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_revert.yul index d6f7e5d18..b8bf66163 100644 --- a/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_revert.yul +++ b/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_revert.yul @@ -5,9 +5,9 @@ revert(0, x) } } -// ==== -// step: controlFlowSimplifier // ---- +// step: controlFlowSimplifier +// // { // if calldatasize() // { diff --git a/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_revert_plus_break.yul b/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_revert_plus_break.yul index 7ef55bc3c..e8d034733 100644 --- a/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_revert_plus_break.yul +++ b/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_revert_plus_break.yul @@ -6,9 +6,9 @@ revert(0, x) } } -// ==== -// step: controlFlowSimplifier // ---- +// step: controlFlowSimplifier +// // { // for { } calldatasize() { mstore(1, 2) } // { diff --git a/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_with_continue.yul b/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_with_continue.yul index 9d5ce5b84..b92efd885 100644 --- a/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_with_continue.yul +++ b/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_with_continue.yul @@ -5,9 +5,9 @@ break } } -// ==== -// step: controlFlowSimplifier // ---- +// step: controlFlowSimplifier +// // { // for { } calldatasize() { mstore(1, 2) } // { diff --git a/test/libyul/yulOptimizerTests/deadCodeEliminator/conditional_break.yul b/test/libyul/yulOptimizerTests/deadCodeEliminator/conditional_break.yul index 3d350c43b..ef17a9708 100644 --- a/test/libyul/yulOptimizerTests/deadCodeEliminator/conditional_break.yul +++ b/test/libyul/yulOptimizerTests/deadCodeEliminator/conditional_break.yul @@ -13,9 +13,9 @@ } } -// ==== -// step: deadCodeEliminator // ---- +// step: deadCodeEliminator +// // { // let a := 20 // for { } lt(a, 40) { a := add(a, 2) } diff --git a/test/libyul/yulOptimizerTests/deadCodeEliminator/early_break.yul b/test/libyul/yulOptimizerTests/deadCodeEliminator/early_break.yul index a0d751938..c7a3d98e1 100644 --- a/test/libyul/yulOptimizerTests/deadCodeEliminator/early_break.yul +++ b/test/libyul/yulOptimizerTests/deadCodeEliminator/early_break.yul @@ -14,9 +14,9 @@ } } -// ==== -// step: deadCodeEliminator // ---- +// step: deadCodeEliminator +// // { // let a := 20 // for { } lt(a, 40) { a := add(a, 2) } diff --git a/test/libyul/yulOptimizerTests/deadCodeEliminator/early_continue.yul b/test/libyul/yulOptimizerTests/deadCodeEliminator/early_continue.yul index 61eae9ff2..d6b9f9d23 100644 --- a/test/libyul/yulOptimizerTests/deadCodeEliminator/early_continue.yul +++ b/test/libyul/yulOptimizerTests/deadCodeEliminator/early_continue.yul @@ -14,9 +14,9 @@ } } -// ==== -// step: deadCodeEliminator // ---- +// step: deadCodeEliminator +// // { // let a := 20 // for { } lt(a, 40) { a := add(a, 2) } diff --git a/test/libyul/yulOptimizerTests/deadCodeEliminator/early_leave.yul b/test/libyul/yulOptimizerTests/deadCodeEliminator/early_leave.yul index 90dae56f0..ce3c00672 100644 --- a/test/libyul/yulOptimizerTests/deadCodeEliminator/early_leave.yul +++ b/test/libyul/yulOptimizerTests/deadCodeEliminator/early_leave.yul @@ -18,9 +18,9 @@ pop(f()) } -// ==== -// step: deadCodeEliminator // ---- +// step: deadCodeEliminator +// // { // function f() -> x // { diff --git a/test/libyul/yulOptimizerTests/deadCodeEliminator/early_revert.yul b/test/libyul/yulOptimizerTests/deadCodeEliminator/early_revert.yul index be13641c2..7e37d6d4b 100644 --- a/test/libyul/yulOptimizerTests/deadCodeEliminator/early_revert.yul +++ b/test/libyul/yulOptimizerTests/deadCodeEliminator/early_revert.yul @@ -15,9 +15,9 @@ } } -// ==== -// step: deadCodeEliminator // ---- +// step: deadCodeEliminator +// // { // let b := 20 // revert(0, 0) diff --git a/test/libyul/yulOptimizerTests/deadCodeEliminator/early_stop.yul b/test/libyul/yulOptimizerTests/deadCodeEliminator/early_stop.yul index ee4227b6a..ad1575736 100644 --- a/test/libyul/yulOptimizerTests/deadCodeEliminator/early_stop.yul +++ b/test/libyul/yulOptimizerTests/deadCodeEliminator/early_stop.yul @@ -15,9 +15,9 @@ } } -// ==== -// step: deadCodeEliminator // ---- +// step: deadCodeEliminator +// // { // let b := 20 // stop() diff --git a/test/libyul/yulOptimizerTests/deadCodeEliminator/for_loop_init_decl.yul b/test/libyul/yulOptimizerTests/deadCodeEliminator/for_loop_init_decl.yul index 295a49504..f5e67f77f 100644 --- a/test/libyul/yulOptimizerTests/deadCodeEliminator/for_loop_init_decl.yul +++ b/test/libyul/yulOptimizerTests/deadCodeEliminator/for_loop_init_decl.yul @@ -4,7 +4,7 @@ let i_1 := i_0 } } -// ==== -// step: deadCodeEliminator // ---- +// step: deadCodeEliminator +// // { stop() } diff --git a/test/libyul/yulOptimizerTests/deadCodeEliminator/function_after_revert.yul b/test/libyul/yulOptimizerTests/deadCodeEliminator/function_after_revert.yul index e1d0f30fe..d5df28fb0 100644 --- a/test/libyul/yulOptimizerTests/deadCodeEliminator/function_after_revert.yul +++ b/test/libyul/yulOptimizerTests/deadCodeEliminator/function_after_revert.yul @@ -12,9 +12,9 @@ pop(add(1, 1)) } -// ==== -// step: deadCodeEliminator // ---- +// step: deadCodeEliminator +// // { // fun() // revert(0, 0) diff --git a/test/libyul/yulOptimizerTests/deadCodeEliminator/nested_revert.yul b/test/libyul/yulOptimizerTests/deadCodeEliminator/nested_revert.yul index b89c1e0b7..088394ee0 100644 --- a/test/libyul/yulOptimizerTests/deadCodeEliminator/nested_revert.yul +++ b/test/libyul/yulOptimizerTests/deadCodeEliminator/nested_revert.yul @@ -12,9 +12,9 @@ y := 10 } } -// ==== -// step: deadCodeEliminator // ---- +// step: deadCodeEliminator +// // { // let y := mload(0) // switch y diff --git a/test/libyul/yulOptimizerTests/deadCodeEliminator/no_removal.yul b/test/libyul/yulOptimizerTests/deadCodeEliminator/no_removal.yul index c1003538d..0e0a2b9c4 100644 --- a/test/libyul/yulOptimizerTests/deadCodeEliminator/no_removal.yul +++ b/test/libyul/yulOptimizerTests/deadCodeEliminator/no_removal.yul @@ -4,9 +4,9 @@ } mstore(0, 0) } -// ==== -// step: deadCodeEliminator // ---- +// step: deadCodeEliminator +// // { // { revert(0, 0) } // mstore(0, 0) diff --git a/test/libyul/yulOptimizerTests/deadCodeEliminator/normal_break.yul b/test/libyul/yulOptimizerTests/deadCodeEliminator/normal_break.yul index 77e4303b6..28425b6e1 100644 --- a/test/libyul/yulOptimizerTests/deadCodeEliminator/normal_break.yul +++ b/test/libyul/yulOptimizerTests/deadCodeEliminator/normal_break.yul @@ -12,9 +12,9 @@ } } -// ==== -// step: deadCodeEliminator // ---- +// step: deadCodeEliminator +// // { // let a := 20 // for { } lt(a, 40) { a := add(a, 2) } diff --git a/test/libyul/yulOptimizerTests/deadCodeEliminator/normal_continue.yul b/test/libyul/yulOptimizerTests/deadCodeEliminator/normal_continue.yul index e3a0b7a2f..e01ae0aed 100644 --- a/test/libyul/yulOptimizerTests/deadCodeEliminator/normal_continue.yul +++ b/test/libyul/yulOptimizerTests/deadCodeEliminator/normal_continue.yul @@ -12,9 +12,9 @@ } } -// ==== -// step: deadCodeEliminator // ---- +// step: deadCodeEliminator +// // { // let a := 20 // for { } lt(a, 40) { a := add(a, 2) } diff --git a/test/libyul/yulOptimizerTests/deadCodeEliminator/normal_stop.yul b/test/libyul/yulOptimizerTests/deadCodeEliminator/normal_stop.yul index 561ac2066..6999c39c0 100644 --- a/test/libyul/yulOptimizerTests/deadCodeEliminator/normal_stop.yul +++ b/test/libyul/yulOptimizerTests/deadCodeEliminator/normal_stop.yul @@ -15,9 +15,9 @@ stop() } -// ==== -// step: deadCodeEliminator // ---- +// step: deadCodeEliminator +// // { // let b := 20 // let a := 20 diff --git a/test/libyul/yulOptimizerTests/disambiguator/for_statement.yul b/test/libyul/yulOptimizerTests/disambiguator/for_statement.yul index c6b246ad0..30f2e5479 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/for_statement.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/for_statement.yul @@ -9,8 +9,9 @@ } // ==== // dialect: yul -// step: disambiguator // ---- +// step: disambiguator +// // { // { let a, b } // { diff --git a/test/libyul/yulOptimizerTests/disambiguator/funtion_call.yul b/test/libyul/yulOptimizerTests/disambiguator/funtion_call.yul index 7a4cfe739..f99c4e447 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/funtion_call.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/funtion_call.yul @@ -8,8 +8,9 @@ } // ==== // dialect: yul -// step: disambiguator // ---- +// step: disambiguator +// // { // { let a, b, c, d, f } // { diff --git a/test/libyul/yulOptimizerTests/disambiguator/if_statement.yul b/test/libyul/yulOptimizerTests/disambiguator/if_statement.yul index def0a2d31..6b6da1f18 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/if_statement.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/if_statement.yul @@ -7,8 +7,9 @@ } // ==== // dialect: yul -// step: disambiguator // ---- +// step: disambiguator +// // { // { let a, b, c } // { diff --git a/test/libyul/yulOptimizerTests/disambiguator/long_names.yul b/test/libyul/yulOptimizerTests/disambiguator/long_names.yul index b403dc095..d55afc482 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/long_names.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/long_names.yul @@ -1,8 +1,9 @@ { { let aanteuhdaoneudbrgkjiuaothduiathudaoeuh:u256 } { let aanteuhdaoneudbrgkjiuaothduiathudaoeuh:u256 } } // ==== // dialect: yul -// step: disambiguator // ---- +// step: disambiguator +// // { // { // let aanteuhdaoneudbrgkjiuaothduiathudaoeuh diff --git a/test/libyul/yulOptimizerTests/disambiguator/smoke.yul b/test/libyul/yulOptimizerTests/disambiguator/smoke.yul index bfe22582a..4ea58a6ef 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/smoke.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/smoke.yul @@ -1,5 +1,5 @@ { } -// ==== -// step: disambiguator // ---- +// step: disambiguator +// // { } diff --git a/test/libyul/yulOptimizerTests/disambiguator/smoke_yul.yul b/test/libyul/yulOptimizerTests/disambiguator/smoke_yul.yul index 2ed2b9ad1..676416437 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/smoke_yul.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/smoke_yul.yul @@ -1,6 +1,7 @@ { } // ==== -// step: disambiguator // dialect: yul // ---- +// step: disambiguator +// // { } diff --git a/test/libyul/yulOptimizerTests/disambiguator/switch_statement.yul b/test/libyul/yulOptimizerTests/disambiguator/switch_statement.yul index 0948b51b9..16ee5353f 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/switch_statement.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/switch_statement.yul @@ -9,8 +9,9 @@ } // ==== // dialect: yul -// step: disambiguator // ---- +// step: disambiguator +// // { // { let a, b, c } // { diff --git a/test/libyul/yulOptimizerTests/disambiguator/variables.yul b/test/libyul/yulOptimizerTests/disambiguator/variables.yul index 7b197f420..65c93bbb9 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/variables.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/variables.yul @@ -1,8 +1,9 @@ { { let a:u256 } { let a:u256 } } // ==== // dialect: yul -// step: disambiguator // ---- +// step: disambiguator +// // { // { let a } // { let a_1 } diff --git a/test/libyul/yulOptimizerTests/disambiguator/variables_clash.yul b/test/libyul/yulOptimizerTests/disambiguator/variables_clash.yul index 9c72b82ff..e2cf23756 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/variables_clash.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/variables_clash.yul @@ -1,8 +1,9 @@ { { let a:u256 let a_1:u256 } { let a:u256 } } // ==== // dialect: yul -// step: disambiguator // ---- +// step: disambiguator +// // { // { // let a diff --git a/test/libyul/yulOptimizerTests/disambiguator/variables_inside_functions.yul b/test/libyul/yulOptimizerTests/disambiguator/variables_inside_functions.yul index fecb67a65..a78af7dab 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/variables_inside_functions.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/variables_inside_functions.yul @@ -7,8 +7,9 @@ } // ==== // dialect: yul -// step: disambiguator // ---- +// step: disambiguator +// // { // { // let c diff --git a/test/libyul/yulOptimizerTests/equivalentFunctionCombiner/multiple_complex.yul b/test/libyul/yulOptimizerTests/equivalentFunctionCombiner/multiple_complex.yul index e400e69ae..5f561185d 100644 --- a/test/libyul/yulOptimizerTests/equivalentFunctionCombiner/multiple_complex.yul +++ b/test/libyul/yulOptimizerTests/equivalentFunctionCombiner/multiple_complex.yul @@ -54,9 +54,9 @@ } } } -// ==== -// step: equivalentFunctionCombiner // ---- +// step: equivalentFunctionCombiner +// // { // pop(f(1, 2, 3)) // pop(f(4, 5, 6)) diff --git a/test/libyul/yulOptimizerTests/equivalentFunctionCombiner/simple.yul b/test/libyul/yulOptimizerTests/equivalentFunctionCombiner/simple.yul index 43629175b..69045f364 100644 --- a/test/libyul/yulOptimizerTests/equivalentFunctionCombiner/simple.yul +++ b/test/libyul/yulOptimizerTests/equivalentFunctionCombiner/simple.yul @@ -4,9 +4,9 @@ function f() { mstore(1, mload(0)) } function g() { mstore(1, mload(0)) } } -// ==== -// step: equivalentFunctionCombiner // ---- +// step: equivalentFunctionCombiner +// // { // f() // f() diff --git a/test/libyul/yulOptimizerTests/equivalentFunctionCombiner/simple_different_vars.yul b/test/libyul/yulOptimizerTests/equivalentFunctionCombiner/simple_different_vars.yul index 25ffa4017..5967adc0e 100644 --- a/test/libyul/yulOptimizerTests/equivalentFunctionCombiner/simple_different_vars.yul +++ b/test/libyul/yulOptimizerTests/equivalentFunctionCombiner/simple_different_vars.yul @@ -4,9 +4,9 @@ function f() -> b { let a := mload(0) b := a } function g() -> a { let b := mload(0) a := b } } -// ==== -// step: equivalentFunctionCombiner // ---- +// step: equivalentFunctionCombiner +// // { // pop(f()) // pop(f()) diff --git a/test/libyul/yulOptimizerTests/equivalentFunctionCombiner/switch_case_order.yul b/test/libyul/yulOptimizerTests/equivalentFunctionCombiner/switch_case_order.yul index 9de10889b..490bfd072 100644 --- a/test/libyul/yulOptimizerTests/equivalentFunctionCombiner/switch_case_order.yul +++ b/test/libyul/yulOptimizerTests/equivalentFunctionCombiner/switch_case_order.yul @@ -4,9 +4,9 @@ function f(x) { switch x case 0 { mstore(0, 42) } case 1 { mstore(1, 42) } } function g(x) { switch x case 1 { mstore(1, 42) } case 0 { mstore(0, 42) } } } -// ==== -// step: equivalentFunctionCombiner // ---- +// step: equivalentFunctionCombiner +// // { // f(0) // f(1) diff --git a/test/libyul/yulOptimizerTests/expressionInliner/argument_duplication_heuristic.yul b/test/libyul/yulOptimizerTests/expressionInliner/argument_duplication_heuristic.yul index 37649a572..12228009a 100644 --- a/test/libyul/yulOptimizerTests/expressionInliner/argument_duplication_heuristic.yul +++ b/test/libyul/yulOptimizerTests/expressionInliner/argument_duplication_heuristic.yul @@ -16,9 +16,9 @@ let y11:= ref1(y1) let y12:= ref3(y1) } -// ==== -// step: expressionInliner // ---- +// step: expressionInliner +// // { // function ref1(a) -> x // { x := add(a, 1) } diff --git a/test/libyul/yulOptimizerTests/expressionInliner/complex_with_evm.yul b/test/libyul/yulOptimizerTests/expressionInliner/complex_with_evm.yul index e95c4144c..49237c2f6 100644 --- a/test/libyul/yulOptimizerTests/expressionInliner/complex_with_evm.yul +++ b/test/libyul/yulOptimizerTests/expressionInliner/complex_with_evm.yul @@ -2,9 +2,9 @@ function f(a) -> x { x := add(a, a) } let y := f(calldatasize()) } -// ==== -// step: expressionInliner // ---- +// step: expressionInliner +// // { // function f(a) -> x // { x := add(a, a) } diff --git a/test/libyul/yulOptimizerTests/expressionInliner/double_calls.yul b/test/libyul/yulOptimizerTests/expressionInliner/double_calls.yul index d19082f2e..42dc4f015 100644 --- a/test/libyul/yulOptimizerTests/expressionInliner/double_calls.yul +++ b/test/libyul/yulOptimizerTests/expressionInliner/double_calls.yul @@ -3,9 +3,9 @@ function g(b, c) -> y { y := mul(mload(c), f(b)) } let y := g(calldatasize(), 7) } -// ==== -// step: expressionInliner // ---- +// step: expressionInliner +// // { // function f(a) -> x // { x := add(a, a) } diff --git a/test/libyul/yulOptimizerTests/expressionInliner/double_recursive_calls.yul b/test/libyul/yulOptimizerTests/expressionInliner/double_recursive_calls.yul index 923032af0..337751a72 100644 --- a/test/libyul/yulOptimizerTests/expressionInliner/double_recursive_calls.yul +++ b/test/libyul/yulOptimizerTests/expressionInliner/double_recursive_calls.yul @@ -3,9 +3,9 @@ function g(b, s) -> y { y := f(b, f(s, s)) } let y := g(calldatasize(), 7) } -// ==== -// step: expressionInliner // ---- +// step: expressionInliner +// // { // function f(a, r) -> x // { x := g(a, f(r, f(r, r))) } diff --git a/test/libyul/yulOptimizerTests/expressionInliner/no_inline_mload.yul b/test/libyul/yulOptimizerTests/expressionInliner/no_inline_mload.yul index 1b2b702fe..1698ac5ac 100644 --- a/test/libyul/yulOptimizerTests/expressionInliner/no_inline_mload.yul +++ b/test/libyul/yulOptimizerTests/expressionInliner/no_inline_mload.yul @@ -3,9 +3,9 @@ function f(a) -> x { x := a } let y := f(mload(2)) } -// ==== -// step: expressionInliner // ---- +// step: expressionInliner +// // { // function f(a) -> x // { x := a } diff --git a/test/libyul/yulOptimizerTests/expressionInliner/no_move_with_sideeffects.yul b/test/libyul/yulOptimizerTests/expressionInliner/no_move_with_sideeffects.yul index 5a116bcc3..48acca95c 100644 --- a/test/libyul/yulOptimizerTests/expressionInliner/no_move_with_sideeffects.yul +++ b/test/libyul/yulOptimizerTests/expressionInliner/no_move_with_sideeffects.yul @@ -6,9 +6,9 @@ function h() -> z { mstore(0, 4) z := mload(0) } let r := f(g(), h()) } -// ==== -// step: expressionInliner // ---- +// step: expressionInliner +// // { // function f(a, b) -> x // { x := add(b, a) } diff --git a/test/libyul/yulOptimizerTests/expressionInliner/simple.yul b/test/libyul/yulOptimizerTests/expressionInliner/simple.yul index 8c3cd28e3..2b6dba240 100644 --- a/test/libyul/yulOptimizerTests/expressionInliner/simple.yul +++ b/test/libyul/yulOptimizerTests/expressionInliner/simple.yul @@ -4,8 +4,9 @@ } // ==== // dialect: yul -// step: expressionInliner // ---- +// step: expressionInliner +// // { // function f() -> x // { x := 2 } diff --git a/test/libyul/yulOptimizerTests/expressionInliner/with_args.yul b/test/libyul/yulOptimizerTests/expressionInliner/with_args.yul index 5b73ed3fe..0456654e3 100644 --- a/test/libyul/yulOptimizerTests/expressionInliner/with_args.yul +++ b/test/libyul/yulOptimizerTests/expressionInliner/with_args.yul @@ -4,8 +4,9 @@ } // ==== // dialect: yul -// step: expressionInliner // ---- +// step: expressionInliner +// // { // function f(a) -> x // { x := a } diff --git a/test/libyul/yulOptimizerTests/expressionJoiner/if_condition.yul b/test/libyul/yulOptimizerTests/expressionJoiner/if_condition.yul index b2a204482..045168cf1 100644 --- a/test/libyul/yulOptimizerTests/expressionJoiner/if_condition.yul +++ b/test/libyul/yulOptimizerTests/expressionJoiner/if_condition.yul @@ -10,9 +10,9 @@ let z := 3 let t := add(z, 9) } -// ==== -// step: expressionJoiner // ---- +// step: expressionJoiner +// // { // if add(mload(7), sload(mload(3))) { let y := add(mload(3), 3) } // let t := add(3, 9) diff --git a/test/libyul/yulOptimizerTests/expressionJoiner/muli_wrong_order3.yul b/test/libyul/yulOptimizerTests/expressionJoiner/muli_wrong_order3.yul index 07982ca47..461285ae2 100644 --- a/test/libyul/yulOptimizerTests/expressionJoiner/muli_wrong_order3.yul +++ b/test/libyul/yulOptimizerTests/expressionJoiner/muli_wrong_order3.yul @@ -4,9 +4,9 @@ let x := mul(add(b, a), mload(2)) sstore(x, 3) } -// ==== -// step: expressionJoiner // ---- +// step: expressionJoiner +// // { // let a := mload(3) // let b := mload(6) diff --git a/test/libyul/yulOptimizerTests/expressionJoiner/multi.yul b/test/libyul/yulOptimizerTests/expressionJoiner/multi.yul index 9d9a139a2..5fcd2c5bf 100644 --- a/test/libyul/yulOptimizerTests/expressionJoiner/multi.yul +++ b/test/libyul/yulOptimizerTests/expressionJoiner/multi.yul @@ -4,9 +4,9 @@ let x := mul(add(b, a), 2) sstore(x, 3) } -// ==== -// step: expressionJoiner // ---- +// step: expressionJoiner +// // { // sstore(mul(add(mload(6), mload(2)), 2), 3) // } diff --git a/test/libyul/yulOptimizerTests/expressionJoiner/multi_reference.yul b/test/libyul/yulOptimizerTests/expressionJoiner/multi_reference.yul index 95a0eccb3..ed209e597 100644 --- a/test/libyul/yulOptimizerTests/expressionJoiner/multi_reference.yul +++ b/test/libyul/yulOptimizerTests/expressionJoiner/multi_reference.yul @@ -3,9 +3,9 @@ let a := mload(2) let b := add(a, a) } -// ==== -// step: expressionJoiner // ---- +// step: expressionJoiner +// // { // let a := mload(2) // let b := add(a, a) diff --git a/test/libyul/yulOptimizerTests/expressionJoiner/multi_wrong_order.yul b/test/libyul/yulOptimizerTests/expressionJoiner/multi_wrong_order.yul index d8624dc14..2837f7033 100644 --- a/test/libyul/yulOptimizerTests/expressionJoiner/multi_wrong_order.yul +++ b/test/libyul/yulOptimizerTests/expressionJoiner/multi_wrong_order.yul @@ -7,9 +7,9 @@ let x := mul(a, add(2, b)) sstore(x, 3) } -// ==== -// step: expressionJoiner // ---- +// step: expressionJoiner +// // { // let a := mload(2) // sstore(mul(a, add(2, mload(6))), 3) diff --git a/test/libyul/yulOptimizerTests/expressionJoiner/multi_wrong_order2.yul b/test/libyul/yulOptimizerTests/expressionJoiner/multi_wrong_order2.yul index 6296c3778..d69f9d8a5 100644 --- a/test/libyul/yulOptimizerTests/expressionJoiner/multi_wrong_order2.yul +++ b/test/libyul/yulOptimizerTests/expressionJoiner/multi_wrong_order2.yul @@ -4,9 +4,9 @@ let x := mul(add(a, b), 2) sstore(x, 3) } -// ==== -// step: expressionJoiner // ---- +// step: expressionJoiner +// // { // let a := mload(2) // sstore(mul(add(a, mload(6)), 2), 3) diff --git a/test/libyul/yulOptimizerTests/expressionJoiner/no_replacement_across_blocks.yul b/test/libyul/yulOptimizerTests/expressionJoiner/no_replacement_across_blocks.yul index 02c4466a2..0e4f1916a 100644 --- a/test/libyul/yulOptimizerTests/expressionJoiner/no_replacement_across_blocks.yul +++ b/test/libyul/yulOptimizerTests/expressionJoiner/no_replacement_across_blocks.yul @@ -11,9 +11,9 @@ } sstore(x, 3) } -// ==== -// step: expressionJoiner // ---- +// step: expressionJoiner +// // { // let x := calldataload(mload(2)) // sstore(x, 3) diff --git a/test/libyul/yulOptimizerTests/expressionJoiner/no_replacement_in_loop_condition1.yul b/test/libyul/yulOptimizerTests/expressionJoiner/no_replacement_in_loop_condition1.yul index 0cc4e8f6d..b453446ad 100644 --- a/test/libyul/yulOptimizerTests/expressionJoiner/no_replacement_in_loop_condition1.yul +++ b/test/libyul/yulOptimizerTests/expressionJoiner/no_replacement_in_loop_condition1.yul @@ -1,9 +1,9 @@ { for { let b := mload(1) } b {} {} } -// ==== -// step: expressionJoiner // ---- +// step: expressionJoiner +// // { // for { let b := mload(1) } b { } // { } diff --git a/test/libyul/yulOptimizerTests/expressionJoiner/no_replacement_in_loop_condition2.yul b/test/libyul/yulOptimizerTests/expressionJoiner/no_replacement_in_loop_condition2.yul index 144476904..ab41999d5 100644 --- a/test/libyul/yulOptimizerTests/expressionJoiner/no_replacement_in_loop_condition2.yul +++ b/test/libyul/yulOptimizerTests/expressionJoiner/no_replacement_in_loop_condition2.yul @@ -2,9 +2,9 @@ let a := mload(0) for { } a {} {} } -// ==== -// step: expressionJoiner // ---- +// step: expressionJoiner +// // { // let a := mload(0) // for { } a { } diff --git a/test/libyul/yulOptimizerTests/expressionJoiner/only_assignment.yul b/test/libyul/yulOptimizerTests/expressionJoiner/only_assignment.yul index 12fa6ec51..30bf46634 100644 --- a/test/libyul/yulOptimizerTests/expressionJoiner/only_assignment.yul +++ b/test/libyul/yulOptimizerTests/expressionJoiner/only_assignment.yul @@ -5,9 +5,9 @@ x := add(a, 3) } } -// ==== -// step: expressionJoiner // ---- +// step: expressionJoiner +// // { // function f(a) -> x // { diff --git a/test/libyul/yulOptimizerTests/expressionJoiner/reassignment.yul b/test/libyul/yulOptimizerTests/expressionJoiner/reassignment.yul index 97661414f..e327d0b33 100644 --- a/test/libyul/yulOptimizerTests/expressionJoiner/reassignment.yul +++ b/test/libyul/yulOptimizerTests/expressionJoiner/reassignment.yul @@ -4,9 +4,9 @@ let b := mload(a) a := 4 } -// ==== -// step: expressionJoiner // ---- +// step: expressionJoiner +// // { // let a := mload(2) // let b := mload(a) diff --git a/test/libyul/yulOptimizerTests/expressionJoiner/simple.yul b/test/libyul/yulOptimizerTests/expressionJoiner/simple.yul index 03d2a7aee..5ec8a900a 100644 --- a/test/libyul/yulOptimizerTests/expressionJoiner/simple.yul +++ b/test/libyul/yulOptimizerTests/expressionJoiner/simple.yul @@ -3,9 +3,9 @@ let x := calldataload(a) sstore(x, 3) } -// ==== -// step: expressionJoiner // ---- +// step: expressionJoiner +// // { // sstore(calldataload(mload(2)), 3) // } diff --git a/test/libyul/yulOptimizerTests/expressionJoiner/single_wrong_order.yul b/test/libyul/yulOptimizerTests/expressionJoiner/single_wrong_order.yul index 21bf67c89..812cb7e7c 100644 --- a/test/libyul/yulOptimizerTests/expressionJoiner/single_wrong_order.yul +++ b/test/libyul/yulOptimizerTests/expressionJoiner/single_wrong_order.yul @@ -5,9 +5,9 @@ let d := add(b, c) sstore(d, 0) } -// ==== -// step: expressionJoiner // ---- +// step: expressionJoiner +// // { // let b := sload(mload(3)) // sstore(add(b, mload(7)), 0) diff --git a/test/libyul/yulOptimizerTests/expressionJoiner/smoke.yul b/test/libyul/yulOptimizerTests/expressionJoiner/smoke.yul index 7eb5f5285..77f73f112 100644 --- a/test/libyul/yulOptimizerTests/expressionJoiner/smoke.yul +++ b/test/libyul/yulOptimizerTests/expressionJoiner/smoke.yul @@ -1,5 +1,5 @@ { } -// ==== -// step: expressionJoiner // ---- +// step: expressionJoiner +// // { } diff --git a/test/libyul/yulOptimizerTests/expressionJoiner/switch_expression.yul b/test/libyul/yulOptimizerTests/expressionJoiner/switch_expression.yul index e8e787762..08f7bb9fb 100644 --- a/test/libyul/yulOptimizerTests/expressionJoiner/switch_expression.yul +++ b/test/libyul/yulOptimizerTests/expressionJoiner/switch_expression.yul @@ -14,9 +14,9 @@ let z := 3 let t := add(z, 9) } -// ==== -// step: expressionJoiner // ---- +// step: expressionJoiner +// // { // switch add(mload(7), sload(mload(3))) // case 3 { let y := add(mload(3), 3) } diff --git a/test/libyul/yulOptimizerTests/expressionJoiner/triple.yul b/test/libyul/yulOptimizerTests/expressionJoiner/triple.yul index cf2b4a615..d6c652e2c 100644 --- a/test/libyul/yulOptimizerTests/expressionJoiner/triple.yul +++ b/test/libyul/yulOptimizerTests/expressionJoiner/triple.yul @@ -5,9 +5,9 @@ let x := mul(add(c, b), a) sstore(x, 3) } -// ==== -// step: expressionJoiner // ---- +// step: expressionJoiner +// // { // sstore(mul(add(mload(7), mload(6)), mload(2)), 3) // } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/assigned_vars_multi.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/assigned_vars_multi.yul index 809f6ff23..783319395 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/assigned_vars_multi.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/assigned_vars_multi.yul @@ -3,9 +3,9 @@ let c, d := f() let y := add(d, add(c, 7)) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // function f() -> x, z // { } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/combine_shift_and_and.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/combine_shift_and_and.yul index 94caf0782..d465600e3 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/combine_shift_and_and.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/combine_shift_and_and.yul @@ -5,8 +5,9 @@ } // ==== // EVMVersion: >byzantium -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // let x := calldataload(0) // let a := shr(248, x) diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/combine_shift_and_and_2.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/combine_shift_and_and_2.yul index 36c56834b..6649a86b5 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/combine_shift_and_and_2.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/combine_shift_and_and_2.yul @@ -10,8 +10,9 @@ } // ==== // EVMVersion: >byzantium -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // let x := calldataload(0) // let a := 0 diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/combine_shift_and_and_3.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/combine_shift_and_and_3.yul index f506c41bd..4211b6afe 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/combine_shift_and_and_3.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/combine_shift_and_and_3.yul @@ -8,8 +8,9 @@ } // ==== // EVMVersion: >byzantium -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // let x := calldataload(0) // let a := and(shl(8, x), 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000) diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/constant_propagation.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/constant_propagation.yul index 983a3b251..2f655efba 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/constant_propagation.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/constant_propagation.yul @@ -1,5 +1,5 @@ { let a := add(7, sub(mload(0), 7)) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { let a := mload(0) } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/constants.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/constants.yul index efbcf8712..8bf04b987 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/constants.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/constants.yul @@ -1,5 +1,5 @@ { let a := add(1, mul(3, 4)) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { let a := 13 } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/create2_and_mask.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/create2_and_mask.yul index cd74d73ad..bbda84653 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/create2_and_mask.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/create2_and_mask.yul @@ -3,9 +3,10 @@ let b := and(0xffffffffffffffffffffffffffffffffffffffff, create2(0, 0, 0x20, 0)) } // ==== -// step: expressionSimplifier // EVMVersion: >=constantinople // ---- +// step: expressionSimplifier +// // { // let a := create2(0, 0, 0x20, 0) // let b := create2(0, 0, 0x20, 0) diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/create_and_mask.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/create_and_mask.yul index c7cc887dc..44a8cabb0 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/create_and_mask.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/create_and_mask.yul @@ -2,9 +2,9 @@ let a := and(create(0, 0, 0x20), 0xffffffffffffffffffffffffffffffffffffffff) let b := and(0xffffffffffffffffffffffffffffffffffffffff, create(0, 0, 0x20)) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // let a := create(0, 0, 0x20) // let b := create(0, 0, 0x20) diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/identity_rules_complex.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/identity_rules_complex.yul index e7b60d2df..38502d22c 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/identity_rules_complex.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/identity_rules_complex.yul @@ -1,5 +1,5 @@ { let a := sub(calldataload(0), calldataload(0)) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { let a := 0 } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/identity_rules_negative.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/identity_rules_negative.yul index 2838eb193..5f3d268ca 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/identity_rules_negative.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/identity_rules_negative.yul @@ -1,7 +1,7 @@ { let a := sub(calldataload(1), calldataload(0)) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // let a := sub(calldataload(1), calldataload(0)) // } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/identity_rules_simple.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/identity_rules_simple.yul index 554d080b2..d75ceb831 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/identity_rules_simple.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/identity_rules_simple.yul @@ -2,9 +2,9 @@ let a := mload(0) let b := sub(a, a) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // let a := mload(0) // let b := 0 diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/including_function_calls.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/including_function_calls.yul index 0c92afe38..73b6bfa54 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/including_function_calls.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/including_function_calls.yul @@ -2,9 +2,9 @@ function f() -> a {} let b := add(7, sub(f(), 7)) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // function f() -> a // { } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/inside_for.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/inside_for.yul index 83906d675..b8b3ee35d 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/inside_for.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/inside_for.yul @@ -2,9 +2,9 @@ let a := 10 for { } iszero(eq(a, 0)) { a := add(a, 1) } {} } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // let a := 10 // for { } iszero(iszero(a)) { a := add(a, 1) } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/invariant.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/invariant.yul index 9ad889243..fc75f131f 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/invariant.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/invariant.yul @@ -2,9 +2,9 @@ let a := mload(sub(7, 7)) let b := sub(a, 0) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // let a := mload(0) // let b := a diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/large_byte_access.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/large_byte_access.yul index d5e7c0ad4..073db8d4e 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/large_byte_access.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/large_byte_access.yul @@ -5,9 +5,9 @@ // create cannot be removed. let d := byte(33, create(0, 0, 0x20)) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // let a := calldataload(0) // let b := 0 diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/mod_and_1.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/mod_and_1.yul index 6d7b03035..65a325d6c 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/mod_and_1.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/mod_and_1.yul @@ -1,9 +1,9 @@ { mstore(0, mod(calldataload(0), exp(2, 8))) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // mstore(0, and(calldataload(0), 255)) // } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/mod_and_2.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/mod_and_2.yul index d949b2f17..d4e35af33 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/mod_and_2.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/mod_and_2.yul @@ -1,9 +1,9 @@ { mstore(0, mod(calldataload(0), exp(2, 255))) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // mstore(0, and(calldataload(0), 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)) // } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_function_call_different_arguments.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_function_call_different_arguments.yul index 1430fd718..b7bc3e4f9 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_function_call_different_arguments.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_function_call_different_arguments.yul @@ -2,9 +2,9 @@ function f(a) -> b { } let c := sub(f(0), f(1)) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // function f(a) -> b // { } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_function_call_different_names.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_function_call_different_names.yul index cc819fff8..b43440128 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_function_call_different_names.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_function_call_different_names.yul @@ -3,9 +3,9 @@ function f2() -> b { } let c := sub(f1(), f2()) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // function f1() -> a // { } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_function_call_equality_not_movable.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_function_call_equality_not_movable.yul index fc43fa788..c0fa43e2c 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_function_call_equality_not_movable.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_function_call_equality_not_movable.yul @@ -3,9 +3,9 @@ function f() -> a { } let b := sub(f(), f()) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // function f() -> a // { } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_removes_non_constant_and_not_movable.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_removes_non_constant_and_not_movable.yul index cee563173..d153ae724 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_removes_non_constant_and_not_movable.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_removes_non_constant_and_not_movable.yul @@ -3,9 +3,9 @@ { let a := div(keccak256(0, 0), 0) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // let a := div(keccak256(0, 0), 0) // } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/reassign.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/reassign.yul index 8178c6d03..fbc5befd0 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/reassign.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/reassign.yul @@ -3,9 +3,9 @@ x := 0 mstore(0, add(7, x)) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // let x := mload(0) // x := 0 diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/remove_redundant_shift_masking.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/remove_redundant_shift_masking.yul index cb5303eaf..b81ae9619 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/remove_redundant_shift_masking.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/remove_redundant_shift_masking.yul @@ -6,8 +6,9 @@ } // ==== // EVMVersion: >=constantinople -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // let a := shr(248, calldataload(0)) // let b := shr(248, calldataload(0)) diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/replace_too_large_shift.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/replace_too_large_shift.yul index 8d69bcc8d..550c7becb 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/replace_too_large_shift.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/replace_too_large_shift.yul @@ -6,8 +6,9 @@ } // ==== // EVMVersion: >=constantinople -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // let a := 0 // let b := 0 diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/return_vars_zero.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/return_vars_zero.yul index 8586396c4..c1c0093ef 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/return_vars_zero.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/return_vars_zero.yul @@ -4,9 +4,9 @@ let y := add(d, add(c, 7)) } } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // function f() -> c, d // { let y := 7 } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/reversed.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/reversed.yul index 1d398f833..9ca956c10 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/reversed.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/reversed.yul @@ -1,7 +1,7 @@ { let a := add(0, mload(0)) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { let a := mload(0) } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/side_effects_in_for_condition.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/side_effects_in_for_condition.yul index 7e181a097..14d65c4e9 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/side_effects_in_for_condition.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/side_effects_in_for_condition.yul @@ -4,9 +4,10 @@ } } // ==== -// step: expressionSimplifier // EVMVersion: >byzantium // ---- +// step: expressionSimplifier +// // { // for { } div(create(0, 1, 0), shl(msize(), 1)) { } // { } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/smoke.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/smoke.yul index 7562dfb47..30a2f5e90 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/smoke.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/smoke.yul @@ -1,5 +1,5 @@ { } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/unassigend_vars_multi.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/unassigend_vars_multi.yul index e5db5ff76..e88877365 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/unassigend_vars_multi.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/unassigend_vars_multi.yul @@ -3,9 +3,9 @@ let c, d let y := add(d, add(c, 7)) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // let c, d // let y := 7 diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/unassigned_vars.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/unassigned_vars.yul index f8480a327..d66d4efb2 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/unassigned_vars.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/unassigned_vars.yul @@ -4,9 +4,9 @@ let d let y := add(d, add(c, 7)) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // let c // let d diff --git a/test/libyul/yulOptimizerTests/expressionSplitter/control_flow.yul b/test/libyul/yulOptimizerTests/expressionSplitter/control_flow.yul index 2eb72c112..d56a5285e 100644 --- a/test/libyul/yulOptimizerTests/expressionSplitter/control_flow.yul +++ b/test/libyul/yulOptimizerTests/expressionSplitter/control_flow.yul @@ -7,9 +7,9 @@ } } } -// ==== -// step: expressionSplitter // ---- +// step: expressionSplitter +// // { // let _1 := 0 // let x := calldataload(_1) diff --git a/test/libyul/yulOptimizerTests/expressionSplitter/inside_function.yul b/test/libyul/yulOptimizerTests/expressionSplitter/inside_function.yul index bb73118ec..294cac14a 100644 --- a/test/libyul/yulOptimizerTests/expressionSplitter/inside_function.yul +++ b/test/libyul/yulOptimizerTests/expressionSplitter/inside_function.yul @@ -5,9 +5,9 @@ } sstore(x, f(mload(2), mload(2))) } -// ==== -// step: expressionSplitter // ---- +// step: expressionSplitter +// // { // let _1 := 3 // let _2 := 7 diff --git a/test/libyul/yulOptimizerTests/expressionSplitter/object_access.yul b/test/libyul/yulOptimizerTests/expressionSplitter/object_access.yul index 969991871..60492e027 100644 --- a/test/libyul/yulOptimizerTests/expressionSplitter/object_access.yul +++ b/test/libyul/yulOptimizerTests/expressionSplitter/object_access.yul @@ -9,9 +9,9 @@ object "main" { } data "abc" "Hello, World!" } -// ==== -// step: expressionSplitter // ---- +// step: expressionSplitter +// // { // let x := dataoffset("abc") // let y := datasize("abc") diff --git a/test/libyul/yulOptimizerTests/expressionSplitter/smoke.yul b/test/libyul/yulOptimizerTests/expressionSplitter/smoke.yul index c47eebe7b..c5f979bf1 100644 --- a/test/libyul/yulOptimizerTests/expressionSplitter/smoke.yul +++ b/test/libyul/yulOptimizerTests/expressionSplitter/smoke.yul @@ -1,5 +1,5 @@ { } -// ==== -// step: expressionSplitter // ---- +// step: expressionSplitter +// // { } diff --git a/test/libyul/yulOptimizerTests/expressionSplitter/switch.yul b/test/libyul/yulOptimizerTests/expressionSplitter/switch.yul index 3608cab4f..3664a7e26 100644 --- a/test/libyul/yulOptimizerTests/expressionSplitter/switch.yul +++ b/test/libyul/yulOptimizerTests/expressionSplitter/switch.yul @@ -5,9 +5,9 @@ default { mstore(0, mload(3)) } x := add(mload(3), 4) } -// ==== -// step: expressionSplitter // ---- +// step: expressionSplitter +// // { // let x := 8 // let _1 := 0 diff --git a/test/libyul/yulOptimizerTests/expressionSplitter/trivial.yul b/test/libyul/yulOptimizerTests/expressionSplitter/trivial.yul index 3d48eed79..a70827b93 100644 --- a/test/libyul/yulOptimizerTests/expressionSplitter/trivial.yul +++ b/test/libyul/yulOptimizerTests/expressionSplitter/trivial.yul @@ -1,9 +1,9 @@ { mstore(add(calldataload(2), mload(3)), 8) } -// ==== -// step: expressionSplitter // ---- +// step: expressionSplitter +// // { // let _1 := 8 // let _2 := 3 diff --git a/test/libyul/yulOptimizerTests/expressionSplitter/typed.yul b/test/libyul/yulOptimizerTests/expressionSplitter/typed.yul index 37f40f5e6..4bae497d6 100644 --- a/test/libyul/yulOptimizerTests/expressionSplitter/typed.yul +++ b/test/libyul/yulOptimizerTests/expressionSplitter/typed.yul @@ -11,8 +11,9 @@ } // ==== // dialect: ewasm -// step: expressionSplitter // ---- +// step: expressionSplitter +// // { // function fun(x:i32, y) -> t:i32, z:i32 // { diff --git a/test/libyul/yulOptimizerTests/forLoopConditionIntoBody/cond_types.yul b/test/libyul/yulOptimizerTests/forLoopConditionIntoBody/cond_types.yul index 95e171475..031507a38 100644 --- a/test/libyul/yulOptimizerTests/forLoopConditionIntoBody/cond_types.yul +++ b/test/libyul/yulOptimizerTests/forLoopConditionIntoBody/cond_types.yul @@ -6,9 +6,9 @@ for { } a { } { } for { } add(a, a) { } { } } -// ==== -// step: forLoopConditionIntoBody // ---- +// step: forLoopConditionIntoBody +// // { // let a := 1 // for { } 42 { } diff --git a/test/libyul/yulOptimizerTests/forLoopConditionIntoBody/empty_body.yul b/test/libyul/yulOptimizerTests/forLoopConditionIntoBody/empty_body.yul index 6f1ad5458..41c9e4234 100644 --- a/test/libyul/yulOptimizerTests/forLoopConditionIntoBody/empty_body.yul +++ b/test/libyul/yulOptimizerTests/forLoopConditionIntoBody/empty_body.yul @@ -1,9 +1,9 @@ { for { let a := 1 } iszero(eq(a, 10)) { a := add(a, 1) } { } } -// ==== -// step: forLoopConditionIntoBody // ---- +// step: forLoopConditionIntoBody +// // { // for { let a := 1 } true { a := add(a, 1) } // { diff --git a/test/libyul/yulOptimizerTests/forLoopConditionIntoBody/nested.yul b/test/libyul/yulOptimizerTests/forLoopConditionIntoBody/nested.yul index 292284a65..acbe3e456 100644 --- a/test/libyul/yulOptimizerTests/forLoopConditionIntoBody/nested.yul +++ b/test/libyul/yulOptimizerTests/forLoopConditionIntoBody/nested.yul @@ -13,9 +13,9 @@ mstore(b,b) } } -// ==== -// step: forLoopConditionIntoBody // ---- +// step: forLoopConditionIntoBody +// // { // let random := 42 // for { diff --git a/test/libyul/yulOptimizerTests/forLoopConditionIntoBody/simple.yul b/test/libyul/yulOptimizerTests/forLoopConditionIntoBody/simple.yul index f47026462..bbe782307 100644 --- a/test/libyul/yulOptimizerTests/forLoopConditionIntoBody/simple.yul +++ b/test/libyul/yulOptimizerTests/forLoopConditionIntoBody/simple.yul @@ -4,9 +4,9 @@ a := add(a, 1) } } -// ==== -// step: forLoopConditionIntoBody // ---- +// step: forLoopConditionIntoBody +// // { // let random := 42 // for { let a := 1 } true { a := add(a, 1) } diff --git a/test/libyul/yulOptimizerTests/forLoopInitRewriter/complex_pre.yul b/test/libyul/yulOptimizerTests/forLoopInitRewriter/complex_pre.yul index 951a5fbe6..6304c4de5 100644 --- a/test/libyul/yulOptimizerTests/forLoopInitRewriter/complex_pre.yul +++ b/test/libyul/yulOptimizerTests/forLoopInitRewriter/complex_pre.yul @@ -5,9 +5,9 @@ a := add(a, 1) } } -// ==== -// step: forLoopInitRewriter // ---- +// step: forLoopInitRewriter +// // { // let random := 42 // let a := 1 diff --git a/test/libyul/yulOptimizerTests/forLoopInitRewriter/empty_pre.yul b/test/libyul/yulOptimizerTests/forLoopInitRewriter/empty_pre.yul index 9fa5fd37e..38a00f752 100644 --- a/test/libyul/yulOptimizerTests/forLoopInitRewriter/empty_pre.yul +++ b/test/libyul/yulOptimizerTests/forLoopInitRewriter/empty_pre.yul @@ -4,9 +4,9 @@ a := add(a, 1) } } -// ==== -// step: forLoopInitRewriter // ---- +// step: forLoopInitRewriter +// // { // let a := 1 // for { } iszero(eq(a, 10)) { a := add(a, 1) } diff --git a/test/libyul/yulOptimizerTests/forLoopInitRewriter/nested.yul b/test/libyul/yulOptimizerTests/forLoopInitRewriter/nested.yul index c751f4483..331d9cdde 100644 --- a/test/libyul/yulOptimizerTests/forLoopInitRewriter/nested.yul +++ b/test/libyul/yulOptimizerTests/forLoopInitRewriter/nested.yul @@ -13,9 +13,9 @@ mstore(b,b) } } -// ==== -// step: forLoopInitRewriter // ---- +// step: forLoopInitRewriter +// // { // let random := 42 // let a := 1 diff --git a/test/libyul/yulOptimizerTests/forLoopInitRewriter/simple.yul b/test/libyul/yulOptimizerTests/forLoopInitRewriter/simple.yul index c8db1e5aa..0dad89961 100644 --- a/test/libyul/yulOptimizerTests/forLoopInitRewriter/simple.yul +++ b/test/libyul/yulOptimizerTests/forLoopInitRewriter/simple.yul @@ -4,9 +4,9 @@ a := add(a, 1) } } -// ==== -// step: forLoopInitRewriter // ---- +// step: forLoopInitRewriter +// // { // let random := 42 // let a := 1 diff --git a/test/libyul/yulOptimizerTests/fullInliner/double_inline.yul b/test/libyul/yulOptimizerTests/fullInliner/double_inline.yul index b3ec1bbe8..259e4aeda 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/double_inline.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/double_inline.yul @@ -4,9 +4,9 @@ let b3, c3 := f(a1) let b4, c4 := f(c3) } -// ==== -// step: fullInliner // ---- +// step: fullInliner +// // { // { // let a_2 := calldataload(0) diff --git a/test/libyul/yulOptimizerTests/fullInliner/inside_condition.yul b/test/libyul/yulOptimizerTests/fullInliner/inside_condition.yul index fd9d893ae..39c3bb295 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/inside_condition.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/inside_condition.yul @@ -8,9 +8,9 @@ r := add(a, calldatasize()) } } -// ==== -// step: fullInliner // ---- +// step: fullInliner +// // { // { // let _2 := mload(0) diff --git a/test/libyul/yulOptimizerTests/fullInliner/large_function_multi_use.yul b/test/libyul/yulOptimizerTests/fullInliner/large_function_multi_use.yul index a088e1681..151b7596c 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/large_function_multi_use.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/large_function_multi_use.yul @@ -15,9 +15,9 @@ // This should be inlined because it is a constant as well (zero) let s := f(a3) } -// ==== -// step: fullInliner // ---- +// step: fullInliner +// // { // { // let a_1 := mload(2) diff --git a/test/libyul/yulOptimizerTests/fullInliner/large_function_single_use.yul b/test/libyul/yulOptimizerTests/fullInliner/large_function_single_use.yul index b8c05b72c..4bcfe6f19 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/large_function_single_use.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/large_function_single_use.yul @@ -10,9 +10,9 @@ // Single-use functions are always inlined. let r := f(mload(1)) } -// ==== -// step: fullInliner // ---- +// step: fullInliner +// // { // { // let a_6 := mload(1) diff --git a/test/libyul/yulOptimizerTests/fullInliner/long_names.yul b/test/libyul/yulOptimizerTests/fullInliner/long_names.yul index 8e9c2019d..b2162c520 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/long_names.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/long_names.yul @@ -7,9 +7,9 @@ mstore(0, verylongfunctionname(verylongvariablename2)) mstore(1, verylongvariablename2) } -// ==== -// step: fullInliner // ---- +// step: fullInliner +// // { // { // let verylongvariablename2_1 := 3 diff --git a/test/libyul/yulOptimizerTests/fullInliner/move_up_rightwards_argument.yul b/test/libyul/yulOptimizerTests/fullInliner/move_up_rightwards_argument.yul index f40563602..7bc959ec8 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/move_up_rightwards_argument.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/move_up_rightwards_argument.yul @@ -5,9 +5,9 @@ } let y := add(mload(1), add(f(mload(2), mload(3), mload(4)), mload(5))) } -// ==== -// step: fullInliner // ---- +// step: fullInliner +// // { // { // let _2 := mload(5) diff --git a/test/libyul/yulOptimizerTests/fullInliner/multi_fun.yul b/test/libyul/yulOptimizerTests/fullInliner/multi_fun.yul index 2f8a85842..56cac2704 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/multi_fun.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/multi_fun.yul @@ -3,9 +3,9 @@ function g(b, c) -> y { y := mul(mload(c), f(b)) } let y := g(f(3), 7) } -// ==== -// step: fullInliner // ---- +// step: fullInliner +// // { // { // let _1 := 7 diff --git a/test/libyul/yulOptimizerTests/fullInliner/multi_fun_callback.yul b/test/libyul/yulOptimizerTests/fullInliner/multi_fun_callback.yul index 46980522d..98c8e3010 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/multi_fun_callback.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/multi_fun_callback.yul @@ -22,9 +22,9 @@ f(100) } } -// ==== -// step: fullInliner // ---- +// step: fullInliner +// // { // { // let x_8 := 100 diff --git a/test/libyul/yulOptimizerTests/fullInliner/multi_return.yul b/test/libyul/yulOptimizerTests/fullInliner/multi_return.yul index 7d90e0118..21369f10b 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/multi_return.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/multi_return.yul @@ -6,9 +6,9 @@ let r, s := f(mload(0)) mstore(r, s) } -// ==== -// step: fullInliner // ---- +// step: fullInliner +// // { // { // let a_3 := mload(0) diff --git a/test/libyul/yulOptimizerTests/fullInliner/multi_return_typed.yul b/test/libyul/yulOptimizerTests/fullInliner/multi_return_typed.yul index f9f01a193..143ae35b2 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/multi_return_typed.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/multi_return_typed.yul @@ -6,8 +6,9 @@ } // ==== // dialect: evmTyped -// step: fullInliner // ---- +// step: fullInliner +// // { // { // let a_3 := mload(3) diff --git a/test/libyul/yulOptimizerTests/fullInliner/no_inline_into_big_function.yul b/test/libyul/yulOptimizerTests/fullInliner/no_inline_into_big_function.yul index 4a7837ca2..c1ce89bcf 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/no_inline_into_big_function.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/no_inline_into_big_function.yul @@ -9,9 +9,9 @@ x := f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(2))))))))))))))))))) } } -// ==== -// step: fullInliner // ---- +// step: fullInliner +// // { // function f(a) -> b // { b := sload(mload(a)) } diff --git a/test/libyul/yulOptimizerTests/fullInliner/no_inline_into_big_global_context.yul b/test/libyul/yulOptimizerTests/fullInliner/no_inline_into_big_global_context.yul index 337612d37..10ccc2a37 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/no_inline_into_big_global_context.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/no_inline_into_big_global_context.yul @@ -7,9 +7,9 @@ // the global context gets too big. let x := f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(2))))))))))))))))))) } -// ==== -// step: fullInliner // ---- +// step: fullInliner +// // { // { // let a_20 := 2 diff --git a/test/libyul/yulOptimizerTests/fullInliner/no_inline_leave.yul b/test/libyul/yulOptimizerTests/fullInliner/no_inline_leave.yul index 552ce9a82..a22025c4b 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/no_inline_leave.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/no_inline_leave.yul @@ -4,9 +4,9 @@ let a1 := calldataload(0) f(a1) } -// ==== -// step: fullInliner // ---- +// step: fullInliner +// // { // { // let a_2 := calldataload(0) diff --git a/test/libyul/yulOptimizerTests/fullInliner/no_return.yul b/test/libyul/yulOptimizerTests/fullInliner/no_return.yul index c45e7a3c7..2897b5151 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/no_return.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/no_return.yul @@ -4,9 +4,9 @@ } f(mload(0)) } -// ==== -// step: fullInliner // ---- +// step: fullInliner +// // { // { // let a_3 := mload(0) diff --git a/test/libyul/yulOptimizerTests/fullInliner/not_inside_for.yul b/test/libyul/yulOptimizerTests/fullInliner/not_inside_for.yul index 94282bf5c..5678a13fd 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/not_inside_for.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/not_inside_for.yul @@ -9,9 +9,9 @@ r := a } } -// ==== -// step: fullInliner // ---- +// step: fullInliner +// // { // { // let a_3 := 0 diff --git a/test/libyul/yulOptimizerTests/fullInliner/pop_result.yul b/test/libyul/yulOptimizerTests/fullInliner/pop_result.yul index 373416925..c46505c79 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/pop_result.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/pop_result.yul @@ -8,9 +8,9 @@ } pop(add(f(7), 2)) } -// ==== -// step: fullInliner // ---- +// step: fullInliner +// // { // { // let _1 := 2 diff --git a/test/libyul/yulOptimizerTests/fullInliner/recursion.yul b/test/libyul/yulOptimizerTests/fullInliner/recursion.yul index 82632a9e7..375327e65 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/recursion.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/recursion.yul @@ -4,9 +4,9 @@ } f(mload(0)) } -// ==== -// step: fullInliner // ---- +// step: fullInliner +// // { // { f(mload(0)) } // function f(a) diff --git a/test/libyul/yulOptimizerTests/fullInliner/simple.yul b/test/libyul/yulOptimizerTests/fullInliner/simple.yul index af6fa8283..2c9d979b5 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/simple.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/simple.yul @@ -5,9 +5,9 @@ } let y := add(f(sload(mload(2))), mload(7)) } -// ==== -// step: fullInliner // ---- +// step: fullInliner +// // { // { // let _2 := mload(7) diff --git a/test/libyul/yulOptimizerTests/fullSimplify/constant_propagation.yul b/test/libyul/yulOptimizerTests/fullSimplify/constant_propagation.yul index 4c7fa2692..968ec4767 100644 --- a/test/libyul/yulOptimizerTests/fullSimplify/constant_propagation.yul +++ b/test/libyul/yulOptimizerTests/fullSimplify/constant_propagation.yul @@ -2,9 +2,9 @@ let a := add(7, sub(mload(0), 7)) mstore(a, 0) } -// ==== -// step: fullSimplify // ---- +// step: fullSimplify +// // { // let _2 := 0 // mstore(mload(_2), _2) diff --git a/test/libyul/yulOptimizerTests/fullSimplify/constants.yul b/test/libyul/yulOptimizerTests/fullSimplify/constants.yul index 2ea5ea442..0b31d361f 100644 --- a/test/libyul/yulOptimizerTests/fullSimplify/constants.yul +++ b/test/libyul/yulOptimizerTests/fullSimplify/constants.yul @@ -2,7 +2,7 @@ let a := add(1, mul(3, 4)) mstore(0, a) } -// ==== -// step: fullSimplify // ---- +// step: fullSimplify +// // { mstore(0, 13) } diff --git a/test/libyul/yulOptimizerTests/fullSimplify/identity_rules_complex.yul b/test/libyul/yulOptimizerTests/fullSimplify/identity_rules_complex.yul index df7712b7a..452ceaae6 100644 --- a/test/libyul/yulOptimizerTests/fullSimplify/identity_rules_complex.yul +++ b/test/libyul/yulOptimizerTests/fullSimplify/identity_rules_complex.yul @@ -2,7 +2,7 @@ let a := sub(calldataload(0), calldataload(0)) mstore(a, 0) } -// ==== -// step: fullSimplify // ---- +// step: fullSimplify +// // { mstore(0, 0) } diff --git a/test/libyul/yulOptimizerTests/fullSimplify/identity_rules_negative.yul b/test/libyul/yulOptimizerTests/fullSimplify/identity_rules_negative.yul index bc7bf5b5a..8c5e4e5df 100644 --- a/test/libyul/yulOptimizerTests/fullSimplify/identity_rules_negative.yul +++ b/test/libyul/yulOptimizerTests/fullSimplify/identity_rules_negative.yul @@ -2,9 +2,9 @@ let a := sub(calldataload(1), calldataload(0)) mstore(0, a) } -// ==== -// step: fullSimplify // ---- +// step: fullSimplify +// // { // let _1 := 0 // mstore(_1, sub(calldataload(1), calldataload(_1))) diff --git a/test/libyul/yulOptimizerTests/fullSimplify/identity_rules_simple.yul b/test/libyul/yulOptimizerTests/fullSimplify/identity_rules_simple.yul index 1e9de7755..e8efb735c 100644 --- a/test/libyul/yulOptimizerTests/fullSimplify/identity_rules_simple.yul +++ b/test/libyul/yulOptimizerTests/fullSimplify/identity_rules_simple.yul @@ -2,7 +2,7 @@ let a := mload(0) mstore(0, sub(a, a)) } -// ==== -// step: fullSimplify // ---- +// step: fullSimplify +// // { mstore(0, 0) } diff --git a/test/libyul/yulOptimizerTests/fullSimplify/including_function_calls.yul b/test/libyul/yulOptimizerTests/fullSimplify/including_function_calls.yul index d75e681a4..73bd6c363 100644 --- a/test/libyul/yulOptimizerTests/fullSimplify/including_function_calls.yul +++ b/test/libyul/yulOptimizerTests/fullSimplify/including_function_calls.yul @@ -3,9 +3,9 @@ let b := add(7, sub(f(), 7)) mstore(b, 0) } -// ==== -// step: fullSimplify // ---- +// step: fullSimplify +// // { // function f() -> a // { } diff --git a/test/libyul/yulOptimizerTests/fullSimplify/inside_for.yul b/test/libyul/yulOptimizerTests/fullSimplify/inside_for.yul index 339e744d7..9d4e52dc1 100644 --- a/test/libyul/yulOptimizerTests/fullSimplify/inside_for.yul +++ b/test/libyul/yulOptimizerTests/fullSimplify/inside_for.yul @@ -3,9 +3,9 @@ let a := 10 for { } iszero(eq(a, sub(x, calldataload(3)))) { a := add(a, 1) } {} } -// ==== -// step: fullSimplify // ---- +// step: fullSimplify +// // { // let a := 10 // for { } iszero(iszero(a)) { a := add(a, 1) } diff --git a/test/libyul/yulOptimizerTests/fullSimplify/invariant.yul b/test/libyul/yulOptimizerTests/fullSimplify/invariant.yul index 453f74e33..687491818 100644 --- a/test/libyul/yulOptimizerTests/fullSimplify/invariant.yul +++ b/test/libyul/yulOptimizerTests/fullSimplify/invariant.yul @@ -7,9 +7,9 @@ // run of CSE afterwards. mstore(b, eq(calldataload(0), a)) } -// ==== -// step: fullSimplify // ---- +// step: fullSimplify +// // { // let a := calldataload(0) // let _4 := 0 diff --git a/test/libyul/yulOptimizerTests/fullSimplify/mod_and_1.yul b/test/libyul/yulOptimizerTests/fullSimplify/mod_and_1.yul index 59dbf172b..1e448c9a4 100644 --- a/test/libyul/yulOptimizerTests/fullSimplify/mod_and_1.yul +++ b/test/libyul/yulOptimizerTests/fullSimplify/mod_and_1.yul @@ -1,9 +1,9 @@ { mstore(0, mod(calldataload(0), exp(2, 8))) } -// ==== -// step: fullSimplify // ---- +// step: fullSimplify +// // { // let _4 := 0 // mstore(_4, and(calldataload(_4), 255)) diff --git a/test/libyul/yulOptimizerTests/fullSimplify/mod_and_2.yul b/test/libyul/yulOptimizerTests/fullSimplify/mod_and_2.yul index 41254b818..0756c1841 100644 --- a/test/libyul/yulOptimizerTests/fullSimplify/mod_and_2.yul +++ b/test/libyul/yulOptimizerTests/fullSimplify/mod_and_2.yul @@ -1,9 +1,9 @@ { mstore(0, mod(calldataload(0), exp(2, 255))) } -// ==== -// step: fullSimplify // ---- +// step: fullSimplify +// // { // let _4 := 0 // mstore(_4, and(calldataload(_4), 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)) diff --git a/test/libyul/yulOptimizerTests/fullSimplify/not_applied_function_call_different_arguments.yul b/test/libyul/yulOptimizerTests/fullSimplify/not_applied_function_call_different_arguments.yul index 5038a6fa9..8dd271d9f 100644 --- a/test/libyul/yulOptimizerTests/fullSimplify/not_applied_function_call_different_arguments.yul +++ b/test/libyul/yulOptimizerTests/fullSimplify/not_applied_function_call_different_arguments.yul @@ -2,9 +2,9 @@ function f(a) -> b { } mstore(0, sub(f(0), f(1))) } -// ==== -// step: fullSimplify // ---- +// step: fullSimplify +// // { // function f(a) -> b // { } diff --git a/test/libyul/yulOptimizerTests/fullSimplify/not_applied_function_call_different_names.yul b/test/libyul/yulOptimizerTests/fullSimplify/not_applied_function_call_different_names.yul index 72ebadd20..0b17b1e4a 100644 --- a/test/libyul/yulOptimizerTests/fullSimplify/not_applied_function_call_different_names.yul +++ b/test/libyul/yulOptimizerTests/fullSimplify/not_applied_function_call_different_names.yul @@ -4,9 +4,9 @@ let c := sub(f1(), f2()) mstore(0, c) } -// ==== -// step: fullSimplify // ---- +// step: fullSimplify +// // { // function f1() -> a // { } diff --git a/test/libyul/yulOptimizerTests/fullSimplify/not_applied_function_call_equality_not_movable.yul b/test/libyul/yulOptimizerTests/fullSimplify/not_applied_function_call_equality_not_movable.yul index 11de59aba..3133c69ca 100644 --- a/test/libyul/yulOptimizerTests/fullSimplify/not_applied_function_call_equality_not_movable.yul +++ b/test/libyul/yulOptimizerTests/fullSimplify/not_applied_function_call_equality_not_movable.yul @@ -4,9 +4,9 @@ let b := sub(f(), f()) mstore(0, b) } -// ==== -// step: fullSimplify // ---- +// step: fullSimplify +// // { // function f() -> a // { mstore(1, 2) } diff --git a/test/libyul/yulOptimizerTests/fullSimplify/not_applied_removes_non_constant_and_not_movable.yul b/test/libyul/yulOptimizerTests/fullSimplify/not_applied_removes_non_constant_and_not_movable.yul index 9f916198c..05fc9447d 100644 --- a/test/libyul/yulOptimizerTests/fullSimplify/not_applied_removes_non_constant_and_not_movable.yul +++ b/test/libyul/yulOptimizerTests/fullSimplify/not_applied_removes_non_constant_and_not_movable.yul @@ -3,9 +3,9 @@ let a := div(create(0, 0, 0), 0) mstore(0, a) } -// ==== -// step: fullSimplify // ---- +// step: fullSimplify +// // { // let _1 := 0 // pop(create(_1, _1, _1)) diff --git a/test/libyul/yulOptimizerTests/fullSimplify/operations.yul b/test/libyul/yulOptimizerTests/fullSimplify/operations.yul index 811f86780..93b424233 100644 --- a/test/libyul/yulOptimizerTests/fullSimplify/operations.yul +++ b/test/libyul/yulOptimizerTests/fullSimplify/operations.yul @@ -19,9 +19,9 @@ mstore(17, or(x, not(x))) mstore(18, or(not(x), x)) } -// ==== -// step: fullSimplify // ---- +// step: fullSimplify +// // { // mstore(1, 0) // mstore(2, 0) diff --git a/test/libyul/yulOptimizerTests/fullSimplify/reversed.yul b/test/libyul/yulOptimizerTests/fullSimplify/reversed.yul index fceec7ecf..5fe632495 100644 --- a/test/libyul/yulOptimizerTests/fullSimplify/reversed.yul +++ b/test/libyul/yulOptimizerTests/fullSimplify/reversed.yul @@ -2,9 +2,9 @@ let a := add(0, mload(0)) mstore(0, a) } -// ==== -// step: fullSimplify // ---- +// step: fullSimplify +// // { // let _1 := 0 // mstore(_1, mload(_1)) diff --git a/test/libyul/yulOptimizerTests/fullSimplify/signextend.yul b/test/libyul/yulOptimizerTests/fullSimplify/signextend.yul index 13d4997dd..9ebdf0128 100644 --- a/test/libyul/yulOptimizerTests/fullSimplify/signextend.yul +++ b/test/libyul/yulOptimizerTests/fullSimplify/signextend.yul @@ -4,9 +4,9 @@ let y := 255 mstore(1, signextend(0, y)) } -// ==== -// step: fullSimplify // ---- +// step: fullSimplify +// // { // mstore(0, 7) // mstore(1, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) diff --git a/test/libyul/yulOptimizerTests/fullSimplify/smoke.yul b/test/libyul/yulOptimizerTests/fullSimplify/smoke.yul index 7ff4c60c3..15ff14a84 100644 --- a/test/libyul/yulOptimizerTests/fullSimplify/smoke.yul +++ b/test/libyul/yulOptimizerTests/fullSimplify/smoke.yul @@ -1,5 +1,5 @@ { } -// ==== -// step: fullSimplify // ---- +// step: fullSimplify +// // { } diff --git a/test/libyul/yulOptimizerTests/fullSuite/abi2.yul b/test/libyul/yulOptimizerTests/fullSuite/abi2.yul index 384a47d89..2f400186a 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/abi2.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/abi2.yul @@ -1071,9 +1071,10 @@ } } // ==== -// step: fullSuite // EVMVersion: >=constantinople // ---- +// step: fullSuite +// // { // { // let _1 := mload(1) diff --git a/test/libyul/yulOptimizerTests/fullSuite/abi_example1.yul b/test/libyul/yulOptimizerTests/fullSuite/abi_example1.yul index 4557c1889..5e6e0305d 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/abi_example1.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/abi_example1.yul @@ -458,8 +458,9 @@ } // ==== // EVMVersion: >=constantinople -// step: fullSuite // ---- +// step: fullSuite +// // { // { // let _1 := 0 diff --git a/test/libyul/yulOptimizerTests/fullSuite/aztec.yul b/test/libyul/yulOptimizerTests/fullSuite/aztec.yul index 635da72d6..1076f349a 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/aztec.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/aztec.yul @@ -228,9 +228,9 @@ mstore(0x00, keccak256(0x300, mul(n, 0x80))) } } -// ==== -// step: fullSuite // ---- +// step: fullSuite +// // { // { // let _1 := 0x80 diff --git a/test/libyul/yulOptimizerTests/fullSuite/clear_after_if_continue.yul b/test/libyul/yulOptimizerTests/fullSuite/clear_after_if_continue.yul index a9cdb84e0..71ed36d97 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/clear_after_if_continue.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/clear_after_if_continue.yul @@ -6,9 +6,9 @@ } if y { revert(0, 0) } } -// ==== -// step: fullSuite // ---- +// step: fullSuite +// // { // { // let y := mload(0x20) diff --git a/test/libyul/yulOptimizerTests/fullSuite/devcon_example.yul b/test/libyul/yulOptimizerTests/fullSuite/devcon_example.yul index 314f2a363..c5cdf8104 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/devcon_example.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/devcon_example.yul @@ -14,9 +14,9 @@ v := calldataload(add(data, mul(i, 0x20))) } } -// ==== -// step: fullSuite // ---- +// step: fullSuite +// // { // { // let _1 := calldataload(0) diff --git a/test/libyul/yulOptimizerTests/fullSuite/loopInvariantCodeMotion.yul b/test/libyul/yulOptimizerTests/fullSuite/loopInvariantCodeMotion.yul index f8fb81aa8..3b30ac4f7 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/loopInvariantCodeMotion.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/loopInvariantCodeMotion.yul @@ -17,9 +17,9 @@ v := add(v, calldataload(7)) } } -// ==== -// step: fullSuite // ---- +// step: fullSuite +// // { // { // let _1 := calldataload(0) diff --git a/test/libyul/yulOptimizerTests/fullSuite/medium.yul b/test/libyul/yulOptimizerTests/fullSuite/medium.yul index c5ed25e2f..4f1a6f35d 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/medium.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/medium.yul @@ -16,9 +16,9 @@ for { switch mul(1,2) case 2 { mstore(0x40, 0x20) } } sub(1,1) {} { mstore(0x80, 0x40) } } } -// ==== -// step: fullSuite // ---- +// step: fullSuite +// // { // { // let p := mload(0x40) diff --git a/test/libyul/yulOptimizerTests/fullSuite/no_move_loop_orig.yul b/test/libyul/yulOptimizerTests/fullSuite/no_move_loop_orig.yul index 4efe81d89..f0ee054b9 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/no_move_loop_orig.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/no_move_loop_orig.yul @@ -7,9 +7,9 @@ } {} } -// ==== -// step: fullSuite // ---- +// step: fullSuite +// // { // { // let _1 := iszero(caller()) diff --git a/test/libyul/yulOptimizerTests/fullSuite/remove_redundant_assignments_in_switch.yul b/test/libyul/yulOptimizerTests/fullSuite/remove_redundant_assignments_in_switch.yul index fa1364297..a0ac5c36d 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/remove_redundant_assignments_in_switch.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/remove_redundant_assignments_in_switch.yul @@ -6,9 +6,9 @@ default { invalid() } mstore(1, 1) } -// ==== -// step: fullSuite // ---- +// step: fullSuite +// // { // { // switch mload(0) diff --git a/test/libyul/yulOptimizerTests/fullSuite/reuse_vars_bug_in_simplifier.yul b/test/libyul/yulOptimizerTests/fullSuite/reuse_vars_bug_in_simplifier.yul index bb350bf8f..6e217ae4f 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/reuse_vars_bug_in_simplifier.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/reuse_vars_bug_in_simplifier.yul @@ -9,7 +9,7 @@ mstore(sub(1,div(sub(x_9,1),sub(1,sub(x_9,1)))), 1) } } -// ==== -// step: fullSuite // ---- +// step: fullSuite +// // { { mstore(1, 1) } } diff --git a/test/libyul/yulOptimizerTests/fullSuite/ssaReverse.yul b/test/libyul/yulOptimizerTests/fullSuite/ssaReverse.yul index c4a70b03e..78af81f38 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/ssaReverse.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/ssaReverse.yul @@ -31,9 +31,9 @@ a,b := abi_decode_t_bytes_calldata_ptr(a,b) mstore(a,b) } -// ==== -// step: fullSuite // ---- +// step: fullSuite +// // { // { // let a, b := abi_decode_t_bytes_calldata_ptr(mload(0), mload(1)) diff --git a/test/libyul/yulOptimizerTests/fullSuite/ssaReverseComplex.yul b/test/libyul/yulOptimizerTests/fullSuite/ssaReverseComplex.yul index 564ed9664..4421dd3cd 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/ssaReverseComplex.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/ssaReverseComplex.yul @@ -9,9 +9,9 @@ } mstore(a, b) } -// ==== -// step: fullSuite // ---- +// step: fullSuite +// // { // { // let a := mload(0) diff --git a/test/libyul/yulOptimizerTests/fullSuite/stack_compressor_msize.yul b/test/libyul/yulOptimizerTests/fullSuite/stack_compressor_msize.yul index 6a4e52652..961abd72c 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/stack_compressor_msize.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/stack_compressor_msize.yul @@ -20,9 +20,9 @@ sstore(0,0) sstore(3,1) } -// ==== -// step: fullSuite // ---- +// step: fullSuite +// // { // { // let _1 := gt(not(pc()), 1) diff --git a/test/libyul/yulOptimizerTests/fullSuite/storage.yul b/test/libyul/yulOptimizerTests/fullSuite/storage.yul index 4daff379f..7b3360847 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/storage.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/storage.yul @@ -3,9 +3,9 @@ sstore(4, 3) sstore(8, sload(4)) } -// ==== -// step: fullSuite // ---- +// step: fullSuite +// // { // { // sstore(4, 5) diff --git a/test/libyul/yulOptimizerTests/fullSuite/switch_inline.yul b/test/libyul/yulOptimizerTests/fullSuite/switch_inline.yul index 2e878e437..65c7512d3 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/switch_inline.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/switch_inline.yul @@ -6,7 +6,7 @@ case 1 { y := 9 } } } -// ==== -// step: fullSuite // ---- +// step: fullSuite +// // { { mstore(9, 0) } } diff --git a/test/libyul/yulOptimizerTests/fullSuite/switch_inline_match_default.yul b/test/libyul/yulOptimizerTests/fullSuite/switch_inline_match_default.yul index 6710f1fee..cff8bd755 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/switch_inline_match_default.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/switch_inline_match_default.yul @@ -7,7 +7,7 @@ default { y := 10 } } } -// ==== -// step: fullSuite // ---- +// step: fullSuite +// // { { mstore(10, 0) } } diff --git a/test/libyul/yulOptimizerTests/functionGrouper/already_grouped.yul b/test/libyul/yulOptimizerTests/functionGrouper/already_grouped.yul index 95117c38e..b75efc54c 100644 --- a/test/libyul/yulOptimizerTests/functionGrouper/already_grouped.yul +++ b/test/libyul/yulOptimizerTests/functionGrouper/already_grouped.yul @@ -4,9 +4,9 @@ } function f() -> y { y := 8 } } -// ==== -// step: functionGrouper // ---- +// step: functionGrouper +// // { // { let x := 2 } // function f() -> y diff --git a/test/libyul/yulOptimizerTests/functionGrouper/empty_block.yul b/test/libyul/yulOptimizerTests/functionGrouper/empty_block.yul index f08de996b..7bfbb3401 100644 --- a/test/libyul/yulOptimizerTests/functionGrouper/empty_block.yul +++ b/test/libyul/yulOptimizerTests/functionGrouper/empty_block.yul @@ -1,8 +1,9 @@ { let a:u256 { } function f() -> x:bool { let b:u256 := 4:u256 {} for {} f() {} {} } } // ==== // dialect: yul -// step: functionGrouper // ---- +// step: functionGrouper +// // { // { // let a diff --git a/test/libyul/yulOptimizerTests/functionGrouper/grouped_but_not_ordered.yul b/test/libyul/yulOptimizerTests/functionGrouper/grouped_but_not_ordered.yul index 4ad0c872d..2e5380d2c 100644 --- a/test/libyul/yulOptimizerTests/functionGrouper/grouped_but_not_ordered.yul +++ b/test/libyul/yulOptimizerTests/functionGrouper/grouped_but_not_ordered.yul @@ -4,9 +4,9 @@ let x := 2 } } -// ==== -// step: functionGrouper // ---- +// step: functionGrouper +// // { // { { let x := 2 } } // function f() -> y diff --git a/test/libyul/yulOptimizerTests/functionGrouper/multi_fun_mixed.yul b/test/libyul/yulOptimizerTests/functionGrouper/multi_fun_mixed.yul index 5fb398ad7..1aedecf6a 100644 --- a/test/libyul/yulOptimizerTests/functionGrouper/multi_fun_mixed.yul +++ b/test/libyul/yulOptimizerTests/functionGrouper/multi_fun_mixed.yul @@ -6,8 +6,9 @@ } // ==== // dialect: yul -// step: functionGrouper // ---- +// step: functionGrouper +// // { // { // let a diff --git a/test/libyul/yulOptimizerTests/functionGrouper/nested_fun.yul b/test/libyul/yulOptimizerTests/functionGrouper/nested_fun.yul index 455da2ef5..9193da739 100644 --- a/test/libyul/yulOptimizerTests/functionGrouper/nested_fun.yul +++ b/test/libyul/yulOptimizerTests/functionGrouper/nested_fun.yul @@ -10,8 +10,9 @@ } // ==== // dialect: yul -// step: functionGrouper // ---- +// step: functionGrouper +// // { // { let a } // function f() diff --git a/test/libyul/yulOptimizerTests/functionGrouper/single_fun.yul b/test/libyul/yulOptimizerTests/functionGrouper/single_fun.yul index f7836b6c6..b007f1855 100644 --- a/test/libyul/yulOptimizerTests/functionGrouper/single_fun.yul +++ b/test/libyul/yulOptimizerTests/functionGrouper/single_fun.yul @@ -3,8 +3,9 @@ } // ==== // dialect: yul -// step: functionGrouper // ---- +// step: functionGrouper +// // { // { let a } // function f() diff --git a/test/libyul/yulOptimizerTests/functionGrouper/smoke.yul b/test/libyul/yulOptimizerTests/functionGrouper/smoke.yul index 00895bf38..e292340f2 100644 --- a/test/libyul/yulOptimizerTests/functionGrouper/smoke.yul +++ b/test/libyul/yulOptimizerTests/functionGrouper/smoke.yul @@ -1,5 +1,5 @@ { } -// ==== -// step: functionGrouper // ---- +// step: functionGrouper +// // { { } } diff --git a/test/libyul/yulOptimizerTests/functionHoister/empty_block.yul b/test/libyul/yulOptimizerTests/functionHoister/empty_block.yul index 276fd4b02..bd66b3a2b 100644 --- a/test/libyul/yulOptimizerTests/functionHoister/empty_block.yul +++ b/test/libyul/yulOptimizerTests/functionHoister/empty_block.yul @@ -9,8 +9,9 @@ } // ==== // dialect: yul -// step: functionHoister // ---- +// step: functionHoister +// // { // let a // function f() -> x:bool diff --git a/test/libyul/yulOptimizerTests/functionHoister/multi_mixed.yul b/test/libyul/yulOptimizerTests/functionHoister/multi_mixed.yul index 4e9e9604f..060fab314 100644 --- a/test/libyul/yulOptimizerTests/functionHoister/multi_mixed.yul +++ b/test/libyul/yulOptimizerTests/functionHoister/multi_mixed.yul @@ -7,8 +7,9 @@ } // ==== // dialect: yul -// step: functionHoister // ---- +// step: functionHoister +// // { // let a // let c diff --git a/test/libyul/yulOptimizerTests/functionHoister/nested.yul b/test/libyul/yulOptimizerTests/functionHoister/nested.yul index 89ea5c0ff..05eb4803b 100644 --- a/test/libyul/yulOptimizerTests/functionHoister/nested.yul +++ b/test/libyul/yulOptimizerTests/functionHoister/nested.yul @@ -8,8 +8,9 @@ } // ==== // dialect: yul -// step: functionHoister // ---- +// step: functionHoister +// // { // let a // function g() diff --git a/test/libyul/yulOptimizerTests/functionHoister/single.yul b/test/libyul/yulOptimizerTests/functionHoister/single.yul index 6cc82e68a..205626b57 100644 --- a/test/libyul/yulOptimizerTests/functionHoister/single.yul +++ b/test/libyul/yulOptimizerTests/functionHoister/single.yul @@ -4,8 +4,9 @@ } // ==== // dialect: yul -// step: functionHoister // ---- +// step: functionHoister +// // { // let a // function f() diff --git a/test/libyul/yulOptimizerTests/functionHoister/smoke.yul b/test/libyul/yulOptimizerTests/functionHoister/smoke.yul index 27c9e8419..e0d43adbb 100644 --- a/test/libyul/yulOptimizerTests/functionHoister/smoke.yul +++ b/test/libyul/yulOptimizerTests/functionHoister/smoke.yul @@ -1,6 +1,6 @@ { } -// ==== -// step: functionHoister // ---- +// step: functionHoister +// // { } diff --git a/test/libyul/yulOptimizerTests/loadResolver/loop.yul b/test/libyul/yulOptimizerTests/loadResolver/loop.yul index 4f7b27734..3606891ee 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/loop.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/loop.yul @@ -4,9 +4,9 @@ x := add(x, 1)} {y := add(x, y) } } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // let _1 := 123213 // let _2 := 0 diff --git a/test/libyul/yulOptimizerTests/loadResolver/memory_with_different_kinds_of_invalidation.yul b/test/libyul/yulOptimizerTests/loadResolver/memory_with_different_kinds_of_invalidation.yul index a9487afa7..77fc5aef0 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/memory_with_different_kinds_of_invalidation.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/memory_with_different_kinds_of_invalidation.yul @@ -14,9 +14,9 @@ function g() {} } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // let _1 := 9 // let _2 := 2 diff --git a/test/libyul/yulOptimizerTests/loadResolver/memory_with_msize.yul b/test/libyul/yulOptimizerTests/loadResolver/memory_with_msize.yul index 17a8761d9..199fb1f6c 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/memory_with_msize.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/memory_with_msize.yul @@ -5,9 +5,9 @@ let q := mload(calldataload(0)) sstore(t, q) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // let _1 := msize() // let _3 := calldataload(0) diff --git a/test/libyul/yulOptimizerTests/loadResolver/merge_known_write.yul b/test/libyul/yulOptimizerTests/loadResolver/merge_known_write.yul index 7f5dfb2f0..e9ced5f4c 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/merge_known_write.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/merge_known_write.yul @@ -7,9 +7,9 @@ let q := mload(calldataload(0)) sstore(t, q) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // let _2 := calldataload(10) // let _3 := 0 diff --git a/test/libyul/yulOptimizerTests/loadResolver/merge_known_write_with_distance.yul b/test/libyul/yulOptimizerTests/loadResolver/merge_known_write_with_distance.yul index f7cfdd7c3..8ce9fba00 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/merge_known_write_with_distance.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/merge_known_write_with_distance.yul @@ -7,9 +7,9 @@ let q := mload(calldataload(0)) sstore(t, q) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // let _2 := calldataload(10) // let _4 := calldataload(0) diff --git a/test/libyul/yulOptimizerTests/loadResolver/merge_unknown_write.yul b/test/libyul/yulOptimizerTests/loadResolver/merge_unknown_write.yul index 4fc21bbf5..225e0f627 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/merge_unknown_write.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/merge_unknown_write.yul @@ -7,9 +7,9 @@ let q := mload(calldataload(0)) sstore(t, q) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // let _2 := calldataload(10) // let _3 := 0 diff --git a/test/libyul/yulOptimizerTests/loadResolver/merge_with_rewrite.yul b/test/libyul/yulOptimizerTests/loadResolver/merge_with_rewrite.yul index ebe65992a..b4b113e81 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/merge_with_rewrite.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/merge_with_rewrite.yul @@ -7,9 +7,9 @@ } sstore(0, mload(2)) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // let _1 := 3 // let _2 := 2 diff --git a/test/libyul/yulOptimizerTests/loadResolver/mload_in_function.yul b/test/libyul/yulOptimizerTests/loadResolver/mload_in_function.yul index 9bb8261dd..5e5c06553 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/mload_in_function.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/mload_in_function.yul @@ -6,9 +6,9 @@ foo(42) sstore(0, mload(0)) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // function foo(x) // { diff --git a/test/libyul/yulOptimizerTests/loadResolver/mstore_in_function_loop_body.yul b/test/libyul/yulOptimizerTests/loadResolver/mstore_in_function_loop_body.yul index 2de873942..da910bace 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/mstore_in_function_loop_body.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/mstore_in_function_loop_body.yul @@ -11,9 +11,9 @@ funcWithLoop(42) sstore(0, mload(0)) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // function userNot(x) -> y // { y := iszero(x) } diff --git a/test/libyul/yulOptimizerTests/loadResolver/mstore_in_function_loop_init.yul b/test/libyul/yulOptimizerTests/loadResolver/mstore_in_function_loop_init.yul index 1e06cf8df..efef507dc 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/mstore_in_function_loop_init.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/mstore_in_function_loop_init.yul @@ -11,9 +11,9 @@ funcWithLoop(42) sstore(0, mload(0)) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // function userNot(x) -> y // { y := iszero(x) } diff --git a/test/libyul/yulOptimizerTests/loadResolver/re_store_memory.yul b/test/libyul/yulOptimizerTests/loadResolver/re_store_memory.yul index 7fb27c996..01e29b705 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/re_store_memory.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/re_store_memory.yul @@ -7,9 +7,9 @@ mstore(a, c) sstore(10, mload(a)) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // let a := 0 // let b := 1 diff --git a/test/libyul/yulOptimizerTests/loadResolver/re_store_storage.yul b/test/libyul/yulOptimizerTests/loadResolver/re_store_storage.yul index aed91e002..8c33e4f5d 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/re_store_storage.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/re_store_storage.yul @@ -7,9 +7,9 @@ sstore(a, c) mstore(32, sload(a)) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // let a := 0 // let b := 1 diff --git a/test/libyul/yulOptimizerTests/loadResolver/reassign.yul b/test/libyul/yulOptimizerTests/loadResolver/reassign.yul index fe7fccfe6..4687422e9 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/reassign.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/reassign.yul @@ -4,9 +4,9 @@ a := calldataload(2) mstore(0, sload(a)) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // let _1 := 0 // let a := calldataload(_1) diff --git a/test/libyul/yulOptimizerTests/loadResolver/reassign_value_expression.yul b/test/libyul/yulOptimizerTests/loadResolver/reassign_value_expression.yul index d2d0999fa..1b73cecb9 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/reassign_value_expression.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/reassign_value_expression.yul @@ -14,9 +14,9 @@ a := 39 mstore(sload(a), 11) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // let x := calldataload(1) // let a := add(x, 10) diff --git a/test/libyul/yulOptimizerTests/loadResolver/second_mstore_with_delta.yul b/test/libyul/yulOptimizerTests/loadResolver/second_mstore_with_delta.yul index ae23c1b8b..1aa05106c 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/second_mstore_with_delta.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/second_mstore_with_delta.yul @@ -9,9 +9,9 @@ mstore(b, 8) sstore(mload(a), mload(b)) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // let x := calldataload(1) // let a := add(x, 10) diff --git a/test/libyul/yulOptimizerTests/loadResolver/second_store.yul b/test/libyul/yulOptimizerTests/loadResolver/second_store.yul index 67aa196f4..f6f8250ce 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/second_store.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/second_store.yul @@ -6,9 +6,9 @@ // if the two slots are different. mstore(0, sload(x)) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // let x := calldataload(1) // sstore(x, 7) diff --git a/test/libyul/yulOptimizerTests/loadResolver/second_store_same_value.yul b/test/libyul/yulOptimizerTests/loadResolver/second_store_same_value.yul index b90b177b3..a5cb459ad 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/second_store_same_value.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/second_store_same_value.yul @@ -6,9 +6,9 @@ // written are 7. mstore(0, sload(x)) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // let x := calldataload(1) // let _2 := 7 diff --git a/test/libyul/yulOptimizerTests/loadResolver/second_store_with_delta.yul b/test/libyul/yulOptimizerTests/loadResolver/second_store_with_delta.yul index a4154ce63..c2e669b7f 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/second_store_with_delta.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/second_store_with_delta.yul @@ -9,9 +9,9 @@ sstore(b, 8) mstore(sload(a), sload(b)) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // let x := calldataload(1) // let a := add(x, 10) diff --git a/test/libyul/yulOptimizerTests/loadResolver/side_effects_of_user_functions.yul b/test/libyul/yulOptimizerTests/loadResolver/side_effects_of_user_functions.yul index b07883c3a..ec9eec6c9 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/side_effects_of_user_functions.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/side_effects_of_user_functions.yul @@ -8,9 +8,9 @@ stores() sstore(0, mload(2)) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // function stores() // { mstore(0, 1) } diff --git a/test/libyul/yulOptimizerTests/loadResolver/simple.yul b/test/libyul/yulOptimizerTests/loadResolver/simple.yul index a32a54241..a645f1692 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/simple.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/simple.yul @@ -4,9 +4,9 @@ let q := sload(calldataload(0)) mstore(t, q) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // let _2 := calldataload(10) // sstore(calldataload(0), _2) diff --git a/test/libyul/yulOptimizerTests/loadResolver/simple_memory.yul b/test/libyul/yulOptimizerTests/loadResolver/simple_memory.yul index a4c06ebdc..667abe053 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/simple_memory.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/simple_memory.yul @@ -4,9 +4,9 @@ let q := mload(calldataload(0)) sstore(t, q) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // let _2 := calldataload(10) // mstore(calldataload(0), _2) diff --git a/test/libyul/yulOptimizerTests/loadResolver/staticcall.yul b/test/libyul/yulOptimizerTests/loadResolver/staticcall.yul index 75307ad5d..b24ab0170 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/staticcall.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/staticcall.yul @@ -10,9 +10,10 @@ mstore(0, sload(a)) } // ==== -// step: loadResolver // EVMVersion: >=byzantium // ---- +// step: loadResolver +// // { // let a := 0 // let b := 1 diff --git a/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/dependOnVarInLoop.yul b/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/dependOnVarInLoop.yul index 82ea2bf78..a1b58ceb2 100644 --- a/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/dependOnVarInLoop.yul +++ b/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/dependOnVarInLoop.yul @@ -7,9 +7,9 @@ mstore(a, not_inv) } } -// ==== -// step: loopInvariantCodeMotion // ---- +// step: loopInvariantCodeMotion +// // { // let b := 1 // let a := 1 diff --git a/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/multi.yul b/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/multi.yul index c7e39cc70..19a85c813 100644 --- a/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/multi.yul +++ b/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/multi.yul @@ -9,9 +9,9 @@ mstore(a, inv) } } -// ==== -// step: loopInvariantCodeMotion // ---- +// step: loopInvariantCodeMotion +// // { // let b := 1 // let a := 1 diff --git a/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/no_move_loop.yul b/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/no_move_loop.yul index 7f842bbdd..19e681d6b 100644 --- a/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/no_move_loop.yul +++ b/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/no_move_loop.yul @@ -8,9 +8,9 @@ let q := g() } } -// ==== -// step: loopInvariantCodeMotion // ---- +// step: loopInvariantCodeMotion +// // { // function f() -> x // { x := g() } diff --git a/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/no_move_recursive_function.yul b/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/no_move_recursive_function.yul index 5f3eeb7ac..2bb86008e 100644 --- a/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/no_move_recursive_function.yul +++ b/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/no_move_recursive_function.yul @@ -8,9 +8,9 @@ let q := g() } } -// ==== -// step: loopInvariantCodeMotion // ---- +// step: loopInvariantCodeMotion +// // { // function f() -> x // { x := g() } diff --git a/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/non-ssavar.yul b/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/non-ssavar.yul index 86cf1274e..18feab0c1 100644 --- a/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/non-ssavar.yul +++ b/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/non-ssavar.yul @@ -7,9 +7,9 @@ mstore(a, not_inv) } } -// ==== -// step: loopInvariantCodeMotion // ---- +// step: loopInvariantCodeMotion +// // { // let b := 1 // let a := 1 diff --git a/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/nonMovable.yul b/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/nonMovable.yul index 787c1756b..15fe39ccd 100644 --- a/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/nonMovable.yul +++ b/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/nonMovable.yul @@ -6,9 +6,9 @@ mstore(a, inv) } } -// ==== -// step: loopInvariantCodeMotion // ---- +// step: loopInvariantCodeMotion +// // { // let b := 0 // let a := 1 diff --git a/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/recursive.yul b/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/recursive.yul index a489b134b..5fdabc7cb 100644 --- a/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/recursive.yul +++ b/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/recursive.yul @@ -8,9 +8,9 @@ a := add(a, 1) } } -// ==== -// step: loopInvariantCodeMotion // ---- +// step: loopInvariantCodeMotion +// // { // let b := 1 // let a := 1 diff --git a/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/simple.yul b/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/simple.yul index 970fec59f..b0527e2b6 100644 --- a/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/simple.yul +++ b/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/simple.yul @@ -6,9 +6,9 @@ mstore(a, inv) } } -// ==== -// step: loopInvariantCodeMotion // ---- +// step: loopInvariantCodeMotion +// // { // let b := 1 // let a := 1 diff --git a/test/libyul/yulOptimizerTests/mainFunction/empty_block.yul b/test/libyul/yulOptimizerTests/mainFunction/empty_block.yul index 741efd42b..635e618d5 100644 --- a/test/libyul/yulOptimizerTests/mainFunction/empty_block.yul +++ b/test/libyul/yulOptimizerTests/mainFunction/empty_block.yul @@ -9,8 +9,9 @@ } // ==== // dialect: yul -// step: mainFunction // ---- +// step: mainFunction +// // { // function main() // { diff --git a/test/libyul/yulOptimizerTests/mainFunction/multi_fun_mixed.yul b/test/libyul/yulOptimizerTests/mainFunction/multi_fun_mixed.yul index 69fb0bef0..1d14937e7 100644 --- a/test/libyul/yulOptimizerTests/mainFunction/multi_fun_mixed.yul +++ b/test/libyul/yulOptimizerTests/mainFunction/multi_fun_mixed.yul @@ -7,8 +7,9 @@ } // ==== // dialect: yul -// step: mainFunction // ---- +// step: mainFunction +// // { // function main() // { diff --git a/test/libyul/yulOptimizerTests/mainFunction/nested_fun.yul b/test/libyul/yulOptimizerTests/mainFunction/nested_fun.yul index b97bb2f4d..a888970e7 100644 --- a/test/libyul/yulOptimizerTests/mainFunction/nested_fun.yul +++ b/test/libyul/yulOptimizerTests/mainFunction/nested_fun.yul @@ -8,8 +8,9 @@ } // ==== // dialect: yul -// step: mainFunction // ---- +// step: mainFunction +// // { // function main() // { let a } diff --git a/test/libyul/yulOptimizerTests/mainFunction/single_fun.yul b/test/libyul/yulOptimizerTests/mainFunction/single_fun.yul index 1ab108f6b..6b20d712c 100644 --- a/test/libyul/yulOptimizerTests/mainFunction/single_fun.yul +++ b/test/libyul/yulOptimizerTests/mainFunction/single_fun.yul @@ -4,8 +4,9 @@ } // ==== // dialect: yul -// step: mainFunction // ---- +// step: mainFunction +// // { // function main() // { let a } diff --git a/test/libyul/yulOptimizerTests/mainFunction/smoke.yul b/test/libyul/yulOptimizerTests/mainFunction/smoke.yul index 54ad2d843..5bad02dfb 100644 --- a/test/libyul/yulOptimizerTests/mainFunction/smoke.yul +++ b/test/libyul/yulOptimizerTests/mainFunction/smoke.yul @@ -1,8 +1,9 @@ {} // ==== -// step: mainFunction // dialect: yul // ---- +// step: mainFunction +// // { // function main() // { } diff --git a/test/libyul/yulOptimizerTests/nameDisplacer/funtion_call.yul b/test/libyul/yulOptimizerTests/nameDisplacer/funtion_call.yul index 9c547d17a..54045ce37 100644 --- a/test/libyul/yulOptimizerTests/nameDisplacer/funtion_call.yul +++ b/test/libyul/yulOptimizerTests/nameDisplacer/funtion_call.yul @@ -6,9 +6,9 @@ function illegal5(illegal1, illegal2) -> illegal3 { illegal3 := add(illegal1, illegal2) } } } -// ==== -// step: nameDisplacer // ---- +// step: nameDisplacer +// // { // let x := illegal4_1(1, 2) // function illegal4_1(illegal1_2, illegal2_3) -> illegal3_4 diff --git a/test/libyul/yulOptimizerTests/nameDisplacer/variables.yul b/test/libyul/yulOptimizerTests/nameDisplacer/variables.yul index dae343217..08b7bc431 100644 --- a/test/libyul/yulOptimizerTests/nameDisplacer/variables.yul +++ b/test/libyul/yulOptimizerTests/nameDisplacer/variables.yul @@ -1,7 +1,7 @@ { { let illegal1 := 1 } { let illegal2 := 2 let illegal3, illegal4 } } -// ==== -// step: nameDisplacer // ---- +// step: nameDisplacer +// // { // { let illegal1_1 := 1 } // { diff --git a/test/libyul/yulOptimizerTests/nameDisplacer/variables_inside_functions.yul b/test/libyul/yulOptimizerTests/nameDisplacer/variables_inside_functions.yul index 73228739a..472aa6a33 100644 --- a/test/libyul/yulOptimizerTests/nameDisplacer/variables_inside_functions.yul +++ b/test/libyul/yulOptimizerTests/nameDisplacer/variables_inside_functions.yul @@ -4,9 +4,9 @@ illegal3 := add(illegal1, illegal2) } } -// ==== -// step: nameDisplacer // ---- +// step: nameDisplacer +// // { // function f(illegal1_1, illegal2_2) -> illegal3_3 // { diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for.yul index a7280364f..314963368 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for.yul @@ -7,9 +7,9 @@ a := 7 } } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let a := 2 // a := 3 diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_branch.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_branch.yul index 6b15425c9..120b43ce8 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_branch.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_branch.yul @@ -13,9 +13,9 @@ y := 8 mstore(x, 0) } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let x // let y diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_break.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_break.yul index 647de0d24..1b795ad8c 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_break.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_break.yul @@ -12,9 +12,9 @@ } mstore(x, 0x42) } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let x // x := 1 diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_continue.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_continue.yul index 3ac614b67..0ee9c551d 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_continue.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_continue.yul @@ -15,9 +15,9 @@ } x := 3 } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let x // for { } calldataload(0) { } diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_continue_2.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_continue_2.yul index ab7ba0df1..ee747ae5d 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_continue_2.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_continue_2.yul @@ -12,9 +12,9 @@ } mstore(x, 0x42) } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let x // x := 1 diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_continue_3.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_continue_3.yul index 14faa2a75..b70f35d2b 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_continue_3.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_continue_3.yul @@ -11,9 +11,9 @@ x := 3 } } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let x // for { } calldataload(0) { mstore(x, 0x42) } diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_decl_inside_break_continue.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_decl_inside_break_continue.yul index 87104647d..f54b21af8 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_decl_inside_break_continue.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_decl_inside_break_continue.yul @@ -18,9 +18,9 @@ } mstore(x, 0x42) } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let x := 1 // for { } calldataload(0) { } diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_deep_noremove.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_deep_noremove.yul index 96571f435..5edd71d58 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_deep_noremove.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_deep_noremove.yul @@ -25,9 +25,9 @@ } x := 13 } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let x := 1 // let y := 2 diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_deep_simple.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_deep_simple.yul index 6df6e33ef..5b086bab8 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_deep_simple.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_deep_simple.yul @@ -18,9 +18,9 @@ } } } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // for { } 1 { } // { diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_multi_break.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_multi_break.yul index 5b0e70f8c..ce084b1ce 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_multi_break.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_multi_break.yul @@ -34,9 +34,9 @@ } mstore(x, 0x42) } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let x := 1 // let y := 1 diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_nested.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_nested.yul index 7e9518f89..a83f53666 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_nested.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_nested.yul @@ -31,9 +31,9 @@ } mstore(x, 0x42) } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let x := 1 // let y := 1 diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_rerun.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_rerun.yul index 3cf202582..5d1e60738 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_rerun.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_rerun.yul @@ -10,9 +10,9 @@ } x := 3 } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let x // x := 1 diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_stmnts_after_break_continue.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_stmnts_after_break_continue.yul index eceba8c23..5e88df968 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_stmnts_after_break_continue.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_stmnts_after_break_continue.yul @@ -22,9 +22,9 @@ } mstore(x, 0x42) } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let x := 1 // let y := 1 diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/function.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/function.yul index 444f73265..2a20ca8b6 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/function.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/function.yul @@ -11,9 +11,9 @@ } r := 2 } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let r // function f(x, y) -> a, b diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/if.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/if.yul index 35b6c968f..2fab04a36 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/if.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/if.yul @@ -9,9 +9,9 @@ // This enforces that none of the assignments above can be removed. mstore(0, d) } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let c // let d diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/if_overwrite_all_branches.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/if_overwrite_all_branches.yul index 120c3e07b..7585f848a 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/if_overwrite_all_branches.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/if_overwrite_all_branches.yul @@ -10,9 +10,9 @@ d := 3 mstore(0, d) } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let c // let d diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/if_used_in_one_branch.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/if_used_in_one_branch.yul index 9fadcbbe9..637a32c02 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/if_used_in_one_branch.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/if_used_in_one_branch.yul @@ -10,9 +10,9 @@ d := 3 mstore(0, d) } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let c // let d diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/leave.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/leave.yul index ef68155ad..1caee198a 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/leave.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/leave.yul @@ -20,9 +20,9 @@ t := 8 } } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // function f(a, b) -> x // { diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/multi_assign.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/multi_assign.yul index b4546aa55..f0845680f 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/multi_assign.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/multi_assign.yul @@ -8,9 +8,9 @@ x := 3 y := 4 } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // function f() -> a, b // { } diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/multivar.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/multivar.yul index b094f25b7..2b13ba3c3 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/multivar.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/multivar.yul @@ -5,9 +5,9 @@ b := a a := b } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let a := 2 // a := 7 diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/non_movable.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/non_movable.yul index a5e697555..343c672de 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/non_movable.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/non_movable.yul @@ -3,9 +3,9 @@ a := 0 a := mload(0) } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let a // a := mload(0) diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/remove_break.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/remove_break.yul index 8e75d82ed..035f66d38 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/remove_break.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/remove_break.yul @@ -11,9 +11,9 @@ mstore(0, x) } } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let i := 0 // for { } lt(i, 2) { i := add(i, 1) } diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/remove_continue.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/remove_continue.yul index f5a29382b..c4f3b3e43 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/remove_continue.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/remove_continue.yul @@ -12,9 +12,9 @@ } } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let i := 0 // for { } lt(i, 2) { i := add(i, 1) } diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/scopes.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/scopes.yul index 85c83bde8..d3c6cb4a6 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/scopes.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/scopes.yul @@ -6,9 +6,9 @@ a := 2 } } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let a // { let b } diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/simple.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/simple.yul index 1fd827ed1..12b9ae6b7 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/simple.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/simple.yul @@ -3,7 +3,7 @@ a := 1 a := 2 } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { let a } diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_overwrite_in_all.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_overwrite_in_all.yul index 547ae025b..a39cdedd7 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_overwrite_in_all.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_overwrite_in_all.yul @@ -7,9 +7,9 @@ default { x := 3 } mstore(x, 0) } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let x // switch calldataload(0) diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_overwrite_in_one.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_overwrite_in_one.yul index 7ab2036e1..271bb4864 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_overwrite_in_one.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_overwrite_in_one.yul @@ -6,9 +6,9 @@ case 0 { x := 2 } mstore(x, 0) } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let x // x := 1 diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_overwrite_use_combination.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_overwrite_use_combination.yul index 8dc43d721..8d38dcc16 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_overwrite_use_combination.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_overwrite_use_combination.yul @@ -7,9 +7,9 @@ default { mstore(x, 1) } mstore(x, 0) } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let x // x := 1 diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_unused.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_unused.yul index f0b29f301..94de51b88 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_unused.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_unused.yul @@ -5,9 +5,9 @@ switch calldataload(0) case 0 { mstore(0, 1) } } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let x // switch calldataload(0) diff --git a/test/libyul/yulOptimizerTests/rematerialiser/branches_for1.yul b/test/libyul/yulOptimizerTests/rematerialiser/branches_for1.yul index 520c87b92..39a7f91b3 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/branches_for1.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/branches_for1.yul @@ -5,9 +5,9 @@ pop(a) } } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let a := caller() // pop(caller()) diff --git a/test/libyul/yulOptimizerTests/rematerialiser/branches_for2.yul b/test/libyul/yulOptimizerTests/rematerialiser/branches_for2.yul index 4dd86f958..59731d617 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/branches_for2.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/branches_for2.yul @@ -7,9 +7,9 @@ } let x := a } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let a := caller() // pop(caller()) diff --git a/test/libyul/yulOptimizerTests/rematerialiser/branches_if.yul b/test/libyul/yulOptimizerTests/rematerialiser/branches_if.yul index e664291f5..0a1e38fa6 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/branches_if.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/branches_if.yul @@ -4,9 +4,9 @@ if b { pop(b) b := a } let c := b } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let a := caller() // let b := address() diff --git a/test/libyul/yulOptimizerTests/rematerialiser/branches_switch.yul b/test/libyul/yulOptimizerTests/rematerialiser/branches_switch.yul index e0aa0a385..442d64654 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/branches_switch.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/branches_switch.yul @@ -6,9 +6,9 @@ default { let x := a let y := b b := a } pop(add(a, b)) } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let a := 1 // let b := 2 diff --git a/test/libyul/yulOptimizerTests/rematerialiser/cheap_caller.yul b/test/libyul/yulOptimizerTests/rematerialiser/cheap_caller.yul index 95733af88..c3f6ea6a2 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/cheap_caller.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/cheap_caller.yul @@ -6,9 +6,9 @@ mstore(add(a, a), mload(a)) sstore(a, sload(a)) } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let a := caller() // mstore(caller(), caller()) diff --git a/test/libyul/yulOptimizerTests/rematerialiser/do_not_move_out_of_scope.yul b/test/libyul/yulOptimizerTests/rematerialiser/do_not_move_out_of_scope.yul index 074100d89..7fc927a4a 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/do_not_move_out_of_scope.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/do_not_move_out_of_scope.yul @@ -7,9 +7,9 @@ } let b := x } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let x // { diff --git a/test/libyul/yulOptimizerTests/rematerialiser/do_remat_large_amounts_of_code_if_used_once.yul b/test/libyul/yulOptimizerTests/rematerialiser/do_remat_large_amounts_of_code_if_used_once.yul index cc009509f..6221f1160 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/do_remat_large_amounts_of_code_if_used_once.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/do_remat_large_amounts_of_code_if_used_once.yul @@ -2,9 +2,9 @@ let x := add(mul(calldataload(2), calldataload(4)), mul(2, calldatasize())) let b := x } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let x := add(mul(calldataload(2), calldataload(4)), mul(2, calldatasize())) // let b := add(mul(calldataload(2), calldataload(4)), mul(2, calldatasize())) diff --git a/test/libyul/yulOptimizerTests/rematerialiser/for_break.yul b/test/libyul/yulOptimizerTests/rematerialiser/for_break.yul index e39b66b44..272160003 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/for_break.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/for_break.yul @@ -13,9 +13,9 @@ } mstore(a, b) } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let a // let b diff --git a/test/libyul/yulOptimizerTests/rematerialiser/for_continue.yul b/test/libyul/yulOptimizerTests/rematerialiser/for_continue.yul index 5a98c4c4d..ed80715e9 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/for_continue.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/for_continue.yul @@ -15,9 +15,9 @@ } mstore(a, b) } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let a // let b diff --git a/test/libyul/yulOptimizerTests/rematerialiser/for_continue_2.yul b/test/libyul/yulOptimizerTests/rematerialiser/for_continue_2.yul index f01514cc5..a5d8198b0 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/for_continue_2.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/for_continue_2.yul @@ -20,9 +20,9 @@ } mstore(a, b) } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let a // let b diff --git a/test/libyul/yulOptimizerTests/rematerialiser/for_continue_with_assignment_in_post.yul b/test/libyul/yulOptimizerTests/rematerialiser/for_continue_with_assignment_in_post.yul index ae04949d9..1b9b3a84a 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/for_continue_with_assignment_in_post.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/for_continue_with_assignment_in_post.yul @@ -23,9 +23,9 @@ let x := b // does not rematerialize as b may be either origin() or callvalue() (btw: not caller()) let y := c // does not rematerialize as c may be either origin() or caller() } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let a // let b diff --git a/test/libyul/yulOptimizerTests/rematerialiser/large_constant.yul b/test/libyul/yulOptimizerTests/rematerialiser/large_constant.yul index 9f57a4739..b00d50f26 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/large_constant.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/large_constant.yul @@ -4,9 +4,9 @@ let a := 0xffffffffffffffffffffff mstore(a, a) } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let a := 0xffffffffffffffffffffff // mstore(a, a) diff --git a/test/libyul/yulOptimizerTests/rematerialiser/large_constant_used_once.yul b/test/libyul/yulOptimizerTests/rematerialiser/large_constant_used_once.yul index 6d388c19e..cc8d23398 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/large_constant_used_once.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/large_constant_used_once.yul @@ -5,9 +5,9 @@ let a := 0xffffffffffffffffffffff mstore(0, a) } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let a := 0xffffffffffffffffffffff // mstore(0, 0xffffffffffffffffffffff) diff --git a/test/libyul/yulOptimizerTests/rematerialiser/many_refs_small_cost_loop.yul b/test/libyul/yulOptimizerTests/rematerialiser/many_refs_small_cost_loop.yul index 0d42afa97..92aacb229 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/many_refs_small_cost_loop.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/many_refs_small_cost_loop.yul @@ -12,9 +12,9 @@ let c := sdiv(x, 4) } } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let x := 0xff // for { } lt(x, 0x100) { } diff --git a/test/libyul/yulOptimizerTests/rematerialiser/medium_sized_constant.yul b/test/libyul/yulOptimizerTests/rematerialiser/medium_sized_constant.yul index ec79843b1..fb73227b7 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/medium_sized_constant.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/medium_sized_constant.yul @@ -12,9 +12,9 @@ mstore(add(a, a), a) mstore(a, mload(a)) } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let b := 2 // mstore(2, 2) diff --git a/test/libyul/yulOptimizerTests/rematerialiser/no_remat_in_loop.yul b/test/libyul/yulOptimizerTests/rematerialiser/no_remat_in_loop.yul index 8fdd1f002..4255445b3 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/no_remat_in_loop.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/no_remat_in_loop.yul @@ -18,9 +18,9 @@ } } } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let a := origin() // let b := calldataload(0) diff --git a/test/libyul/yulOptimizerTests/rematerialiser/non_movable_function.yul b/test/libyul/yulOptimizerTests/rematerialiser/non_movable_function.yul index 1b59fd598..4cffa6a02 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/non_movable_function.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/non_movable_function.yul @@ -5,9 +5,9 @@ let c := a mstore(add(a, b), c) } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // function f(x) -> y // { } diff --git a/test/libyul/yulOptimizerTests/rematerialiser/non_movable_instruction.yul b/test/libyul/yulOptimizerTests/rematerialiser/non_movable_instruction.yul index 0fb885604..dc1d78c74 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/non_movable_instruction.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/non_movable_instruction.yul @@ -4,9 +4,9 @@ let c := a mstore(add(a, b), c) } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let a := 1 // let b := mload(1) diff --git a/test/libyul/yulOptimizerTests/rematerialiser/reassign.yul b/test/libyul/yulOptimizerTests/rematerialiser/reassign.yul index fe3cf5812..ef6e12ab6 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/reassign.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/reassign.yul @@ -6,9 +6,9 @@ let d := add(b, c) pop(a) pop(b) pop(c) pop(d) } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let a := extcodesize(0) // let b := a diff --git a/test/libyul/yulOptimizerTests/rematerialiser/reassignment.yul b/test/libyul/yulOptimizerTests/rematerialiser/reassignment.yul index c10f9ddf2..7af26af63 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/reassignment.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/reassignment.yul @@ -5,9 +5,9 @@ let b := mload(a) pop(b) } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let a := 1 // pop(1) diff --git a/test/libyul/yulOptimizerTests/rematerialiser/smoke.yul b/test/libyul/yulOptimizerTests/rematerialiser/smoke.yul index e0452c4b8..e7c28202c 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/smoke.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/smoke.yul @@ -1,5 +1,5 @@ {} -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { } diff --git a/test/libyul/yulOptimizerTests/rematerialiser/some_refs_small_cost_loop.yul b/test/libyul/yulOptimizerTests/rematerialiser/some_refs_small_cost_loop.yul index 0eeb248a6..071c3c463 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/some_refs_small_cost_loop.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/some_refs_small_cost_loop.yul @@ -7,9 +7,9 @@ let y := add(x, 1) } } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let x := 0xff // for { } lt(x, 0x100) { } diff --git a/test/libyul/yulOptimizerTests/rematerialiser/some_refs_small_cost_nested_loop.yul b/test/libyul/yulOptimizerTests/rematerialiser/some_refs_small_cost_nested_loop.yul index c95cf5454..3d4d65f0a 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/some_refs_small_cost_nested_loop.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/some_refs_small_cost_nested_loop.yul @@ -12,9 +12,9 @@ } } } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let x := 0xff // for { } lt(x, 0x100) { } diff --git a/test/libyul/yulOptimizerTests/rematerialiser/trivial.yul b/test/libyul/yulOptimizerTests/rematerialiser/trivial.yul index 35d4f0332..04a797e20 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/trivial.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/trivial.yul @@ -3,9 +3,9 @@ let b := a mstore(0, b) } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let a := 1 // let b := 1 diff --git a/test/libyul/yulOptimizerTests/rematerialiser/update_asignment_remat.yul b/test/libyul/yulOptimizerTests/rematerialiser/update_asignment_remat.yul index 076131cde..bb5f02980 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/update_asignment_remat.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/update_asignment_remat.yul @@ -4,9 +4,9 @@ a := mul(a, 2) let b := a } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let a := extcodesize(0) // a := mul(a, 2) diff --git a/test/libyul/yulOptimizerTests/splitJoin/control_flow.yul b/test/libyul/yulOptimizerTests/splitJoin/control_flow.yul index 7e60a54be..c8b22424c 100644 --- a/test/libyul/yulOptimizerTests/splitJoin/control_flow.yul +++ b/test/libyul/yulOptimizerTests/splitJoin/control_flow.yul @@ -6,9 +6,9 @@ } } } -// ==== -// step: splitJoin // ---- +// step: splitJoin +// // { // if mul(add(calldataload(0), 2), 3) // { diff --git a/test/libyul/yulOptimizerTests/splitJoin/functions.yul b/test/libyul/yulOptimizerTests/splitJoin/functions.yul index b4ad9ed8e..e2f554dd0 100644 --- a/test/libyul/yulOptimizerTests/splitJoin/functions.yul +++ b/test/libyul/yulOptimizerTests/splitJoin/functions.yul @@ -8,9 +8,9 @@ sstore(b, mul(b, 2)) } } -// ==== -// step: splitJoin // ---- +// step: splitJoin +// // { // let x := f(0) // function f(y) -> r diff --git a/test/libyul/yulOptimizerTests/splitJoin/smoke.yul b/test/libyul/yulOptimizerTests/splitJoin/smoke.yul index d59bd5644..4aac31ddb 100644 --- a/test/libyul/yulOptimizerTests/splitJoin/smoke.yul +++ b/test/libyul/yulOptimizerTests/splitJoin/smoke.yul @@ -1,5 +1,5 @@ {} -// ==== -// step: splitJoin // ---- +// step: splitJoin +// // { } diff --git a/test/libyul/yulOptimizerTests/ssaAndBack/for_loop.yul b/test/libyul/yulOptimizerTests/ssaAndBack/for_loop.yul index e4787540d..43b9ade6a 100644 --- a/test/libyul/yulOptimizerTests/ssaAndBack/for_loop.yul +++ b/test/libyul/yulOptimizerTests/ssaAndBack/for_loop.yul @@ -15,9 +15,9 @@ b := mload(a) } } -// ==== -// step: ssaAndBack // ---- +// step: ssaAndBack +// // { // let a := mload(0) // let b := mload(1) diff --git a/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign.yul b/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign.yul index 0617c47e4..2e818561c 100644 --- a/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign.yul +++ b/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign.yul @@ -6,9 +6,9 @@ a := mload(4) mstore(a, 0) } -// ==== -// step: ssaAndBack // ---- +// step: ssaAndBack +// // { // let a_5 := mload(4) // mstore(a_5, 0) diff --git a/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign_if.yul b/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign_if.yul index 73aee8516..4815349d7 100644 --- a/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign_if.yul +++ b/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign_if.yul @@ -8,9 +8,9 @@ } mstore(a, 0) } -// ==== -// step: ssaAndBack // ---- +// step: ssaAndBack +// // { // let a := mload(0) // if mload(1) { a := mload(3) } diff --git a/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign_multi_var_if.yul b/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign_multi_var_if.yul index b6eb0b6cf..a0821ab37 100644 --- a/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign_multi_var_if.yul +++ b/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign_multi_var_if.yul @@ -9,9 +9,9 @@ } mstore(a, b) } -// ==== -// step: ssaAndBack // ---- +// step: ssaAndBack +// // { // let a := mload(0) // let b := mload(1) diff --git a/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign_multi_var_switch.yul b/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign_multi_var_switch.yul index e747e8503..92a0ba825 100644 --- a/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign_multi_var_switch.yul +++ b/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign_multi_var_switch.yul @@ -16,9 +16,9 @@ } mstore(a, b) } -// ==== -// step: ssaAndBack // ---- +// step: ssaAndBack +// // { // let a := mload(0) // let b := mload(1) diff --git a/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign_switch.yul b/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign_switch.yul index 8265f500e..63c4f8561 100644 --- a/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign_switch.yul +++ b/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign_switch.yul @@ -13,9 +13,9 @@ } mstore(a, 0) } -// ==== -// step: ssaAndBack // ---- +// step: ssaAndBack +// // { // let a := mload(0) // switch mload(1) diff --git a/test/libyul/yulOptimizerTests/ssaAndBack/simple.yul b/test/libyul/yulOptimizerTests/ssaAndBack/simple.yul index 15e56f4d6..e2f130507 100644 --- a/test/libyul/yulOptimizerTests/ssaAndBack/simple.yul +++ b/test/libyul/yulOptimizerTests/ssaAndBack/simple.yul @@ -3,9 +3,9 @@ a := mload(1) mstore(a, 0) } -// ==== -// step: ssaAndBack // ---- +// step: ssaAndBack +// // { // let a_2 := mload(1) // mstore(a_2, 0) diff --git a/test/libyul/yulOptimizerTests/ssaAndBack/single_assign_if.yul b/test/libyul/yulOptimizerTests/ssaAndBack/single_assign_if.yul index 0e777a5a5..e2516b45b 100644 --- a/test/libyul/yulOptimizerTests/ssaAndBack/single_assign_if.yul +++ b/test/libyul/yulOptimizerTests/ssaAndBack/single_assign_if.yul @@ -6,9 +6,9 @@ } mstore(a, 0) } -// ==== -// step: ssaAndBack // ---- +// step: ssaAndBack +// // { // let a := mload(0) // if mload(1) { a := mload(1) } diff --git a/test/libyul/yulOptimizerTests/ssaAndBack/single_assign_switch.yul b/test/libyul/yulOptimizerTests/ssaAndBack/single_assign_switch.yul index aacad246a..e6e0553c1 100644 --- a/test/libyul/yulOptimizerTests/ssaAndBack/single_assign_switch.yul +++ b/test/libyul/yulOptimizerTests/ssaAndBack/single_assign_switch.yul @@ -9,9 +9,9 @@ } mstore(a, 0) } -// ==== -// step: ssaAndBack // ---- +// step: ssaAndBack +// // { // let a := mload(0) // switch mload(1) diff --git a/test/libyul/yulOptimizerTests/ssaAndBack/ssaReverse.yul b/test/libyul/yulOptimizerTests/ssaAndBack/ssaReverse.yul index fbb149c68..da8d797b8 100644 --- a/test/libyul/yulOptimizerTests/ssaAndBack/ssaReverse.yul +++ b/test/libyul/yulOptimizerTests/ssaAndBack/ssaReverse.yul @@ -20,9 +20,9 @@ let a,b := abi_decode_t_bytes_calldata_ptr(mload(0),mload(1)) mstore(a,b) } -// ==== -// step: ssaAndBack // ---- +// step: ssaAndBack +// // { // function abi_decode_t_bytes_calldata_ptr(offset_12, end_13) -> arrayPos_14, length_15 // { diff --git a/test/libyul/yulOptimizerTests/ssaAndBack/two_vars.yul b/test/libyul/yulOptimizerTests/ssaAndBack/two_vars.yul index 1c246a754..6053bd9ac 100644 --- a/test/libyul/yulOptimizerTests/ssaAndBack/two_vars.yul +++ b/test/libyul/yulOptimizerTests/ssaAndBack/two_vars.yul @@ -7,9 +7,9 @@ b := mload(a) mstore(a, b) } -// ==== -// step: ssaAndBack // ---- +// step: ssaAndBack +// // { // let a_1 := mload(0) // let b_2 := mload(a_1) diff --git a/test/libyul/yulOptimizerTests/ssaPlusCleanup/control_structures.yul b/test/libyul/yulOptimizerTests/ssaPlusCleanup/control_structures.yul index 28520d3c5..104dc2822 100644 --- a/test/libyul/yulOptimizerTests/ssaPlusCleanup/control_structures.yul +++ b/test/libyul/yulOptimizerTests/ssaPlusCleanup/control_structures.yul @@ -10,9 +10,9 @@ } } } -// ==== -// step: ssaPlusCleanup // ---- +// step: ssaPlusCleanup +// // { // function copy(from, to) -> length // { diff --git a/test/libyul/yulOptimizerTests/ssaPlusCleanup/multi_reassign.yul b/test/libyul/yulOptimizerTests/ssaPlusCleanup/multi_reassign.yul index 105970c3c..85e86e005 100644 --- a/test/libyul/yulOptimizerTests/ssaPlusCleanup/multi_reassign.yul +++ b/test/libyul/yulOptimizerTests/ssaPlusCleanup/multi_reassign.yul @@ -5,9 +5,9 @@ a := 4 mstore(0, a) } -// ==== -// step: ssaPlusCleanup // ---- +// step: ssaPlusCleanup +// // { // let a_1 := 1 // let a := a_1 diff --git a/test/libyul/yulOptimizerTests/ssaPlusCleanup/multi_reassign_with_use.yul b/test/libyul/yulOptimizerTests/ssaPlusCleanup/multi_reassign_with_use.yul index 6770fee2b..75a045d05 100644 --- a/test/libyul/yulOptimizerTests/ssaPlusCleanup/multi_reassign_with_use.yul +++ b/test/libyul/yulOptimizerTests/ssaPlusCleanup/multi_reassign_with_use.yul @@ -5,9 +5,9 @@ a := mload(add(a, 4)) mstore(0, a) } -// ==== -// step: ssaPlusCleanup // ---- +// step: ssaPlusCleanup +// // { // let a_1 := 1 // let a := a_1 diff --git a/test/libyul/yulOptimizerTests/ssaReverser/abi_example.yul b/test/libyul/yulOptimizerTests/ssaReverser/abi_example.yul index 18d404df0..1c79777d2 100644 --- a/test/libyul/yulOptimizerTests/ssaReverser/abi_example.yul +++ b/test/libyul/yulOptimizerTests/ssaReverser/abi_example.yul @@ -19,9 +19,9 @@ } } } -// ==== -// step: ssaReverser // ---- +// step: ssaReverser +// // { // function abi_decode_t_bytes_calldata_ptr(offset_12, end_13) -> arrayPos_14, length_15 // { diff --git a/test/libyul/yulOptimizerTests/ssaReverser/self_assign.yul b/test/libyul/yulOptimizerTests/ssaReverser/self_assign.yul index 48b9d39cf..1985f6c08 100644 --- a/test/libyul/yulOptimizerTests/ssaReverser/self_assign.yul +++ b/test/libyul/yulOptimizerTests/ssaReverser/self_assign.yul @@ -2,7 +2,7 @@ let a := calldataload(0) a := a } -// ==== -// step: ssaReverser // ---- +// step: ssaReverser +// // { let a := calldataload(0) } diff --git a/test/libyul/yulOptimizerTests/ssaReverser/simple.yul b/test/libyul/yulOptimizerTests/ssaReverser/simple.yul index 03dab25f9..be2cfe9d7 100644 --- a/test/libyul/yulOptimizerTests/ssaReverser/simple.yul +++ b/test/libyul/yulOptimizerTests/ssaReverser/simple.yul @@ -4,9 +4,9 @@ a := a_1 mstore(a_1, 0) } -// ==== -// step: ssaReverser // ---- +// step: ssaReverser +// // { // let a := mload(1) // a := mload(0) diff --git a/test/libyul/yulOptimizerTests/ssaTransform/branches.yul b/test/libyul/yulOptimizerTests/ssaTransform/branches.yul index 76a459160..81f82451f 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/branches.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/branches.yul @@ -7,9 +7,9 @@ a := add(a, 1) mstore(a, 1) } -// ==== -// step: ssaTransform // ---- +// step: ssaTransform +// // { // let a_1 := 1 // let a := a_1 diff --git a/test/libyul/yulOptimizerTests/ssaTransform/for_reassign_body.yul b/test/libyul/yulOptimizerTests/ssaTransform/for_reassign_body.yul index 6901f9f17..e1e1c13ba 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/for_reassign_body.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/for_reassign_body.yul @@ -6,9 +6,9 @@ } mstore(0, a) } -// ==== -// step: ssaTransform // ---- +// step: ssaTransform +// // { // let a_1 := mload(0) // let a := a_1 diff --git a/test/libyul/yulOptimizerTests/ssaTransform/for_reassign_init.yul b/test/libyul/yulOptimizerTests/ssaTransform/for_reassign_init.yul index fcf1a4478..284bdbf3d 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/for_reassign_init.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/for_reassign_init.yul @@ -6,9 +6,9 @@ } mstore(0, a) } -// ==== -// step: ssaTransform // ---- +// step: ssaTransform +// // { // let a_1 := mload(0) // let a := a_1 diff --git a/test/libyul/yulOptimizerTests/ssaTransform/for_reassign_post.yul b/test/libyul/yulOptimizerTests/ssaTransform/for_reassign_post.yul index 217a043ad..ac7e426ab 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/for_reassign_post.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/for_reassign_post.yul @@ -6,9 +6,9 @@ } mstore(0, a) } -// ==== -// step: ssaTransform // ---- +// step: ssaTransform +// // { // let a_1 := mload(0) // let a := a_1 diff --git a/test/libyul/yulOptimizerTests/ssaTransform/for_simple.yul b/test/libyul/yulOptimizerTests/ssaTransform/for_simple.yul index cec419633..77ac89a60 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/for_simple.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/for_simple.yul @@ -13,9 +13,9 @@ } a := add(a, 8) } -// ==== -// step: ssaTransform // ---- +// step: ssaTransform +// // { // let a_1 := mload(0) // let a := a_1 diff --git a/test/libyul/yulOptimizerTests/ssaTransform/function.yul b/test/libyul/yulOptimizerTests/ssaTransform/function.yul index b6e120f40..d41c18b04 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/function.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/function.yul @@ -6,9 +6,9 @@ a := add(a, d) } } -// ==== -// step: ssaTransform // ---- +// step: ssaTransform +// // { // function f(a, b) -> c, d // { diff --git a/test/libyul/yulOptimizerTests/ssaTransform/multi_assign.yul b/test/libyul/yulOptimizerTests/ssaTransform/multi_assign.yul index 4f1c44123..ff4a0eb1d 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/multi_assign.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/multi_assign.yul @@ -7,9 +7,9 @@ b := mload(a) function f() -> x, y {} } -// ==== -// step: ssaTransform // ---- +// step: ssaTransform +// // { // let a_1 := mload(0) // let a := a_1 diff --git a/test/libyul/yulOptimizerTests/ssaTransform/multi_decl.yul b/test/libyul/yulOptimizerTests/ssaTransform/multi_decl.yul index ea849ead9..06847711e 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/multi_decl.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/multi_decl.yul @@ -6,9 +6,9 @@ sstore(a, b) function f(t, v) -> w, z {} } -// ==== -// step: ssaTransform // ---- +// step: ssaTransform +// // { // let x_1, y_2 := f(1, 2) // let x := x_1 diff --git a/test/libyul/yulOptimizerTests/ssaTransform/nested.yul b/test/libyul/yulOptimizerTests/ssaTransform/nested.yul index a48de0002..e075f06a2 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/nested.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/nested.yul @@ -10,9 +10,9 @@ } a := add(b, a) } -// ==== -// step: ssaTransform // ---- +// step: ssaTransform +// // { // let a_1 := 1 // let a := a_1 diff --git a/test/libyul/yulOptimizerTests/ssaTransform/nested_reassign.yul b/test/libyul/yulOptimizerTests/ssaTransform/nested_reassign.yul index 7d2d7bc33..32d74f180 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/nested_reassign.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/nested_reassign.yul @@ -11,9 +11,9 @@ // but not above because end of block mstore(0, x) } -// ==== -// step: ssaTransform // ---- +// step: ssaTransform +// // { // let a // let b diff --git a/test/libyul/yulOptimizerTests/ssaTransform/notransform.yul b/test/libyul/yulOptimizerTests/ssaTransform/notransform.yul index f42de9976..b41998c59 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/notransform.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/notransform.yul @@ -6,9 +6,9 @@ mstore(c, 0) c := add(a, b) } -// ==== -// step: ssaTransform // ---- +// step: ssaTransform +// // { // let a := 1 // let b := add(a, 2) diff --git a/test/libyul/yulOptimizerTests/ssaTransform/simple.yul b/test/libyul/yulOptimizerTests/ssaTransform/simple.yul index d23d07d82..b52ec0c05 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/simple.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/simple.yul @@ -4,9 +4,9 @@ a := 3 a := 4 } -// ==== -// step: ssaTransform // ---- +// step: ssaTransform +// // { // let a_1 := 1 // let a := a_1 diff --git a/test/libyul/yulOptimizerTests/ssaTransform/switch.yul b/test/libyul/yulOptimizerTests/ssaTransform/switch.yul index 32d6b339b..8604be0e3 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/switch.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/switch.yul @@ -8,9 +8,9 @@ default { a := add(a, 8) } mstore(0, a) } -// ==== -// step: ssaTransform // ---- +// step: ssaTransform +// // { // let a_1 := mload(0) // let a := a_1 diff --git a/test/libyul/yulOptimizerTests/ssaTransform/switch_reassign.yul b/test/libyul/yulOptimizerTests/ssaTransform/switch_reassign.yul index 775df55f4..3cf38ef38 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/switch_reassign.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/switch_reassign.yul @@ -6,9 +6,9 @@ // should still create an SSA variable for a mstore(0, a) } -// ==== -// step: ssaTransform // ---- +// step: ssaTransform +// // { // let a_1 := mload(0) // let a := a_1 diff --git a/test/libyul/yulOptimizerTests/ssaTransform/typed.yul b/test/libyul/yulOptimizerTests/ssaTransform/typed.yul index f9d48a227..4b1aa1643 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/typed.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/typed.yul @@ -14,8 +14,9 @@ } // ==== // dialect: evmTyped -// step: ssaTransform // ---- +// step: ssaTransform +// // { // let b_1:bool := true // let b:bool := b_1 diff --git a/test/libyul/yulOptimizerTests/ssaTransform/typed_for.yul b/test/libyul/yulOptimizerTests/ssaTransform/typed_for.yul index 685c42a24..596f56cb0 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/typed_for.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/typed_for.yul @@ -8,8 +8,9 @@ } // ==== // dialect: evmTyped -// step: ssaTransform // ---- +// step: ssaTransform +// // { // let b:bool := true // let c_1:bool := false diff --git a/test/libyul/yulOptimizerTests/ssaTransform/typed_switch.yul b/test/libyul/yulOptimizerTests/ssaTransform/typed_switch.yul index 7d61b1031..b87b5dbbc 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/typed_switch.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/typed_switch.yul @@ -8,8 +8,9 @@ } // ==== // dialect: evmTyped -// step: ssaTransform // ---- +// step: ssaTransform +// // { // let b:bool := true // let c_1:bool := false diff --git a/test/libyul/yulOptimizerTests/ssaTransform/used.yul b/test/libyul/yulOptimizerTests/ssaTransform/used.yul index c23bc6ee8..cbd0cdb25 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/used.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/used.yul @@ -14,9 +14,9 @@ a := 4 mstore(a, 0) } -// ==== -// step: ssaTransform // ---- +// step: ssaTransform +// // { // let a_1 := 1 // let a := a_1 diff --git a/test/libyul/yulOptimizerTests/stackCompressor/inlineInBlock.yul b/test/libyul/yulOptimizerTests/stackCompressor/inlineInBlock.yul index 6c0ceef63..4ff056157 100644 --- a/test/libyul/yulOptimizerTests/stackCompressor/inlineInBlock.yul +++ b/test/libyul/yulOptimizerTests/stackCompressor/inlineInBlock.yul @@ -3,9 +3,9 @@ let y := calldataload(calldataload(9)) mstore(y, add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(y, 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1)) } -// ==== -// step: stackCompressor // ---- +// step: stackCompressor +// // { // mstore(calldataload(calldataload(9)), add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(calldataload(calldataload(9)), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1)) // } diff --git a/test/libyul/yulOptimizerTests/stackCompressor/inlineInFunction.yul b/test/libyul/yulOptimizerTests/stackCompressor/inlineInFunction.yul index e74e788aa..f237ea8bb 100644 --- a/test/libyul/yulOptimizerTests/stackCompressor/inlineInFunction.yul +++ b/test/libyul/yulOptimizerTests/stackCompressor/inlineInFunction.yul @@ -5,9 +5,9 @@ mstore(y, add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(y, 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1)) } } -// ==== -// step: stackCompressor // ---- +// step: stackCompressor +// // { // let x := 8 // function f() diff --git a/test/libyul/yulOptimizerTests/stackCompressor/noInline.yul b/test/libyul/yulOptimizerTests/stackCompressor/noInline.yul index 39c46fb96..b5f3dd872 100644 --- a/test/libyul/yulOptimizerTests/stackCompressor/noInline.yul +++ b/test/libyul/yulOptimizerTests/stackCompressor/noInline.yul @@ -2,9 +2,9 @@ let x := 8 function f() { let y := 9 } } -// ==== -// step: stackCompressor // ---- +// step: stackCompressor +// // { // let x := 8 // function f() diff --git a/test/libyul/yulOptimizerTests/stackCompressor/unusedPrunerWithMSize.yul b/test/libyul/yulOptimizerTests/stackCompressor/unusedPrunerWithMSize.yul index f285d6b5e..279c0d901 100644 --- a/test/libyul/yulOptimizerTests/stackCompressor/unusedPrunerWithMSize.yul +++ b/test/libyul/yulOptimizerTests/stackCompressor/unusedPrunerWithMSize.yul @@ -18,9 +18,9 @@ extcodecopy(1, msize(), 1, 1) } } -// ==== -// step: stackCompressor // ---- +// step: stackCompressor +// // { // let _17_72 := pc() // let _22_75 := pc() diff --git a/test/libyul/yulOptimizerTests/structuralSimplifier/bugfix_visit_after_change.yul b/test/libyul/yulOptimizerTests/structuralSimplifier/bugfix_visit_after_change.yul index f180d50ad..94da17faa 100644 --- a/test/libyul/yulOptimizerTests/structuralSimplifier/bugfix_visit_after_change.yul +++ b/test/libyul/yulOptimizerTests/structuralSimplifier/bugfix_visit_after_change.yul @@ -6,7 +6,7 @@ x := 1 } } -// ==== -// step: structuralSimplifier // ---- +// step: structuralSimplifier +// // { let x := 0 } diff --git a/test/libyul/yulOptimizerTests/structuralSimplifier/for_false_condition.sol b/test/libyul/yulOptimizerTests/structuralSimplifier/for_false_condition.yul similarity index 93% rename from test/libyul/yulOptimizerTests/structuralSimplifier/for_false_condition.sol rename to test/libyul/yulOptimizerTests/structuralSimplifier/for_false_condition.yul index 0d352a3f9..edca6b642 100644 --- a/test/libyul/yulOptimizerTests/structuralSimplifier/for_false_condition.sol +++ b/test/libyul/yulOptimizerTests/structuralSimplifier/for_false_condition.yul @@ -3,7 +3,7 @@ let b := a } } -// ==== -// step: structuralSimplifier // ---- +// step: structuralSimplifier +// // { let a := 42 } diff --git a/test/libyul/yulOptimizerTests/structuralSimplifier/if_false_condition.yul b/test/libyul/yulOptimizerTests/structuralSimplifier/if_false_condition.yul index ab08b18e8..3b7a39181 100644 --- a/test/libyul/yulOptimizerTests/structuralSimplifier/if_false_condition.yul +++ b/test/libyul/yulOptimizerTests/structuralSimplifier/if_false_condition.yul @@ -1,5 +1,5 @@ { if 0 { mstore(0, 0) } } -// ==== -// step: structuralSimplifier // ---- +// step: structuralSimplifier +// // { } diff --git a/test/libyul/yulOptimizerTests/structuralSimplifier/if_multi_unassigned_condition.yul b/test/libyul/yulOptimizerTests/structuralSimplifier/if_multi_unassigned_condition.yul index 836b4371c..bbed85bb0 100644 --- a/test/libyul/yulOptimizerTests/structuralSimplifier/if_multi_unassigned_condition.yul +++ b/test/libyul/yulOptimizerTests/structuralSimplifier/if_multi_unassigned_condition.yul @@ -3,7 +3,7 @@ if x { mstore(0, 0) } if y { mstore(0, 0) } } -// ==== -// step: structuralSimplifier // ---- +// step: structuralSimplifier +// // { let x, y } diff --git a/test/libyul/yulOptimizerTests/structuralSimplifier/if_true_condition.yul b/test/libyul/yulOptimizerTests/structuralSimplifier/if_true_condition.yul index 7d493efbc..bf1046fb2 100644 --- a/test/libyul/yulOptimizerTests/structuralSimplifier/if_true_condition.yul +++ b/test/libyul/yulOptimizerTests/structuralSimplifier/if_true_condition.yul @@ -1,5 +1,5 @@ { if 1 { mstore(0, 0) } } -// ==== -// step: structuralSimplifier // ---- +// step: structuralSimplifier +// // { mstore(0, 0) } diff --git a/test/libyul/yulOptimizerTests/structuralSimplifier/if_unassigned_condition.yul b/test/libyul/yulOptimizerTests/structuralSimplifier/if_unassigned_condition.yul index 4595fe899..bee5381c8 100644 --- a/test/libyul/yulOptimizerTests/structuralSimplifier/if_unassigned_condition.yul +++ b/test/libyul/yulOptimizerTests/structuralSimplifier/if_unassigned_condition.yul @@ -2,7 +2,7 @@ let x if x { mstore(0, 0) } } -// ==== -// step: structuralSimplifier // ---- +// step: structuralSimplifier +// // { let x } diff --git a/test/libyul/yulOptimizerTests/structuralSimplifier/nested.yul b/test/libyul/yulOptimizerTests/structuralSimplifier/nested.yul index 6783b6eee..44b2ecc61 100644 --- a/test/libyul/yulOptimizerTests/structuralSimplifier/nested.yul +++ b/test/libyul/yulOptimizerTests/structuralSimplifier/nested.yul @@ -1,5 +1,5 @@ { if 1 { if 1 { for { mstore(0, 0) } 0 {} { mstore(2, 3) } if 0 { mstore(1, 2) } } } } -// ==== -// step: structuralSimplifier // ---- +// step: structuralSimplifier +// // { mstore(0, 0) } diff --git a/test/libyul/yulOptimizerTests/structuralSimplifier/switch_inline.yul b/test/libyul/yulOptimizerTests/structuralSimplifier/switch_inline.yul index b80d4ea99..faa0304df 100644 --- a/test/libyul/yulOptimizerTests/structuralSimplifier/switch_inline.yul +++ b/test/libyul/yulOptimizerTests/structuralSimplifier/switch_inline.yul @@ -4,9 +4,9 @@ case 0 { y := 8 } case 1 { y := 9 } } -// ==== -// step: structuralSimplifier // ---- +// step: structuralSimplifier +// // { // let y := 200 // { y := 9 } diff --git a/test/libyul/yulOptimizerTests/structuralSimplifier/switch_inline_match_default.yul b/test/libyul/yulOptimizerTests/structuralSimplifier/switch_inline_match_default.yul index 5e985d78e..9238cb057 100644 --- a/test/libyul/yulOptimizerTests/structuralSimplifier/switch_inline_match_default.yul +++ b/test/libyul/yulOptimizerTests/structuralSimplifier/switch_inline_match_default.yul @@ -5,9 +5,9 @@ case 1 { y := 9 } default { y := 10 } } -// ==== -// step: structuralSimplifier // ---- +// step: structuralSimplifier +// // { // let y := 200 // { y := 10 } diff --git a/test/libyul/yulOptimizerTests/structuralSimplifier/switch_inline_no_match.yul b/test/libyul/yulOptimizerTests/structuralSimplifier/switch_inline_no_match.yul index 584bbb73d..9036db709 100644 --- a/test/libyul/yulOptimizerTests/structuralSimplifier/switch_inline_no_match.yul +++ b/test/libyul/yulOptimizerTests/structuralSimplifier/switch_inline_no_match.yul @@ -4,7 +4,7 @@ case 0 { y := 8 } case 1 { y := 9 } } -// ==== -// step: structuralSimplifier // ---- +// step: structuralSimplifier +// // { let y := 200 } diff --git a/test/libyul/yulOptimizerTests/structuralSimplifier/switch_inline_no_match_mixed.yul b/test/libyul/yulOptimizerTests/structuralSimplifier/switch_inline_no_match_mixed.yul index 0dea12292..5eeae71ba 100644 --- a/test/libyul/yulOptimizerTests/structuralSimplifier/switch_inline_no_match_mixed.yul +++ b/test/libyul/yulOptimizerTests/structuralSimplifier/switch_inline_no_match_mixed.yul @@ -5,7 +5,7 @@ case "" { y := 8 } case 1 { y := 9 } } -// ==== -// step: structuralSimplifier // ---- +// step: structuralSimplifier +// // { let y := 200 } diff --git a/test/libyul/yulOptimizerTests/structuralSimplifier/switch_no_remove_empty_case.yul b/test/libyul/yulOptimizerTests/structuralSimplifier/switch_no_remove_empty_case.yul index 8629be3f6..f8cc0558a 100644 --- a/test/libyul/yulOptimizerTests/structuralSimplifier/switch_no_remove_empty_case.yul +++ b/test/libyul/yulOptimizerTests/structuralSimplifier/switch_no_remove_empty_case.yul @@ -5,9 +5,9 @@ case 1 { y := 9 } default { y := 100 } } -// ==== -// step: structuralSimplifier // ---- +// step: structuralSimplifier +// // { // let y := 200 // switch calldataload(0) diff --git a/test/libyul/yulOptimizerTests/unusedPruner/functions.yul b/test/libyul/yulOptimizerTests/unusedPruner/functions.yul index 80758f082..cceace3bb 100644 --- a/test/libyul/yulOptimizerTests/unusedPruner/functions.yul +++ b/test/libyul/yulOptimizerTests/unusedPruner/functions.yul @@ -2,7 +2,7 @@ function f() { let a := 1 } function g() { f() } } -// ==== -// step: unusedPruner // ---- +// step: unusedPruner +// // { } diff --git a/test/libyul/yulOptimizerTests/unusedPruner/intermediate_assignment.yul b/test/libyul/yulOptimizerTests/unusedPruner/intermediate_assignment.yul index 1c1397061..32e96b9f3 100644 --- a/test/libyul/yulOptimizerTests/unusedPruner/intermediate_assignment.yul +++ b/test/libyul/yulOptimizerTests/unusedPruner/intermediate_assignment.yul @@ -3,9 +3,9 @@ a := 4 let b := 1 } -// ==== -// step: unusedPruner // ---- +// step: unusedPruner +// // { // let a := 1 // a := 4 diff --git a/test/libyul/yulOptimizerTests/unusedPruner/intermediate_multi_assignment.yul b/test/libyul/yulOptimizerTests/unusedPruner/intermediate_multi_assignment.yul index 2dd207fbf..bc05f09f8 100644 --- a/test/libyul/yulOptimizerTests/unusedPruner/intermediate_multi_assignment.yul +++ b/test/libyul/yulOptimizerTests/unusedPruner/intermediate_multi_assignment.yul @@ -4,9 +4,9 @@ a := f() b := 1 } -// ==== -// step: unusedPruner // ---- +// step: unusedPruner +// // { // let a, b // function f() -> x diff --git a/test/libyul/yulOptimizerTests/unusedPruner/keccak.yul b/test/libyul/yulOptimizerTests/unusedPruner/keccak.yul index c6b93a648..6ad93184a 100644 --- a/test/libyul/yulOptimizerTests/unusedPruner/keccak.yul +++ b/test/libyul/yulOptimizerTests/unusedPruner/keccak.yul @@ -3,9 +3,9 @@ let b := keccak256(1, 1) sstore(0, msize()) } -// ==== -// step: unusedPruner // ---- +// step: unusedPruner +// // { // pop(keccak256(1, 1)) // sstore(0, msize()) diff --git a/test/libyul/yulOptimizerTests/unusedPruner/movable_user_defined_function.yul b/test/libyul/yulOptimizerTests/unusedPruner/movable_user_defined_function.yul index 0d49d713b..09d366fb2 100644 --- a/test/libyul/yulOptimizerTests/unusedPruner/movable_user_defined_function.yul +++ b/test/libyul/yulOptimizerTests/unusedPruner/movable_user_defined_function.yul @@ -7,7 +7,7 @@ } let x := f(g(2)) } -// ==== -// step: unusedPruner // ---- +// step: unusedPruner +// // { } diff --git a/test/libyul/yulOptimizerTests/unusedPruner/msize.yul b/test/libyul/yulOptimizerTests/unusedPruner/msize.yul index ae6beaa75..05ad7b743 100644 --- a/test/libyul/yulOptimizerTests/unusedPruner/msize.yul +++ b/test/libyul/yulOptimizerTests/unusedPruner/msize.yul @@ -3,9 +3,9 @@ let b := mload(10) sstore(0, msize()) } -// ==== -// step: unusedPruner // ---- +// step: unusedPruner +// // { // pop(mload(10)) // sstore(0, msize()) diff --git a/test/libyul/yulOptimizerTests/unusedPruner/multi_assign.yul b/test/libyul/yulOptimizerTests/unusedPruner/multi_assign.yul index 77e9306c9..47e114373 100644 --- a/test/libyul/yulOptimizerTests/unusedPruner/multi_assign.yul +++ b/test/libyul/yulOptimizerTests/unusedPruner/multi_assign.yul @@ -4,9 +4,9 @@ function f() -> x, y { } a, b := f() } -// ==== -// step: unusedPruner // ---- +// step: unusedPruner +// // { // let a // let b diff --git a/test/libyul/yulOptimizerTests/unusedPruner/multi_assignments.yul b/test/libyul/yulOptimizerTests/unusedPruner/multi_assignments.yul index 01e573199..86f175d69 100644 --- a/test/libyul/yulOptimizerTests/unusedPruner/multi_assignments.yul +++ b/test/libyul/yulOptimizerTests/unusedPruner/multi_assignments.yul @@ -3,9 +3,9 @@ x := 1 y := 2 } -// ==== -// step: unusedPruner // ---- +// step: unusedPruner +// // { // let x, y // x := 1 diff --git a/test/libyul/yulOptimizerTests/unusedPruner/multi_declarations.yul b/test/libyul/yulOptimizerTests/unusedPruner/multi_declarations.yul index 76bd6a510..f727b0e93 100644 --- a/test/libyul/yulOptimizerTests/unusedPruner/multi_declarations.yul +++ b/test/libyul/yulOptimizerTests/unusedPruner/multi_declarations.yul @@ -1,7 +1,7 @@ { let x, y } -// ==== -// step: unusedPruner // ---- +// step: unusedPruner +// // { } diff --git a/test/libyul/yulOptimizerTests/unusedPruner/multi_declare.yul b/test/libyul/yulOptimizerTests/unusedPruner/multi_declare.yul index b4f6a5a7e..aa8ae0ad4 100644 --- a/test/libyul/yulOptimizerTests/unusedPruner/multi_declare.yul +++ b/test/libyul/yulOptimizerTests/unusedPruner/multi_declare.yul @@ -2,7 +2,7 @@ function f() -> x, y { } let a, b := f() } -// ==== -// step: unusedPruner // ---- +// step: unusedPruner +// // { } diff --git a/test/libyul/yulOptimizerTests/unusedPruner/multi_partial_assignments.yul b/test/libyul/yulOptimizerTests/unusedPruner/multi_partial_assignments.yul index 67d692f70..f54087a7d 100644 --- a/test/libyul/yulOptimizerTests/unusedPruner/multi_partial_assignments.yul +++ b/test/libyul/yulOptimizerTests/unusedPruner/multi_partial_assignments.yul @@ -2,9 +2,9 @@ let x, y x := 1 } -// ==== -// step: unusedPruner // ---- +// step: unusedPruner +// // { // let x, y // x := 1 diff --git a/test/libyul/yulOptimizerTests/unusedPruner/no_msize.yul b/test/libyul/yulOptimizerTests/unusedPruner/no_msize.yul index 8d40256eb..7bfc4d788 100644 --- a/test/libyul/yulOptimizerTests/unusedPruner/no_msize.yul +++ b/test/libyul/yulOptimizerTests/unusedPruner/no_msize.yul @@ -3,7 +3,7 @@ let b := mload(10) sstore(0, 5) } -// ==== -// step: unusedPruner // ---- +// step: unusedPruner +// // { sstore(0, 5) } diff --git a/test/libyul/yulOptimizerTests/unusedPruner/pop.yul b/test/libyul/yulOptimizerTests/unusedPruner/pop.yul index 089098215..66d16db1e 100644 --- a/test/libyul/yulOptimizerTests/unusedPruner/pop.yul +++ b/test/libyul/yulOptimizerTests/unusedPruner/pop.yul @@ -2,7 +2,7 @@ let a := 1 pop(a) } -// ==== -// step: unusedPruner // ---- +// step: unusedPruner +// // { } diff --git a/test/libyul/yulOptimizerTests/unusedPruner/smoke.yul b/test/libyul/yulOptimizerTests/unusedPruner/smoke.yul index 9adf68be5..a2ac495a0 100644 --- a/test/libyul/yulOptimizerTests/unusedPruner/smoke.yul +++ b/test/libyul/yulOptimizerTests/unusedPruner/smoke.yul @@ -1,5 +1,5 @@ { } -// ==== -// step: unusedPruner // ---- +// step: unusedPruner +// // { } diff --git a/test/libyul/yulOptimizerTests/unusedPruner/trivial.yul b/test/libyul/yulOptimizerTests/unusedPruner/trivial.yul index b3a05d38f..9de594351 100644 --- a/test/libyul/yulOptimizerTests/unusedPruner/trivial.yul +++ b/test/libyul/yulOptimizerTests/unusedPruner/trivial.yul @@ -3,7 +3,7 @@ let b := 1 mstore(0, 1) } -// ==== -// step: unusedPruner // ---- +// step: unusedPruner +// // { mstore(0, 1) } diff --git a/test/libyul/yulOptimizerTests/varDeclInitializer/ambiguous.yul b/test/libyul/yulOptimizerTests/varDeclInitializer/ambiguous.yul index 054d0b53c..8d306ca16 100644 --- a/test/libyul/yulOptimizerTests/varDeclInitializer/ambiguous.yul +++ b/test/libyul/yulOptimizerTests/varDeclInitializer/ambiguous.yul @@ -11,9 +11,9 @@ let b := 2 let x, y := f() } -// ==== -// step: varDeclInitializer // ---- +// step: varDeclInitializer +// // { // function f() -> x, y // { diff --git a/test/libyul/yulOptimizerTests/varDeclInitializer/inside_func.yul b/test/libyul/yulOptimizerTests/varDeclInitializer/inside_func.yul index f9510e32f..9a169b435 100644 --- a/test/libyul/yulOptimizerTests/varDeclInitializer/inside_func.yul +++ b/test/libyul/yulOptimizerTests/varDeclInitializer/inside_func.yul @@ -8,9 +8,9 @@ let r r := 4 } -// ==== -// step: varDeclInitializer // ---- +// step: varDeclInitializer +// // { // function f() -> x, y // { diff --git a/test/libyul/yulOptimizerTests/varDeclInitializer/multi.yul b/test/libyul/yulOptimizerTests/varDeclInitializer/multi.yul index 4911a6bd2..4968e2b04 100644 --- a/test/libyul/yulOptimizerTests/varDeclInitializer/multi.yul +++ b/test/libyul/yulOptimizerTests/varDeclInitializer/multi.yul @@ -3,9 +3,9 @@ let a let b } -// ==== -// step: varDeclInitializer // ---- +// step: varDeclInitializer +// // { // let x := 0 // let y := 0 diff --git a/test/libyul/yulOptimizerTests/varDeclInitializer/multi_assign.yul b/test/libyul/yulOptimizerTests/varDeclInitializer/multi_assign.yul index fac0eaa06..f8c37f2c5 100644 --- a/test/libyul/yulOptimizerTests/varDeclInitializer/multi_assign.yul +++ b/test/libyul/yulOptimizerTests/varDeclInitializer/multi_assign.yul @@ -7,9 +7,9 @@ let s := 3 let t } -// ==== -// step: varDeclInitializer // ---- +// step: varDeclInitializer +// // { // function f() -> x, y // { diff --git a/test/libyul/yulOptimizerTests/varDeclInitializer/simple.yul b/test/libyul/yulOptimizerTests/varDeclInitializer/simple.yul index 62d21dd0f..2b7d1048f 100644 --- a/test/libyul/yulOptimizerTests/varDeclInitializer/simple.yul +++ b/test/libyul/yulOptimizerTests/varDeclInitializer/simple.yul @@ -1,7 +1,7 @@ { let a } -// ==== -// step: varDeclInitializer // ---- +// step: varDeclInitializer +// // { let a := 0 } diff --git a/test/libyul/yulOptimizerTests/varDeclInitializer/typed.yul b/test/libyul/yulOptimizerTests/varDeclInitializer/typed.yul index 912246bea..069c68cab 100644 --- a/test/libyul/yulOptimizerTests/varDeclInitializer/typed.yul +++ b/test/libyul/yulOptimizerTests/varDeclInitializer/typed.yul @@ -8,8 +8,9 @@ } // ==== // dialect: evmTyped -// step: varDeclInitializer // ---- +// step: varDeclInitializer +// // { // let a1 := 0 // let a2:bool := false diff --git a/test/libyul/yulOptimizerTests/varNameCleaner/builtins.yul b/test/libyul/yulOptimizerTests/varNameCleaner/builtins.yul index 694d21847..b6ee0377f 100644 --- a/test/libyul/yulOptimizerTests/varNameCleaner/builtins.yul +++ b/test/libyul/yulOptimizerTests/varNameCleaner/builtins.yul @@ -1,7 +1,7 @@ { let datasize_256 := 1 } -// ==== -// step: varNameCleaner // ---- +// step: varNameCleaner +// // { let datasize_1 := 1 } diff --git a/test/libyul/yulOptimizerTests/varNameCleaner/function_names.yul b/test/libyul/yulOptimizerTests/varNameCleaner/function_names.yul index 629b5451e..ea4ca9ea2 100644 --- a/test/libyul/yulOptimizerTests/varNameCleaner/function_names.yul +++ b/test/libyul/yulOptimizerTests/varNameCleaner/function_names.yul @@ -3,9 +3,9 @@ function f() { let f_1 } let f_10 } -// ==== -// step: varNameCleaner // ---- +// step: varNameCleaner +// // { // let f_1 // function f() diff --git a/test/libyul/yulOptimizerTests/varNameCleaner/function_parameters.yul b/test/libyul/yulOptimizerTests/varNameCleaner/function_parameters.yul index 6f1d1817c..1608dd6fb 100644 --- a/test/libyul/yulOptimizerTests/varNameCleaner/function_parameters.yul +++ b/test/libyul/yulOptimizerTests/varNameCleaner/function_parameters.yul @@ -8,9 +8,9 @@ } let f_10 } -// ==== -// step: varNameCleaner // ---- +// step: varNameCleaner +// // { // let f_1 // function f(x) -> x_1, y diff --git a/test/libyul/yulOptimizerTests/varNameCleaner/function_scopes.yul b/test/libyul/yulOptimizerTests/varNameCleaner/function_scopes.yul index 7dabb4d47..c7d86ef98 100644 --- a/test/libyul/yulOptimizerTests/varNameCleaner/function_scopes.yul +++ b/test/libyul/yulOptimizerTests/varNameCleaner/function_scopes.yul @@ -2,9 +2,9 @@ function f() { let x_1 := 0 } function g() { let x_2 := 0 } } -// ==== -// step: varNameCleaner // ---- +// step: varNameCleaner +// // { // function f() // { let x := 0 } diff --git a/test/libyul/yulOptimizerTests/varNameCleaner/instructions.yul b/test/libyul/yulOptimizerTests/varNameCleaner/instructions.yul index acf71b1d9..2d7dbeb4a 100644 --- a/test/libyul/yulOptimizerTests/varNameCleaner/instructions.yul +++ b/test/libyul/yulOptimizerTests/varNameCleaner/instructions.yul @@ -1,7 +1,7 @@ { let mul_256 := 1 } -// ==== -// step: varNameCleaner // ---- +// step: varNameCleaner +// // { let mul_1 := 1 } diff --git a/test/libyul/yulOptimizerTests/varNameCleaner/name_stripping.yul b/test/libyul/yulOptimizerTests/varNameCleaner/name_stripping.yul index 4104c9567..cd32d8530 100644 --- a/test/libyul/yulOptimizerTests/varNameCleaner/name_stripping.yul +++ b/test/libyul/yulOptimizerTests/varNameCleaner/name_stripping.yul @@ -4,9 +4,9 @@ let a_4312 := 0xdeadbeef let _42 := 21718 } -// ==== -// step: varNameCleaner // ---- +// step: varNameCleaner +// // { // let a := 1 // let a_1 := 2 diff --git a/test/libyul/yulOptimizerTests/varNameCleaner/reshuffling-inverse.yul b/test/libyul/yulOptimizerTests/varNameCleaner/reshuffling-inverse.yul index d96a7b0be..100e5ccc6 100644 --- a/test/libyul/yulOptimizerTests/varNameCleaner/reshuffling-inverse.yul +++ b/test/libyul/yulOptimizerTests/varNameCleaner/reshuffling-inverse.yul @@ -4,9 +4,9 @@ let x_2 := 3 let x_1 := 4 } -// ==== -// step: varNameCleaner // ---- +// step: varNameCleaner +// // { // let x := 1 // let x_1 := 2 diff --git a/test/libyul/yulOptimizerTests/varNameCleaner/reshuffling.yul b/test/libyul/yulOptimizerTests/varNameCleaner/reshuffling.yul index e1132ad8b..d197d4ff3 100644 --- a/test/libyul/yulOptimizerTests/varNameCleaner/reshuffling.yul +++ b/test/libyul/yulOptimizerTests/varNameCleaner/reshuffling.yul @@ -3,9 +3,9 @@ let x_2 := 2 let x_3 := 3 } -// ==== -// step: varNameCleaner // ---- +// step: varNameCleaner +// // { // let x := 1 // let x_1 := 2 diff --git a/test/libyul/yulOptimizerTests/wordSizeTransform/constant_assignment.yul b/test/libyul/yulOptimizerTests/wordSizeTransform/constant_assignment.yul index fadfbd61f..10f8814a6 100644 --- a/test/libyul/yulOptimizerTests/wordSizeTransform/constant_assignment.yul +++ b/test/libyul/yulOptimizerTests/wordSizeTransform/constant_assignment.yul @@ -3,9 +3,9 @@ val := 9876543219876543219876543219876543219876543219876543219876543219876543210 } -// ==== -// step: wordSizeTransform // ---- +// step: wordSizeTransform +// // { // let val_0 := 196678011949 // let val_1 := 17592899865401375162 diff --git a/test/libyul/yulOptimizerTests/wordSizeTransform/function_call.yul b/test/libyul/yulOptimizerTests/wordSizeTransform/function_call.yul index d633e9500..3aef8c99c 100644 --- a/test/libyul/yulOptimizerTests/wordSizeTransform/function_call.yul +++ b/test/libyul/yulOptimizerTests/wordSizeTransform/function_call.yul @@ -12,9 +12,9 @@ } } -// ==== -// step: wordSizeTransform // ---- +// step: wordSizeTransform +// // { // function swap(x_0, x_1, x_2, x_3, y_0, y_1, y_2, y_3) -> a_0, a_1, a_2, a_3, b_0, b_1, b_2, b_3 // { diff --git a/test/libyul/yulOptimizerTests/wordSizeTransform/functional_instruction.yul b/test/libyul/yulOptimizerTests/wordSizeTransform/functional_instruction.yul index c1a99ef34..5ac0bfc00 100644 --- a/test/libyul/yulOptimizerTests/wordSizeTransform/functional_instruction.yul +++ b/test/libyul/yulOptimizerTests/wordSizeTransform/functional_instruction.yul @@ -1,9 +1,9 @@ { let x := add(999999999999999999999999999999999999999999999999999999999999999, 77777777777777777777777777777777777777777777777777777777777777) } -// ==== -// step: wordSizeTransform // ---- +// step: wordSizeTransform +// // { // let _1_0 := 12390 // let _1_1 := 13186919961226471680 diff --git a/test/libyul/yulOptimizerTests/wordSizeTransform/if.yul b/test/libyul/yulOptimizerTests/wordSizeTransform/if.yul index 5bfef91b1..b799760f8 100644 --- a/test/libyul/yulOptimizerTests/wordSizeTransform/if.yul +++ b/test/libyul/yulOptimizerTests/wordSizeTransform/if.yul @@ -2,9 +2,9 @@ if calldataload(0) { sstore(0, 1) } if add(calldataload(0), calldataload(1)) { sstore(0, 2) } } -// ==== -// step: wordSizeTransform // ---- +// step: wordSizeTransform +// // { // let _1_0 := 0 // let _1_1 := 0 diff --git a/test/libyul/yulOptimizerTests/wordSizeTransform/or_bool_renamed.yul b/test/libyul/yulOptimizerTests/wordSizeTransform/or_bool_renamed.yul index 016dd9bb8..803b28970 100644 --- a/test/libyul/yulOptimizerTests/wordSizeTransform/or_bool_renamed.yul +++ b/test/libyul/yulOptimizerTests/wordSizeTransform/or_bool_renamed.yul @@ -2,9 +2,9 @@ let or_bool := 2 if or_bool { sstore(0, 1) } } -// ==== -// step: wordSizeTransform // ---- +// step: wordSizeTransform +// // { // let or_bool_3_0 := 0 // let or_bool_3_1 := 0 diff --git a/test/libyul/yulOptimizerTests/wordSizeTransform/switch_1.yul b/test/libyul/yulOptimizerTests/wordSizeTransform/switch_1.yul index 22cb7631e..d40e2283f 100644 --- a/test/libyul/yulOptimizerTests/wordSizeTransform/switch_1.yul +++ b/test/libyul/yulOptimizerTests/wordSizeTransform/switch_1.yul @@ -5,9 +5,9 @@ case 2 { sstore(2, 1) } case 3 { sstore(3, 1) } } -// ==== -// step: wordSizeTransform // ---- +// step: wordSizeTransform +// // { // let _1_0 := 0 // let _1_1 := 0 diff --git a/test/libyul/yulOptimizerTests/wordSizeTransform/switch_2.yul b/test/libyul/yulOptimizerTests/wordSizeTransform/switch_2.yul index 12759e230..a9612a392 100644 --- a/test/libyul/yulOptimizerTests/wordSizeTransform/switch_2.yul +++ b/test/libyul/yulOptimizerTests/wordSizeTransform/switch_2.yul @@ -5,9 +5,9 @@ case 0x01000000000000000000000000000000000000020 { sstore(2, 1) } case 0x02000000000000000000000000000000000000020 { sstore(3, 1) } } -// ==== -// step: wordSizeTransform // ---- +// step: wordSizeTransform +// // { // let _1_0 := 0 // let _1_1 := 0 diff --git a/test/libyul/yulOptimizerTests/wordSizeTransform/switch_3.yul b/test/libyul/yulOptimizerTests/wordSizeTransform/switch_3.yul index 617eebb64..403c57962 100644 --- a/test/libyul/yulOptimizerTests/wordSizeTransform/switch_3.yul +++ b/test/libyul/yulOptimizerTests/wordSizeTransform/switch_3.yul @@ -6,9 +6,9 @@ case 3 { sstore(3, 1) } default { sstore(8, 9) } } -// ==== -// step: wordSizeTransform // ---- +// step: wordSizeTransform +// // { // let _1_0 := 0 // let _1_1 := 0 diff --git a/test/libyul/yulOptimizerTests/wordSizeTransform/switch_4.yul b/test/libyul/yulOptimizerTests/wordSizeTransform/switch_4.yul index 20f81d614..d1f45a623 100644 --- a/test/libyul/yulOptimizerTests/wordSizeTransform/switch_4.yul +++ b/test/libyul/yulOptimizerTests/wordSizeTransform/switch_4.yul @@ -6,9 +6,9 @@ case 0x02000000000000000000000000000000000000020 { sstore(3, 1) } default { sstore(8, 9) } } -// ==== -// step: wordSizeTransform // ---- +// step: wordSizeTransform +// // { // let _1_0 := 0 // let _1_1 := 0 diff --git a/test/libyul/yulOptimizerTests/wordSizeTransform/switch_5.yul b/test/libyul/yulOptimizerTests/wordSizeTransform/switch_5.yul index 2a42adefe..a02243a25 100644 --- a/test/libyul/yulOptimizerTests/wordSizeTransform/switch_5.yul +++ b/test/libyul/yulOptimizerTests/wordSizeTransform/switch_5.yul @@ -2,9 +2,9 @@ switch calldataload(0) default { sstore(8, 9) } } -// ==== -// step: wordSizeTransform // ---- +// step: wordSizeTransform +// // { // let _1_0 := 0 // let _1_1 := 0 diff --git a/test/tools/CMakeLists.txt b/test/tools/CMakeLists.txt index 5ea8486ec..c8add4ce7 100644 --- a/test/tools/CMakeLists.txt +++ b/test/tools/CMakeLists.txt @@ -17,6 +17,7 @@ add_executable(isoltest ../CommonSyntaxTest.cpp ../EVMHost.cpp ../TestCase.cpp + ../TestCaseReader.cpp ../libsolidity/util/BytesUtils.cpp ../libsolidity/util/ContractABIUtils.cpp ../libsolidity/util/TestFileParser.cpp diff --git a/test/tools/isoltest.cpp b/test/tools/isoltest.cpp index e439aba64..ad689ffcf 100644 --- a/test/tools/isoltest.cpp +++ b/test/tools/isoltest.cpp @@ -161,7 +161,6 @@ TestTool::Result TestTool::process() (AnsiColorized(cout, formatted, {BOLD}) << m_name << ": ").flush(); m_test = m_testCaseCreator(TestCase::Config{m_path.string(), m_options.evmVersion()}); - m_test->validateSettings(); if (m_test->shouldRun()) switch (TestCase::TestResult result = m_test->run(outputMessages, " ", formatted)) { @@ -173,7 +172,7 @@ TestTool::Result TestTool::process() AnsiColorized(cout, formatted, {BOLD, CYAN}) << " Contract:" << endl; m_test->printSource(cout, " ", formatted); - m_test->printUpdatedSettings(cout, " ", formatted); + m_test->printSettings(cout, " ", formatted); cout << endl << outputMessages.str() << endl; return result == TestCase::TestResult::FatalError ? Result::Exception : Result::Failure; @@ -232,7 +231,7 @@ TestTool::Request TestTool::handleResponse(bool _exception) cout << endl; ofstream file(m_path.string(), ios::trunc); m_test->printSource(file); - m_test->printUpdatedSettings(file); + m_test->printSettings(file); file << "// ----" << endl; m_test->printUpdatedExpectations(file, "// "); return Request::Rerun; diff --git a/test/yulPhaser/AlgorithmRunner.cpp b/test/yulPhaser/AlgorithmRunner.cpp new file mode 100644 index 000000000..0b54ad38f --- /dev/null +++ b/test/yulPhaser/AlgorithmRunner.cpp @@ -0,0 +1,243 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ + +#include + +#include +#include + +#include + +#include +#include +#include + +using namespace std; +using namespace boost::unit_test::framework; +using namespace boost::test_tools; +using namespace solidity::util; + +namespace fs = boost::filesystem; + +namespace solidity::phaser::test +{ + +class CountingAlgorithm: public GeneticAlgorithm +{ +public: + using GeneticAlgorithm::GeneticAlgorithm; + Population runNextRound(Population _population) override + { + ++m_currentRound; + return _population; + } + + size_t m_currentRound = 0; +}; + +class RandomisingAlgorithm: public GeneticAlgorithm +{ +public: + using GeneticAlgorithm::GeneticAlgorithm; + Population runNextRound(Population _population) override + { + return Population::makeRandom(_population.fitnessMetric(), _population.individuals().size(), 10, 20); + } +}; + +class AlgorithmRunnerFixture +{ +protected: + shared_ptr m_fitnessMetric = make_shared(); + output_test_stream m_output; + AlgorithmRunner::Options m_options; +}; + +class AlgorithmRunnerAutosaveFixture: public AlgorithmRunnerFixture +{ +public: + static vector chromosomeStrings(Population const& _population) + { + vector lines; + for (auto const& individual: _population.individuals()) + lines.push_back(toString(individual.chromosome)); + + return lines; + } + +protected: + TemporaryDirectory m_tempDir; + string const m_autosavePath = m_tempDir.memberPath("population-autosave.txt"); + Population const m_population = Population::makeRandom(m_fitnessMetric, 5, 0, 20); + RandomisingAlgorithm m_algorithm; +}; + +BOOST_AUTO_TEST_SUITE(Phaser) +BOOST_AUTO_TEST_SUITE(AlgorithmRunnerTest) + +BOOST_FIXTURE_TEST_CASE(run_should_call_runNextRound_once_per_round, AlgorithmRunnerFixture) +{ + m_options.maxRounds = 5; + AlgorithmRunner runner(Population(m_fitnessMetric), m_options, m_output); + + CountingAlgorithm algorithm; + + BOOST_TEST(algorithm.m_currentRound == 0); + runner.run(algorithm); + BOOST_TEST(algorithm.m_currentRound == 5); + runner.run(algorithm); + BOOST_TEST(algorithm.m_currentRound == 10); +} + +BOOST_FIXTURE_TEST_CASE(run_should_print_the_top_chromosome, AlgorithmRunnerFixture) +{ + // run() is allowed to print more but should at least print the first one + + m_options.maxRounds = 1; + AlgorithmRunner runner( + // NOTE: Chromosomes chosen so that they're not substrings of each other and are not + // words likely to appear in the output in normal circumstances. + Population(m_fitnessMetric, {Chromosome("fcCUnDve"), Chromosome("jsxIOo"), Chromosome("ighTLM")}), + m_options, + m_output + ); + + CountingAlgorithm algorithm; + + BOOST_TEST(m_output.is_empty()); + runner.run(algorithm); + BOOST_TEST(countSubstringOccurrences(m_output.str(), toString(runner.population().individuals()[0].chromosome)) == 1); + runner.run(algorithm); + runner.run(algorithm); + runner.run(algorithm); + BOOST_TEST(countSubstringOccurrences(m_output.str(), toString(runner.population().individuals()[0].chromosome)) == 4); +} + +BOOST_FIXTURE_TEST_CASE(run_should_save_initial_population_to_file_if_autosave_file_specified, AlgorithmRunnerAutosaveFixture) +{ + m_options.maxRounds = 0; + m_options.populationAutosaveFile = m_autosavePath; + AlgorithmRunner runner(m_population, m_options, m_output); + assert(!fs::exists(m_autosavePath)); + + runner.run(m_algorithm); + assert(runner.population() == m_population); + + BOOST_TEST(fs::is_regular_file(m_autosavePath)); + BOOST_TEST(readLinesFromFile(m_autosavePath) == chromosomeStrings(runner.population())); +} + +BOOST_FIXTURE_TEST_CASE(run_should_save_population_to_file_if_autosave_file_specified, AlgorithmRunnerAutosaveFixture) +{ + m_options.maxRounds = 1; + m_options.populationAutosaveFile = m_autosavePath; + AlgorithmRunner runner(m_population, m_options, m_output); + assert(!fs::exists(m_autosavePath)); + + runner.run(m_algorithm); + assert(runner.population() != m_population); + + BOOST_TEST(fs::is_regular_file(m_autosavePath)); + BOOST_TEST(readLinesFromFile(m_autosavePath) == chromosomeStrings(runner.population())); +} + +BOOST_FIXTURE_TEST_CASE(run_should_overwrite_existing_file_if_autosave_file_specified, AlgorithmRunnerAutosaveFixture) +{ + m_options.maxRounds = 5; + m_options.populationAutosaveFile = m_autosavePath; + AlgorithmRunner runner(m_population, m_options, m_output); + assert(!fs::exists(m_autosavePath)); + + vector originalContent = {"Original content"}; + { + ofstream tmpFile(m_autosavePath); + tmpFile << originalContent[0] << endl; + } + assert(fs::exists(m_autosavePath)); + assert(readLinesFromFile(m_autosavePath) == originalContent); + + runner.run(m_algorithm); + + BOOST_TEST(fs::is_regular_file(m_autosavePath)); + BOOST_TEST(readLinesFromFile(m_autosavePath) != originalContent); +} + +BOOST_FIXTURE_TEST_CASE(run_should_not_save_population_to_file_if_autosave_file_not_specified, AlgorithmRunnerAutosaveFixture) +{ + m_options.maxRounds = 5; + m_options.populationAutosaveFile = nullopt; + AlgorithmRunner runner(m_population, m_options, m_output); + assert(!fs::exists(m_autosavePath)); + + runner.run(m_algorithm); + + BOOST_TEST(!fs::exists(m_autosavePath)); +} + +BOOST_FIXTURE_TEST_CASE(run_should_randomise_duplicate_chromosomes_if_requested, AlgorithmRunnerFixture) +{ + Chromosome duplicate("afc"); + Population population(m_fitnessMetric, {duplicate, duplicate, duplicate}); + CountingAlgorithm algorithm; + + m_options.maxRounds = 1; + m_options.randomiseDuplicates = true; + m_options.minChromosomeLength = 50; + m_options.maxChromosomeLength = 50; + AlgorithmRunner runner(population, m_options, m_output); + + runner.run(algorithm); + + auto const& newIndividuals = runner.population().individuals(); + + BOOST_TEST(newIndividuals.size() == 3); + BOOST_TEST(( + newIndividuals[0].chromosome == duplicate || + newIndividuals[1].chromosome == duplicate || + newIndividuals[2].chromosome == duplicate + )); + BOOST_TEST(newIndividuals[0] != newIndividuals[1]); + BOOST_TEST(newIndividuals[0] != newIndividuals[2]); + BOOST_TEST(newIndividuals[1] != newIndividuals[2]); + + BOOST_TEST((newIndividuals[0].chromosome.length() == 50 || newIndividuals[0].chromosome == duplicate)); + BOOST_TEST((newIndividuals[1].chromosome.length() == 50 || newIndividuals[1].chromosome == duplicate)); + BOOST_TEST((newIndividuals[2].chromosome.length() == 50 || newIndividuals[2].chromosome == duplicate)); +} + +BOOST_FIXTURE_TEST_CASE(run_should_not_randomise_duplicate_chromosomes_if_not_requested, AlgorithmRunnerFixture) +{ + Chromosome duplicate("afc"); + Population population(m_fitnessMetric, {duplicate, duplicate, duplicate}); + CountingAlgorithm algorithm; + + m_options.maxRounds = 1; + m_options.randomiseDuplicates = false; + AlgorithmRunner runner(population, m_options, m_output); + + runner.run(algorithm); + + BOOST_TEST(runner.population().individuals().size() == 3); + BOOST_TEST(runner.population().individuals()[0].chromosome == duplicate); + BOOST_TEST(runner.population().individuals()[1].chromosome == duplicate); + BOOST_TEST(runner.population().individuals()[2].chromosome == duplicate); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() + +} diff --git a/test/yulPhaser/Chromosome.cpp b/test/yulPhaser/Chromosome.cpp index 23de34a2d..442f7967f 100644 --- a/test/yulPhaser/Chromosome.cpp +++ b/test/yulPhaser/Chromosome.cpp @@ -15,7 +15,7 @@ along with solidity. If not, see . */ -#include +#include #include #include diff --git a/test/yulPhaser/Common.cpp b/test/yulPhaser/Common.cpp index 93aa432fa..39e6dd784 100644 --- a/test/yulPhaser/Common.cpp +++ b/test/yulPhaser/Common.cpp @@ -15,52 +15,135 @@ along with solidity. If not, see . */ -#include +#include -#include +#include -#include +#include + +#include +#include + +#include +#include +#include using namespace std; -using namespace solidity; -using namespace solidity::yul; +using namespace boost::test_tools; +using namespace solidity::util; -vector phaser::test::chromosomeLengths(Population const& _population) +namespace solidity::phaser::test { - vector lengths; - for (auto const& individual: _population.individuals()) - lengths.push_back(individual.chromosome.length()); - return lengths; +class ReadLinesFromFileFixture +{ +protected: + TemporaryDirectory m_tempDir; +}; + +namespace +{ + +enum class TestEnum +{ + A, + B, + AB, + CD, + EF, + GH, +}; + +map const TestEnumToStringMap = +{ + {TestEnum::A, "a"}, + {TestEnum::B, "b"}, + {TestEnum::AB, "a b"}, + {TestEnum::CD, "c-d"}, + {TestEnum::EF, "e f"}, +}; +map const StringToTestEnumMap = invertMap(TestEnumToStringMap); + } -map phaser::test::enumerateOptmisationSteps() +BOOST_AUTO_TEST_SUITE(Phaser) +BOOST_AUTO_TEST_SUITE(CommonTest) + +BOOST_FIXTURE_TEST_CASE(readLinesFromFile_should_return_all_lines_from_a_text_file_as_strings_without_newlines, ReadLinesFromFileFixture) { - map stepIndices; - size_t i = 0; - for (auto const& nameAndAbbreviation: OptimiserSuite::stepNameToAbbreviationMap()) - stepIndices.insert({nameAndAbbreviation.first, i++}); - - return stepIndices; -} - -string phaser::test::stripWhitespace(string const& input) -{ - regex whitespaceRegex("\\s+"); - return regex_replace(input, whitespaceRegex, ""); -} - -size_t phaser::test::countSubstringOccurrences(string const& _inputString, string const& _substring) -{ - assert(_substring.size() > 0); - - size_t count = 0; - size_t lastOccurrence = 0; - while ((lastOccurrence = _inputString.find(_substring, lastOccurrence)) != string::npos) { - ++count; - lastOccurrence += _substring.size(); + ofstream tmpFile(m_tempDir.memberPath("test-file.txt")); + tmpFile << endl << "Line 1" << endl << endl << endl << "Line 2" << endl << "#" << endl << endl; } - return count; + vector lines = readLinesFromFile(m_tempDir.memberPath("test-file.txt")); + BOOST_TEST((lines == vector{"", "Line 1", "", "", "Line 2", "#", ""})); +} + +BOOST_AUTO_TEST_CASE(deserializeChoice_should_convert_string_to_enum) +{ + istringstream aStream("a"); + TestEnum aResult; + deserializeChoice(aStream, aResult, StringToTestEnumMap); + BOOST_CHECK(aResult == TestEnum::A); + BOOST_TEST(!aStream.fail()); + + istringstream bStream("b"); + TestEnum bResult; + deserializeChoice(bStream, bResult, StringToTestEnumMap); + BOOST_CHECK(bResult == TestEnum::B); + BOOST_TEST(!bStream.fail()); + + istringstream cdStream("c-d"); + TestEnum cdResult; + deserializeChoice(cdStream, cdResult, StringToTestEnumMap); + BOOST_CHECK(cdResult == TestEnum::CD); + BOOST_TEST(!cdStream.fail()); +} + +BOOST_AUTO_TEST_CASE(deserializeChoice_should_set_failbit_if_there_is_no_enum_corresponding_to_string) +{ + istringstream xyzStream("xyz"); + TestEnum xyzResult; + deserializeChoice(xyzStream, xyzResult, StringToTestEnumMap); + BOOST_TEST(xyzStream.fail()); +} + +BOOST_AUTO_TEST_CASE(deserializeChoice_does_not_have_to_support_strings_with_spaces) +{ + istringstream abStream("a b"); + TestEnum abResult; + deserializeChoice(abStream, abResult, StringToTestEnumMap); + BOOST_CHECK(abResult == TestEnum::A); + BOOST_TEST(!abStream.fail()); + + istringstream efStream("e f"); + TestEnum efResult; + deserializeChoice(efStream, efResult, StringToTestEnumMap); + BOOST_TEST(efStream.fail()); +} + +BOOST_AUTO_TEST_CASE(serializeChoice_should_convert_enum_to_string) +{ + output_test_stream output; + + serializeChoice(output, TestEnum::A, TestEnumToStringMap); + BOOST_CHECK(output.is_equal("a")); + BOOST_TEST(!output.fail()); + + serializeChoice(output, TestEnum::AB, TestEnumToStringMap); + BOOST_CHECK(output.is_equal("a b")); + BOOST_TEST(!output.fail()); +} + +BOOST_AUTO_TEST_CASE(serializeChoice_should_set_failbit_if_there_is_no_string_corresponding_to_enum) +{ + output_test_stream output; + serializeChoice(output, TestEnum::GH, TestEnumToStringMap); + BOOST_TEST(output.fail()); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() + } diff --git a/test/yulPhaser/FitnessMetrics.cpp b/test/yulPhaser/FitnessMetrics.cpp index 58561806d..8b62b03b7 100644 --- a/test/yulPhaser/FitnessMetrics.cpp +++ b/test/yulPhaser/FitnessMetrics.cpp @@ -22,22 +22,30 @@ #include +#include + #include +#include + using namespace std; using namespace solidity::langutil; +using namespace solidity::util; using namespace solidity::yul; namespace solidity::phaser::test { -class FitnessMetricFixture +class DummyProgramBasedMetric: public ProgramBasedMetric +{ +public: + using ProgramBasedMetric::ProgramBasedMetric; + size_t evaluate(Chromosome const&) override { return 0; } +}; + +class ProgramBasedMetricFixture { protected: - FitnessMetricFixture(): - m_sourceStream(SampleSourceCode, ""), - m_program(Program::load(m_sourceStream)) {} - static constexpr char SampleSourceCode[] = "{\n" " function foo() -> result\n" @@ -52,57 +60,171 @@ protected: " mstore(foo(), bar())\n" "}\n"; - CharStream m_sourceStream; - Program m_program; + Program optimisedProgram(Program _program) const + { + [[maybe_unused]] size_t originalSize = _program.codeSize(); + Program result = move(_program); + result.optimise(m_chromosome.optimisationSteps()); + + // Make sure that the program and the chromosome we have chosen are suitable for the test + assert(result.codeSize() != originalSize); + + return result; + } + + CharStream m_sourceStream = CharStream(SampleSourceCode, ""); + Chromosome m_chromosome{vector{UnusedPruner::name, EquivalentFunctionCombiner::name}}; + Program m_program = get(Program::load(m_sourceStream)); + Program m_optimisedProgram = optimisedProgram(m_program); +}; + +class FitnessMetricCombinationFixture: public ProgramBasedMetricFixture +{ +protected: + vector> m_simpleMetrics = { + make_shared(m_program, 1), + make_shared(m_program, 2), + make_shared(m_program, 3), + }; + vector m_fitness = { + m_simpleMetrics[0]->evaluate(m_chromosome), + m_simpleMetrics[1]->evaluate(m_chromosome), + m_simpleMetrics[2]->evaluate(m_chromosome), + }; }; BOOST_AUTO_TEST_SUITE(Phaser) BOOST_AUTO_TEST_SUITE(FitnessMetricsTest) +BOOST_AUTO_TEST_SUITE(ProgramBasedMetricTest) + +BOOST_FIXTURE_TEST_CASE(optimisedProgram_should_return_optimised_program, ProgramBasedMetricFixture) +{ + string code = toString(DummyProgramBasedMetric(m_program).optimisedProgram(m_chromosome)); + + BOOST_TEST(code != toString(m_program)); + BOOST_TEST(code == toString(m_optimisedProgram)); +} + +BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE(ProgramSizeTest) -BOOST_FIXTURE_TEST_CASE(evaluate_should_compute_size_of_the_optimised_program, FitnessMetricFixture) +BOOST_FIXTURE_TEST_CASE(evaluate_should_compute_size_of_the_optimised_program, ProgramBasedMetricFixture) { - Chromosome chromosome(vector{UnusedPruner::name, EquivalentFunctionCombiner::name}); + size_t fitness = ProgramSize(m_program).evaluate(m_chromosome); - Program optimisedProgram = m_program; - optimisedProgram.optimise(chromosome.optimisationSteps()); - assert(m_program.codeSize() != optimisedProgram.codeSize()); - - BOOST_TEST(ProgramSize(m_program).evaluate(chromosome) != m_program.codeSize()); - BOOST_TEST(ProgramSize(m_program).evaluate(chromosome) == optimisedProgram.codeSize()); + BOOST_TEST(fitness != m_program.codeSize()); + BOOST_TEST(fitness == m_optimisedProgram.codeSize()); } -BOOST_FIXTURE_TEST_CASE(evaluate_should_repeat_the_optimisation_specified_number_of_times, FitnessMetricFixture) +BOOST_FIXTURE_TEST_CASE(evaluate_should_repeat_the_optimisation_specified_number_of_times, ProgramBasedMetricFixture) { - Chromosome chromosome(vector{UnusedPruner::name, EquivalentFunctionCombiner::name}); - - Program programOptimisedOnce = m_program; - programOptimisedOnce.optimise(chromosome.optimisationSteps()); - Program programOptimisedTwice = programOptimisedOnce; - programOptimisedTwice.optimise(chromosome.optimisationSteps()); - assert(m_program.codeSize() != programOptimisedOnce.codeSize()); - assert(m_program.codeSize() != programOptimisedTwice.codeSize()); - assert(programOptimisedOnce.codeSize() != programOptimisedTwice.codeSize()); + Program const& programOptimisedOnce = m_optimisedProgram; + Program programOptimisedTwice = optimisedProgram(programOptimisedOnce); ProgramSize metric(m_program, 2); + size_t fitness = metric.evaluate(m_chromosome); - BOOST_TEST(metric.evaluate(chromosome) != m_program.codeSize()); - BOOST_TEST(metric.evaluate(chromosome) != programOptimisedOnce.codeSize()); - BOOST_TEST(metric.evaluate(chromosome) == programOptimisedTwice.codeSize()); + BOOST_TEST(fitness != m_program.codeSize()); + BOOST_TEST(fitness != programOptimisedOnce.codeSize()); + BOOST_TEST(fitness == programOptimisedTwice.codeSize()); } -BOOST_FIXTURE_TEST_CASE(evaluate_should_not_optimise_if_number_of_repetitions_is_zero, FitnessMetricFixture) +BOOST_FIXTURE_TEST_CASE(evaluate_should_not_optimise_if_number_of_repetitions_is_zero, ProgramBasedMetricFixture) { - Chromosome chromosome(vector{UnusedPruner::name, EquivalentFunctionCombiner::name}); - - Program optimisedProgram = m_program; - optimisedProgram.optimise(chromosome.optimisationSteps()); - assert(m_program.codeSize() != optimisedProgram.codeSize()); - ProgramSize metric(m_program, 0); + size_t fitness = metric.evaluate(m_chromosome); - BOOST_TEST(metric.evaluate(chromosome) == m_program.codeSize()); - BOOST_TEST(metric.evaluate(chromosome) != optimisedProgram.codeSize()); + BOOST_TEST(fitness == m_program.codeSize()); + BOOST_TEST(fitness != m_optimisedProgram.codeSize()); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE(RelativeProgramSizeTest) + +BOOST_FIXTURE_TEST_CASE(evaluate_should_compute_the_size_ratio_between_optimised_program_and_original_program, ProgramBasedMetricFixture) +{ + BOOST_TEST(RelativeProgramSize(m_program, 3).evaluate(m_chromosome) == round(1000.0 * m_optimisedProgram.codeSize() / m_program.codeSize())); +} + +BOOST_FIXTURE_TEST_CASE(evaluate_should_repeat_the_optimisation_specified_number_of_times, ProgramBasedMetricFixture) +{ + Program const& programOptimisedOnce = m_optimisedProgram; + Program programOptimisedTwice = optimisedProgram(programOptimisedOnce); + + RelativeProgramSize metric(m_program, 3, 2); + size_t fitness = metric.evaluate(m_chromosome); + + BOOST_TEST(fitness != 1000); + BOOST_TEST(fitness != RelativeProgramSize(programOptimisedTwice, 3, 1).evaluate(m_chromosome)); + BOOST_TEST(fitness == round(1000.0 * programOptimisedTwice.codeSize() / m_program.codeSize())); +} + +BOOST_FIXTURE_TEST_CASE(evaluate_should_return_one_if_number_of_repetitions_is_zero, ProgramBasedMetricFixture) +{ + RelativeProgramSize metric(m_program, 3, 0); + + BOOST_TEST(metric.evaluate(m_chromosome) == 1000); +} + +BOOST_FIXTURE_TEST_CASE(evaluate_should_return_one_if_the_original_program_size_is_zero, ProgramBasedMetricFixture) +{ + CharStream sourceStream = CharStream("{}", ""); + Program program = get(Program::load(sourceStream)); + + RelativeProgramSize metric(program, 3); + + BOOST_TEST(metric.evaluate(m_chromosome) == 1000); + BOOST_TEST(metric.evaluate(Chromosome("")) == 1000); + BOOST_TEST(metric.evaluate(Chromosome("afcxjLTLTDoO")) == 1000); +} + +BOOST_FIXTURE_TEST_CASE(evaluate_should_multiply_the_result_by_scaling_factor, ProgramBasedMetricFixture) +{ + double sizeRatio = static_cast(m_optimisedProgram.codeSize()) / m_program.codeSize(); + BOOST_TEST(RelativeProgramSize(m_program, 0).evaluate(m_chromosome) == round(1.0 * sizeRatio)); + BOOST_TEST(RelativeProgramSize(m_program, 1).evaluate(m_chromosome) == round(10.0 * sizeRatio)); + BOOST_TEST(RelativeProgramSize(m_program, 2).evaluate(m_chromosome) == round(100.0 * sizeRatio)); + BOOST_TEST(RelativeProgramSize(m_program, 3).evaluate(m_chromosome) == round(1000.0 * sizeRatio)); + BOOST_TEST(RelativeProgramSize(m_program, 4).evaluate(m_chromosome) == round(10000.0 * sizeRatio)); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE(FitnessMetricCombinationTest) + +BOOST_FIXTURE_TEST_CASE(FitnessMetricAverage_evaluate_should_compute_average_of_values_returned_by_metrics_passed_to_it, FitnessMetricCombinationFixture) +{ + FitnessMetricAverage metric(m_simpleMetrics); + + assert(m_simpleMetrics.size() == 3); + BOOST_TEST(metric.evaluate(m_chromosome) == (m_fitness[0] + m_fitness[1] + m_fitness[2]) / 3); + BOOST_TEST(metric.metrics() == m_simpleMetrics); +} + +BOOST_FIXTURE_TEST_CASE(FitnessMetricSum_evaluate_should_compute_sum_of_values_returned_by_metrics_passed_to_it, FitnessMetricCombinationFixture) +{ + FitnessMetricSum metric(m_simpleMetrics); + + assert(m_simpleMetrics.size() == 3); + BOOST_TEST(metric.evaluate(m_chromosome) == m_fitness[0] + m_fitness[1] + m_fitness[2]); + BOOST_TEST(metric.metrics() == m_simpleMetrics); +} + +BOOST_FIXTURE_TEST_CASE(FitnessMetricMaximum_evaluate_should_compute_maximum_of_values_returned_by_metrics_passed_to_it, FitnessMetricCombinationFixture) +{ + FitnessMetricMaximum metric(m_simpleMetrics); + + assert(m_simpleMetrics.size() == 3); + BOOST_TEST(metric.evaluate(m_chromosome) == max(m_fitness[0], max(m_fitness[1], m_fitness[2]))); + BOOST_TEST(metric.metrics() == m_simpleMetrics); +} + +BOOST_FIXTURE_TEST_CASE(FitnessMetricMinimum_evaluate_should_compute_minimum_of_values_returned_by_metrics_passed_to_it, FitnessMetricCombinationFixture) +{ + FitnessMetricMinimum metric(m_simpleMetrics); + + assert(m_simpleMetrics.size() == 3); + BOOST_TEST(metric.evaluate(m_chromosome) == min(m_fitness[0], min(m_fitness[1], m_fitness[2]))); + BOOST_TEST(metric.metrics() == m_simpleMetrics); } BOOST_AUTO_TEST_SUITE_END() @@ -110,4 +232,3 @@ BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() } - diff --git a/test/yulPhaser/GeneticAlgorithms.cpp b/test/yulPhaser/GeneticAlgorithms.cpp index aaa0a0b05..f7a5e7a92 100644 --- a/test/yulPhaser/GeneticAlgorithms.cpp +++ b/test/yulPhaser/GeneticAlgorithms.cpp @@ -15,121 +15,175 @@ along with solidity. If not, see . */ -#include +#include #include #include #include -#include - -#include #include #include -#include +#include #include using namespace std; using namespace boost::unit_test::framework; using namespace boost::test_tools; -using namespace solidity::langutil; -using namespace solidity::util; namespace solidity::phaser::test { -class DummyAlgorithm: public GeneticAlgorithm -{ -public: - using GeneticAlgorithm::GeneticAlgorithm; - void runNextRound() override { ++m_currentRound; } - - size_t m_currentRound = 0; -}; - class GeneticAlgorithmFixture { protected: shared_ptr m_fitnessMetric = make_shared(); - output_test_stream m_output; }; BOOST_AUTO_TEST_SUITE(Phaser) BOOST_AUTO_TEST_SUITE(GeneticAlgorithmsTest) -BOOST_AUTO_TEST_SUITE(GeneticAlgorithmTest) - -BOOST_FIXTURE_TEST_CASE(run_should_call_runNextRound_once_per_round, GeneticAlgorithmFixture) -{ - DummyAlgorithm algorithm(Population(m_fitnessMetric), m_output); - - BOOST_TEST(algorithm.m_currentRound == 0); - algorithm.run(10); - BOOST_TEST(algorithm.m_currentRound == 10); - algorithm.run(3); - BOOST_TEST(algorithm.m_currentRound == 13); -} - -BOOST_FIXTURE_TEST_CASE(run_should_print_the_top_chromosome, GeneticAlgorithmFixture) -{ - // run() is allowed to print more but should at least print the first one - - DummyAlgorithm algorithm( - // NOTE: Chromosomes chosen so that they're not substrings of each other and are not - // words likely to appear in the output in normal circumstances. - Population(m_fitnessMetric, {Chromosome("fcCUnDve"), Chromosome("jsxIOo"), Chromosome("ighTLM")}), - m_output - ); - - BOOST_TEST(m_output.is_empty()); - algorithm.run(1); - BOOST_TEST(countSubstringOccurrences(m_output.str(), toString(algorithm.population().individuals()[0].chromosome)) == 1); - algorithm.run(3); - BOOST_TEST(countSubstringOccurrences(m_output.str(), toString(algorithm.population().individuals()[0].chromosome)) == 4); -} - -BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE(RandomAlgorithmTest) BOOST_FIXTURE_TEST_CASE(runNextRound_should_preserve_elite_and_randomise_rest_of_population, GeneticAlgorithmFixture) { auto population = Population::makeRandom(m_fitnessMetric, 4, 3, 3) + Population::makeRandom(m_fitnessMetric, 4, 5, 5); - RandomAlgorithm algorithm(population, m_output, {0.5, 1, 1}); - assert((chromosomeLengths(algorithm.population()) == vector{3, 3, 3, 3, 5, 5, 5, 5})); + assert((chromosomeLengths(population) == vector{3, 3, 3, 3, 5, 5, 5, 5})); + RandomAlgorithm algorithm({0.5, 1, 1}); - algorithm.runNextRound(); - BOOST_TEST((chromosomeLengths(algorithm.population()) == vector{1, 1, 1, 1, 3, 3, 3, 3})); + Population newPopulation = algorithm.runNextRound(population); + BOOST_TEST((chromosomeLengths(newPopulation) == vector{1, 1, 1, 1, 3, 3, 3, 3})); } BOOST_FIXTURE_TEST_CASE(runNextRound_should_not_replace_elite_with_worse_individuals, GeneticAlgorithmFixture) { auto population = Population::makeRandom(m_fitnessMetric, 4, 3, 3) + Population::makeRandom(m_fitnessMetric, 4, 5, 5); - RandomAlgorithm algorithm(population, m_output, {0.5, 7, 7}); - assert((chromosomeLengths(algorithm.population()) == vector{3, 3, 3, 3, 5, 5, 5, 5})); + assert((chromosomeLengths(population) == vector{3, 3, 3, 3, 5, 5, 5, 5})); + RandomAlgorithm algorithm({0.5, 7, 7}); - algorithm.runNextRound(); - BOOST_TEST((chromosomeLengths(algorithm.population()) == vector{3, 3, 3, 3, 7, 7, 7, 7})); + Population newPopulation = algorithm.runNextRound(population); + BOOST_TEST((chromosomeLengths(newPopulation) == vector{3, 3, 3, 3, 7, 7, 7, 7})); } BOOST_FIXTURE_TEST_CASE(runNextRound_should_replace_all_chromosomes_if_zero_size_elite, GeneticAlgorithmFixture) { auto population = Population::makeRandom(m_fitnessMetric, 4, 3, 3) + Population::makeRandom(m_fitnessMetric, 4, 5, 5); - RandomAlgorithm algorithm(population, m_output, {0.0, 1, 1}); - assert((chromosomeLengths(algorithm.population()) == vector{3, 3, 3, 3, 5, 5, 5, 5})); + assert((chromosomeLengths(population) == vector{3, 3, 3, 3, 5, 5, 5, 5})); + RandomAlgorithm algorithm({0.0, 1, 1}); - algorithm.runNextRound(); - BOOST_TEST((chromosomeLengths(algorithm.population()) == vector{1, 1, 1, 1, 1, 1, 1, 1})); + Population newPopulation = algorithm.runNextRound(population); + BOOST_TEST((chromosomeLengths(newPopulation) == vector{1, 1, 1, 1, 1, 1, 1, 1})); } BOOST_FIXTURE_TEST_CASE(runNextRound_should_not_replace_any_chromosomes_if_whole_population_is_the_elite, GeneticAlgorithmFixture) { auto population = Population::makeRandom(m_fitnessMetric, 4, 3, 3) + Population::makeRandom(m_fitnessMetric, 4, 5, 5); - RandomAlgorithm algorithm(population, m_output, {1.0, 1, 1}); - assert((chromosomeLengths(algorithm.population()) == vector{3, 3, 3, 3, 5, 5, 5, 5})); + assert((chromosomeLengths(population) == vector{3, 3, 3, 3, 5, 5, 5, 5})); + RandomAlgorithm algorithm({1.0, 1, 1}); - algorithm.runNextRound(); - BOOST_TEST((chromosomeLengths(algorithm.population()) == vector{3, 3, 3, 3, 5, 5, 5, 5})); + Population newPopulation = algorithm.runNextRound(population); + BOOST_TEST((chromosomeLengths(newPopulation) == vector{3, 3, 3, 3, 5, 5, 5, 5})); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE(GenerationalElitistWithExclusivePoolsTest) + +BOOST_FIXTURE_TEST_CASE(runNextRound_should_preserve_elite_and_regenerate_rest_of_population, GeneticAlgorithmFixture) +{ + auto population = Population::makeRandom(m_fitnessMetric, 6, 3, 3) + Population::makeRandom(m_fitnessMetric, 4, 5, 5); + assert((chromosomeLengths(population) == vector{3, 3, 3, 3, 3, 3, 5, 5, 5, 5})); + + GenerationalElitistWithExclusivePools::Options options = { + /* mutationPoolSize = */ 0.2, + /* crossoverPoolSize = */ 0.2, + /* randomisationChance = */ 0.0, + /* deletionVsAdditionChance = */ 1.0, + /* percentGenesToRandomise = */ 0.0, + /* percentGenesToAddOrDelete = */ 1.0, + }; + GenerationalElitistWithExclusivePools algorithm(options); + + Population newPopulation = algorithm.runNextRound(population); + + BOOST_TEST((chromosomeLengths(newPopulation) == vector{0, 0, 3, 3, 3, 3, 3, 3, 3, 3})); +} + +BOOST_FIXTURE_TEST_CASE(runNextRound_should_not_replace_elite_with_worse_individuals, GeneticAlgorithmFixture) +{ + auto population = Population::makeRandom(m_fitnessMetric, 6, 3, 3) + Population::makeRandom(m_fitnessMetric, 4, 5, 5); + assert(chromosomeLengths(population) == (vector{3, 3, 3, 3, 3, 3, 5, 5, 5, 5})); + + GenerationalElitistWithExclusivePools::Options options = { + /* mutationPoolSize = */ 0.2, + /* crossoverPoolSize = */ 0.2, + /* randomisationChance = */ 0.0, + /* deletionVsAdditionChance = */ 0.0, + /* percentGenesToRandomise = */ 0.0, + /* percentGenesToAddOrDelete = */ 1.0, + }; + GenerationalElitistWithExclusivePools algorithm(options); + + Population newPopulation = algorithm.runNextRound(population); + + BOOST_TEST((chromosomeLengths(newPopulation) == vector{3, 3, 3, 3, 3, 3, 3, 3, 7, 7})); +} + +BOOST_FIXTURE_TEST_CASE(runNextRound_should_generate_individuals_in_the_crossover_pool_by_mutating_the_elite, GeneticAlgorithmFixture) +{ + auto population = Population::makeRandom(m_fitnessMetric, 20, 5, 5); + + GenerationalElitistWithExclusivePools::Options options = { + /* mutationPoolSize = */ 0.8, + /* crossoverPoolSize = */ 0.0, + /* randomisationChance = */ 0.5, + /* deletionVsAdditionChance = */ 0.5, + /* percentGenesToRandomise = */ 1.0, + /* percentGenesToAddOrDelete = */ 1.0, + }; + GenerationalElitistWithExclusivePools algorithm(options); + + SimulationRNG::reset(1); + Population newPopulation = algorithm.runNextRound(population); + + BOOST_TEST(( + chromosomeLengths(newPopulation) == + vector{0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 11, 11, 11} + )); +} + +BOOST_FIXTURE_TEST_CASE(runNextRound_should_generate_individuals_in_the_crossover_pool_by_crossing_over_the_elite, GeneticAlgorithmFixture) +{ + auto population = ( + Population(m_fitnessMetric, {Chromosome("aa"), Chromosome("ff")}) + + Population::makeRandom(m_fitnessMetric, 8, 6, 6) + ); + assert((chromosomeLengths(population) == vector{2, 2, 6, 6, 6, 6, 6, 6, 6, 6})); + + GenerationalElitistWithExclusivePools::Options options = { + /* mutationPoolSize = */ 0.0, + /* crossoverPoolSize = */ 0.8, + /* randomisationChance = */ 0.0, + /* deletionVsAdditionChance = */ 0.0, + /* percentGenesToRandomise = */ 0.0, + /* percentGenesToAddOrDelete = */ 0.0, + }; + GenerationalElitistWithExclusivePools algorithm(options); + + SimulationRNG::reset(1); + Population newPopulation = algorithm.runNextRound(population); + + vector const& newIndividuals = newPopulation.individuals(); + BOOST_TEST((chromosomeLengths(newPopulation) == vector{2, 2, 2, 2, 2, 2, 2, 2, 2, 2})); + for (auto& individual: newIndividuals) + BOOST_TEST(( + individual.chromosome == Chromosome("aa") || + individual.chromosome == Chromosome("af") || + individual.chromosome == Chromosome("fa") || + individual.chromosome == Chromosome("ff") + )); + BOOST_TEST(any_of(newIndividuals.begin() + 2, newIndividuals.end(), [](auto& individual){ + return individual.chromosome != Chromosome("aa") && individual.chromosome != Chromosome("ff"); + })); } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/yulPhaser/Mutations.cpp b/test/yulPhaser/Mutations.cpp new file mode 100644 index 000000000..df58cec54 --- /dev/null +++ b/test/yulPhaser/Mutations.cpp @@ -0,0 +1,394 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ + +#include + +#include + +#include + +#include + +#include +#include + +using namespace std; + +namespace solidity::phaser::test +{ + +BOOST_AUTO_TEST_SUITE(Phaser) +BOOST_AUTO_TEST_SUITE(MutationsTest) +BOOST_AUTO_TEST_SUITE(GeneRandomisationTest) + +BOOST_AUTO_TEST_CASE(geneRandomisation_should_iterate_over_genes_and_replace_them_with_random_ones_with_given_probability) +{ + Chromosome chromosome("fcCUnDvejs"); + function mutation01 = geneRandomisation(0.1); + function mutation05 = geneRandomisation(0.5); + function mutation10 = geneRandomisation(1.0); + + SimulationRNG::reset(1); + BOOST_TEST(countDifferences(mutation01(chromosome), chromosome), 2); + BOOST_TEST(countDifferences(mutation05(chromosome), chromosome), 5); + BOOST_TEST(countDifferences(mutation10(chromosome), chromosome), 7); + SimulationRNG::reset(2); + BOOST_TEST(countDifferences(mutation01(chromosome), chromosome), 1); + BOOST_TEST(countDifferences(mutation05(chromosome), chromosome), 3); + BOOST_TEST(countDifferences(mutation10(chromosome), chromosome), 9); +} + +BOOST_AUTO_TEST_CASE(geneRandomisation_should_return_identical_chromosome_if_probability_is_zero) +{ + Chromosome chromosome("fcCUnDvejsrmV"); + function mutation = geneRandomisation(0.0); + + BOOST_TEST(mutation(chromosome) == chromosome); +} + +BOOST_AUTO_TEST_CASE(geneDeletion_should_iterate_over_genes_and_delete_them_with_given_probability) +{ + Chromosome chromosome("fcCUnDvejs"); + function mutation01 = geneDeletion(0.1); + function mutation05 = geneDeletion(0.5); + + SimulationRNG::reset(1); + // fcCUnDvejs + BOOST_TEST(mutation01(chromosome) == Chromosome(stripWhitespace("fcCU Dvejs"))); + BOOST_TEST(mutation05(chromosome) == Chromosome(stripWhitespace(" D ejs"))); + SimulationRNG::reset(2); + BOOST_TEST(mutation01(chromosome) == Chromosome(stripWhitespace("fcUnDvejs"))); + BOOST_TEST(mutation05(chromosome) == Chromosome(stripWhitespace(" Un s"))); +} + +BOOST_AUTO_TEST_CASE(geneDeletion_should_return_identical_chromosome_if_probability_is_zero) +{ + Chromosome chromosome("fcCUnDvejsrmV"); + function mutation = geneDeletion(0.0); + + BOOST_TEST(mutation(chromosome) == chromosome); +} + +BOOST_AUTO_TEST_CASE(geneDeletion_should_delete_all_genes_if_probability_is_one) +{ + Chromosome chromosome("fcCUnDvejsrmV"); + function mutation = geneDeletion(1.0); + + BOOST_TEST(mutation(chromosome) == Chromosome("")); +} + +BOOST_AUTO_TEST_CASE(geneAddition_should_iterate_over_gene_positions_and_insert_new_genes_with_given_probability) +{ + Chromosome chromosome("fcCUnDvejs"); + function mutation01 = geneAddition(0.1); + function mutation05 = geneAddition(0.5); + + SimulationRNG::reset(1); + // f c C U n D v e j s + BOOST_TEST(mutation01(chromosome) == Chromosome(stripWhitespace(" f c C UC n D v e jx s"))); // 20% more + BOOST_TEST(mutation05(chromosome) == Chromosome(stripWhitespace("j f cu C U ne D v eI j sf"))); // 50% more + SimulationRNG::reset(2); + BOOST_TEST(mutation01(chromosome) == Chromosome(stripWhitespace(" f cu C U n D v e j s"))); // 10% more + BOOST_TEST(mutation05(chromosome) == Chromosome(stripWhitespace("L f ce Cv U n D v e jO s"))); // 40% more +} + +BOOST_AUTO_TEST_CASE(geneAddition_should_be_able_to_insert_before_first_position) +{ + SimulationRNG::reset(7); + Chromosome chromosome("fcCUnDvejs"); + function mutation = geneAddition(0.1); + + Chromosome mutatedChromosome = mutation(chromosome); + BOOST_TEST(mutatedChromosome.length() > chromosome.length()); + + vector suffix( + mutatedChromosome.optimisationSteps().end() - chromosome.length(), + mutatedChromosome.optimisationSteps().end() + ); + BOOST_TEST(suffix == chromosome.optimisationSteps()); +} + +BOOST_AUTO_TEST_CASE(geneAddition_should_be_able_to_insert_after_last_position) +{ + SimulationRNG::reset(81); + Chromosome chromosome("fcCUnDvejs"); + function mutation = geneAddition(0.1); + + Chromosome mutatedChromosome = mutation(chromosome); + BOOST_TEST(mutatedChromosome.length() > chromosome.length()); + + vector prefix( + mutatedChromosome.optimisationSteps().begin(), + mutatedChromosome.optimisationSteps().begin() + chromosome.length() + ); + BOOST_TEST(prefix == chromosome.optimisationSteps()); +} + +BOOST_AUTO_TEST_CASE(geneAddition_should_return_identical_chromosome_if_probability_is_zero) +{ + Chromosome chromosome("fcCUnDvejsrmV"); + function mutation = geneAddition(0.0); + + BOOST_TEST(mutation(chromosome) == chromosome); +} + +BOOST_AUTO_TEST_CASE(geneAddition_should_insert_genes_at_all_positions_if_probability_is_one) +{ + Chromosome chromosome("fcCUnDvejsrmV"); + function mutation = geneAddition(1.0); + + Chromosome mutatedChromosome = mutation(chromosome); + BOOST_TEST(mutatedChromosome.length() == chromosome.length() * 2 + 1); + + vector originalGenes; + for (size_t i = 0; i < mutatedChromosome.length() - 1; ++i) + if (i % 2 == 1) + originalGenes.push_back(mutatedChromosome.optimisationSteps()[i]); + + BOOST_TEST(Chromosome(originalGenes) == chromosome); +} + +BOOST_AUTO_TEST_CASE(alternativeMutations_should_choose_between_mutations_with_given_probability) +{ + SimulationRNG::reset(1); + Chromosome chromosome("a"); + function mutation = alternativeMutations( + 0.8, + wholeChromosomeReplacement(Chromosome("c")), + wholeChromosomeReplacement(Chromosome("f")) + ); + + size_t cCount = 0; + size_t fCount = 0; + for (size_t i = 0; i < 10; ++i) + { + Chromosome mutatedChromosome = mutation(chromosome); + cCount += static_cast(mutatedChromosome == Chromosome("c")); + fCount += static_cast(mutatedChromosome == Chromosome("f")); + } + + // This particular seed results in 7 "c"s out of 10 which looks plausible given the 80% chance. + BOOST_TEST(cCount == 7); + BOOST_TEST(fCount == 3); +} + +BOOST_AUTO_TEST_CASE(alternativeMutations_should_always_choose_first_mutation_if_probability_is_one) +{ + Chromosome chromosome("a"); + function mutation = alternativeMutations( + 1.0, + wholeChromosomeReplacement(Chromosome("c")), + wholeChromosomeReplacement(Chromosome("f")) + ); + + for (size_t i = 0; i < 10; ++i) + BOOST_TEST(mutation(chromosome) == Chromosome("c")); +} + +BOOST_AUTO_TEST_CASE(alternativeMutations_should_always_choose_second_mutation_if_probability_is_zero) +{ + Chromosome chromosome("a"); + function mutation = alternativeMutations( + 0.0, + wholeChromosomeReplacement(Chromosome("c")), + wholeChromosomeReplacement(Chromosome("f")) + ); + + for (size_t i = 0; i < 10; ++i) + BOOST_TEST(mutation(chromosome) == Chromosome("f")); +} + +BOOST_AUTO_TEST_CASE(randomPointCrossover_should_swap_chromosome_parts_at_random_point) +{ + function crossover = randomPointCrossover(); + + SimulationRNG::reset(1); + Chromosome result1 = crossover(Chromosome("aaaaaaaaaa"), Chromosome("cccccc")); + BOOST_TEST(result1 == Chromosome("aaaccc")); + + SimulationRNG::reset(1); + Chromosome result2 = crossover(Chromosome("cccccc"), Chromosome("aaaaaaaaaa")); + BOOST_TEST(result2 == Chromosome("cccaaaaaaa")); +} + +BOOST_AUTO_TEST_CASE(randomPointCrossover_should_only_consider_points_available_on_both_chromosomes) +{ + SimulationRNG::reset(1); + function crossover = randomPointCrossover(); + + for (size_t i = 0; i < 30; ++i) + { + Chromosome result1 = crossover(Chromosome("aaa"), Chromosome("TTTTTTTTTTTTTTTTTTTT")); + Chromosome result2 = crossover(Chromosome("TTTTTTTTTTTTTTTTTTTT"), Chromosome("aaa")); + BOOST_TEST(( + result1 == Chromosome("TTTTTTTTTTTTTTTTTTTT") || + result1 == Chromosome("aTTTTTTTTTTTTTTTTTTT") || + result1 == Chromosome("aaTTTTTTTTTTTTTTTTTT") || + result1 == Chromosome("aaaTTTTTTTTTTTTTTTTT") + )); + BOOST_TEST(( + result2 == Chromosome("aaa") || + result2 == Chromosome("Taa") || + result2 == Chromosome("TTa") || + result2 == Chromosome("TTT") + )); + } +} + +BOOST_AUTO_TEST_CASE(randomPointCrossover_should_never_split_at_position_zero_if_chromosomes_are_splittable) +{ + SimulationRNG::reset(1); + function crossover = randomPointCrossover(); + + for (size_t i = 0; i < 30; ++i) + { + Chromosome result1 = crossover(Chromosome("aa"), Chromosome("TTTTTTTTTTTTTTTTTTTT")); + Chromosome result2 = crossover(Chromosome("TTTTTTTTTTTTTTTTTTTT"), Chromosome("aa")); + BOOST_TEST(result1 != Chromosome("TTTTTTTTTTTTTTTTTTTT")); + BOOST_TEST(result2 != Chromosome("aa")); + } +} + +BOOST_AUTO_TEST_CASE(randomPointCrossover_should_never_split_at_position_zero_if_chromosomes_are_not_empty) +{ + SimulationRNG::reset(1); + function crossover = randomPointCrossover(); + + for (size_t i = 0; i < 30; ++i) + { + Chromosome result1 = crossover(Chromosome("a"), Chromosome("T")); + Chromosome result2 = crossover(Chromosome("T"), Chromosome("a")); + BOOST_TEST(result1 == Chromosome("a")); + BOOST_TEST(result2 == Chromosome("T")); + } +} + +BOOST_AUTO_TEST_CASE(randomPointCrossover_should_work_even_if_one_chromosome_is_unsplittable) +{ + function crossover = randomPointCrossover(); + + SimulationRNG::reset(1); + BOOST_CHECK(crossover(Chromosome("ff"), Chromosome("a")) == Chromosome("f")); + BOOST_CHECK(crossover(Chromosome("a"), Chromosome("ff")) == Chromosome("af")); +} + +BOOST_AUTO_TEST_CASE(randomPointCrossover_should_split_at_position_zero_only_if_at_least_one_chromosome_is_empty) +{ + Chromosome empty(""); + Chromosome unsplittable("a"); + Chromosome splittable("aaaa"); + function crossover = randomPointCrossover(); + + SimulationRNG::reset(1); + BOOST_CHECK(crossover(empty, empty) == empty); + BOOST_CHECK(crossover(unsplittable, empty) == empty); + BOOST_CHECK(crossover(empty, unsplittable) == unsplittable); + BOOST_CHECK(crossover(splittable, empty) == empty); + BOOST_CHECK(crossover(empty, splittable) == splittable); +} + +BOOST_AUTO_TEST_CASE(fixedPointCrossover_should_swap_chromosome_parts_at_given_point) +{ + Chromosome result1 = fixedPointCrossover(0.8)(Chromosome("aaaaaaaaaa"), Chromosome("cccccccccc")); + Chromosome result2 = fixedPointCrossover(0.8)(Chromosome("cccccccccc"), Chromosome("aaaaaaaaaa")); + BOOST_TEST(result1 == Chromosome("aaaaaaaacc")); + BOOST_TEST(result2 == Chromosome("ccccccccaa")); +} + +BOOST_AUTO_TEST_CASE(fixedPointCrossover_should_determine_crossover_point_based_on_length_of_shorter_chromosome) +{ + Chromosome result1 = fixedPointCrossover(0.4)(Chromosome("aaaaa"), Chromosome("cccccccccc")); + Chromosome result2 = fixedPointCrossover(0.4)(Chromosome("cccccccccc"), Chromosome("aaaaa")); + BOOST_TEST(result1 == Chromosome("aacccccccc")); + BOOST_TEST(result2 == Chromosome("ccaaa")); +} + +BOOST_AUTO_TEST_CASE(fixedPointCrossover_should_round_split_point) +{ + Chromosome result1 = fixedPointCrossover(0.49)(Chromosome("aaaaa"), Chromosome("ccccc")); + Chromosome result2 = fixedPointCrossover(0.49)(Chromosome("ccccc"), Chromosome("aaaaa")); + BOOST_TEST(result1 == Chromosome("aaccc")); + BOOST_TEST(result2 == Chromosome("ccaaa")); + + Chromosome result3 = fixedPointCrossover(0.50)(Chromosome("aaaaa"), Chromosome("ccccc")); + Chromosome result4 = fixedPointCrossover(0.50)(Chromosome("ccccc"), Chromosome("aaaaa")); + BOOST_TEST(result3 == Chromosome("aaacc")); + BOOST_TEST(result4 == Chromosome("cccaa")); + + Chromosome result5 = fixedPointCrossover(0.51)(Chromosome("aaaaa"), Chromosome("ccccc")); + Chromosome result6 = fixedPointCrossover(0.51)(Chromosome("ccccc"), Chromosome("aaaaa")); + BOOST_TEST(result5 == Chromosome("aaacc")); + BOOST_TEST(result6 == Chromosome("cccaa")); +} + +BOOST_AUTO_TEST_CASE(fixedPointCrossover_should_split_at_position_zero_if_explicitly_requested) +{ + Chromosome result1 = fixedPointCrossover(0.0)(Chromosome("aaaaa"), Chromosome("cccccccccc")); + Chromosome result2 = fixedPointCrossover(0.0)(Chromosome("cccccccccc"), Chromosome("aaaaa")); + BOOST_TEST(result1 == Chromosome("cccccccccc")); + BOOST_TEST(result2 == Chromosome("aaaaa")); +} + +BOOST_AUTO_TEST_CASE(fixedPointCrossover_should_split_at_end_of_shorter_chromosome_if_crossover_point_is_after_last_position) +{ + Chromosome result1 = fixedPointCrossover(1.0)(Chromosome("aaaaa"), Chromosome("cccccccccc")); + Chromosome result2 = fixedPointCrossover(1.0)(Chromosome("cccccccccc"), Chromosome("aaaaa")); + BOOST_TEST(result1 == Chromosome("aaaaaccccc")); + BOOST_TEST(result2 == Chromosome("ccccc")); +} + +BOOST_AUTO_TEST_CASE(fixedPointCrossover_should_select_correct_split_point_for_unsplittable_chromosomes) +{ + function crossover00 = fixedPointCrossover(0.0); + BOOST_CHECK(crossover00(Chromosome("fff"), Chromosome("a")) == Chromosome("a")); + BOOST_CHECK(crossover00(Chromosome("a"), Chromosome("fff")) == Chromosome("fff")); + + BOOST_CHECK(crossover00(Chromosome("f"), Chromosome("a")) == Chromosome("a")); + + function crossover10 = fixedPointCrossover(1.0); + BOOST_CHECK(crossover10(Chromosome("fff"), Chromosome("a")) == Chromosome("f")); + BOOST_CHECK(crossover10(Chromosome("a"), Chromosome("fff")) == Chromosome("aff")); + + BOOST_CHECK(crossover10(Chromosome("f"), Chromosome("a")) == Chromosome("f")); +} + +BOOST_AUTO_TEST_CASE(fixedPointCrossover_should_always_use_position_zero_as_split_point_when_chromosome_empty) +{ + Chromosome empty(""); + Chromosome unsplittable("f"); + Chromosome splittable("aaaa"); + + function crossover00 = fixedPointCrossover(0.0); + BOOST_CHECK(crossover00(empty, empty) == empty); + BOOST_CHECK(crossover00(unsplittable, empty) == empty); + BOOST_CHECK(crossover00(empty, unsplittable) == unsplittable); + BOOST_CHECK(crossover00(splittable, empty) == empty); + BOOST_CHECK(crossover00(empty, splittable) == splittable); + + function crossover10 = fixedPointCrossover(1.0); + BOOST_CHECK(crossover10(empty, empty) == empty); + BOOST_CHECK(crossover10(unsplittable, empty) == empty); + BOOST_CHECK(crossover10(empty, unsplittable) == unsplittable); + BOOST_CHECK(crossover10(splittable, empty) == empty); + BOOST_CHECK(crossover10(empty, splittable) == splittable); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() + +} diff --git a/test/yulPhaser/PairSelections.cpp b/test/yulPhaser/PairSelections.cpp new file mode 100644 index 000000000..64109470f --- /dev/null +++ b/test/yulPhaser/PairSelections.cpp @@ -0,0 +1,185 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ + +#include + +#include +#include + +#include + +#include +#include +#include + +using namespace std; + +namespace solidity::phaser::test +{ + +BOOST_AUTO_TEST_SUITE(Phaser) +BOOST_AUTO_TEST_SUITE(PairSelectionsTest) +BOOST_AUTO_TEST_SUITE(RandomPairSelectionTest) + +BOOST_AUTO_TEST_CASE(materialise_should_return_random_values_with_equal_probabilities) +{ + constexpr int collectionSize = 10; + constexpr int selectionSize = 100; + constexpr double relativeTolerance = 0.1; + constexpr double expectedValue = (collectionSize - 1) / 2.0; + constexpr double variance = (collectionSize * collectionSize - 1) / 12.0; + + SimulationRNG::reset(1); + vector> pairs = RandomPairSelection(selectionSize).materialise(collectionSize); + vector samples; + for (auto& [first, second]: pairs) + { + samples.push_back(first); + samples.push_back(second); + } + + BOOST_TEST(abs(mean(samples) - expectedValue) < expectedValue * relativeTolerance); + BOOST_TEST(abs(meanSquaredError(samples, expectedValue) - variance) < variance * relativeTolerance); +} + +BOOST_AUTO_TEST_CASE(materialise_should_return_only_values_that_can_be_used_as_collection_indices) +{ + const size_t collectionSize = 200; + + vector> pairs = RandomPairSelection(0.5).materialise(collectionSize); + + BOOST_TEST(pairs.size() == 100); + BOOST_TEST(all_of(pairs.begin(), pairs.end(), [&](auto const& pair){ return get<0>(pair) <= collectionSize; })); + BOOST_TEST(all_of(pairs.begin(), pairs.end(), [&](auto const& pair){ return get<1>(pair) <= collectionSize; })); +} + +BOOST_AUTO_TEST_CASE(materialise_should_never_return_a_pair_of_identical_indices) +{ + vector> pairs = RandomPairSelection(0.5).materialise(100); + + BOOST_TEST(pairs.size() == 50); + BOOST_TEST(all_of(pairs.begin(), pairs.end(), [](auto const& pair){ return get<0>(pair) != get<1>(pair); })); +} + +BOOST_AUTO_TEST_CASE(materialise_should_return_number_of_pairs_thats_a_fraction_of_collection_size) +{ + BOOST_TEST(RandomPairSelection(0.0).materialise(10).size() == 0); + BOOST_TEST(RandomPairSelection(0.3).materialise(10).size() == 3); + BOOST_TEST(RandomPairSelection(0.5).materialise(10).size() == 5); + BOOST_TEST(RandomPairSelection(0.7).materialise(10).size() == 7); + BOOST_TEST(RandomPairSelection(1.0).materialise(10).size() == 10); +} + +BOOST_AUTO_TEST_CASE(materialise_should_support_number_of_pairs_bigger_than_collection_size) +{ + BOOST_TEST(RandomPairSelection(2.0).materialise(5).size() == 10); + BOOST_TEST(RandomPairSelection(1.5).materialise(10).size() == 15); + BOOST_TEST(RandomPairSelection(10.0).materialise(10).size() == 100); +} + +BOOST_AUTO_TEST_CASE(materialise_should_round_the_number_of_pairs_to_the_nearest_integer) +{ + BOOST_TEST(RandomPairSelection(0.49).materialise(3).size() == 1); + BOOST_TEST(RandomPairSelection(0.50).materialise(3).size() == 2); + BOOST_TEST(RandomPairSelection(0.51).materialise(3).size() == 2); + + BOOST_TEST(RandomPairSelection(1.51).materialise(3).size() == 5); + + BOOST_TEST(RandomPairSelection(0.01).materialise(2).size() == 0); + BOOST_TEST(RandomPairSelection(0.01).materialise(3).size() == 0); +} + +BOOST_AUTO_TEST_CASE(materialise_should_return_no_pairs_if_collection_is_empty) +{ + BOOST_TEST(RandomPairSelection(0).materialise(0).empty()); + BOOST_TEST(RandomPairSelection(0.5).materialise(0).empty()); + BOOST_TEST(RandomPairSelection(1.0).materialise(0).empty()); + BOOST_TEST(RandomPairSelection(2.0).materialise(0).empty()); +} + +BOOST_AUTO_TEST_CASE(materialise_should_return_no_pairs_if_collection_has_one_element) +{ + BOOST_TEST(RandomPairSelection(0).materialise(1).empty()); + BOOST_TEST(RandomPairSelection(0.5).materialise(1).empty()); + BOOST_TEST(RandomPairSelection(1.0).materialise(1).empty()); + BOOST_TEST(RandomPairSelection(2.0).materialise(1).empty()); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE(PairMosaicSelectionTest) + +using IndexPairs = vector>; + +BOOST_AUTO_TEST_CASE(materialise) +{ + BOOST_TEST(PairMosaicSelection({{1, 1}}, 0.5).materialise(4) == IndexPairs({{1, 1}, {1, 1}})); + BOOST_TEST(PairMosaicSelection({{1, 1}}, 1.0).materialise(4) == IndexPairs({{1, 1}, {1, 1}, {1, 1}, {1, 1}})); + BOOST_TEST(PairMosaicSelection({{1, 1}}, 2.0).materialise(4) == IndexPairs({{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}})); + BOOST_TEST(PairMosaicSelection({{1, 1}}, 1.0).materialise(2) == IndexPairs({{1, 1}, {1, 1}})); + + IndexPairs pairs1{{0, 1}, {1, 0}}; + BOOST_TEST(PairMosaicSelection(pairs1, 0.5).materialise(4) == IndexPairs({{0, 1}, {1, 0}})); + BOOST_TEST(PairMosaicSelection(pairs1, 1.0).materialise(4) == IndexPairs({{0, 1}, {1, 0}, {0, 1}, {1, 0}})); + BOOST_TEST(PairMosaicSelection(pairs1, 2.0).materialise(4) == IndexPairs({{0, 1}, {1, 0}, {0, 1}, {1, 0}, {0, 1}, {1, 0}, {0, 1}, {1, 0}})); + BOOST_TEST(PairMosaicSelection(pairs1, 1.0).materialise(2) == IndexPairs({{0, 1}, {1, 0}})); + + IndexPairs pairs2{{3, 2}, {2, 3}, {1, 0}, {1, 1}}; + BOOST_TEST(PairMosaicSelection(pairs2, 0.5).materialise(4) == IndexPairs({{3, 2}, {2, 3}})); + BOOST_TEST(PairMosaicSelection(pairs2, 1.0).materialise(4) == IndexPairs({{3, 2}, {2, 3}, {1, 0}, {1, 1}})); + BOOST_TEST(PairMosaicSelection(pairs2, 2.0).materialise(4) == IndexPairs({{3, 2}, {2, 3}, {1, 0}, {1, 1}, {3, 2}, {2, 3}, {1, 0}, {1, 1}})); + + IndexPairs pairs3{{1, 0}, {1, 1}, {1, 0}, {1, 1}}; + BOOST_TEST(PairMosaicSelection(pairs3, 1.0).materialise(2) == IndexPairs({{1, 0}, {1, 1}})); +} + +BOOST_AUTO_TEST_CASE(materialise_should_round_indices) +{ + IndexPairs pairs{{4, 4}, {3, 3}, {2, 2}, {1, 1}, {0, 0}}; + BOOST_TEST(PairMosaicSelection(pairs, 0.49).materialise(5) == IndexPairs({{4, 4}, {3, 3}})); + BOOST_TEST(PairMosaicSelection(pairs, 0.50).materialise(5) == IndexPairs({{4, 4}, {3, 3}, {2, 2}})); + BOOST_TEST(PairMosaicSelection(pairs, 0.51).materialise(5) == IndexPairs({{4, 4}, {3, 3}, {2, 2}})); +} + +BOOST_AUTO_TEST_CASE(materialise_should_return_no_pairs_if_collection_is_empty) +{ + BOOST_TEST(PairMosaicSelection({{1, 1}}, 1.0).materialise(0).empty()); + BOOST_TEST(PairMosaicSelection({{1, 1}, {3, 3}}, 2.0).materialise(0).empty()); + BOOST_TEST(PairMosaicSelection({{5, 5}, {4, 4}, {3, 3}, {2, 2}}, 0.5).materialise(0).empty()); +} + +BOOST_AUTO_TEST_CASE(materialise_should_return_no_pairs_if_collection_has_one_element) +{ + IndexPairs pairs{{4, 4}, {3, 3}, {2, 2}, {1, 1}, {0, 0}}; + BOOST_TEST(PairMosaicSelection(pairs, 0.0).materialise(1).empty()); + BOOST_TEST(PairMosaicSelection(pairs, 0.5).materialise(1).empty()); + BOOST_TEST(PairMosaicSelection(pairs, 1.0).materialise(1).empty()); + BOOST_TEST(PairMosaicSelection(pairs, 7.0).materialise(1).empty()); +} + +BOOST_AUTO_TEST_CASE(materialise_should_clamp_indices_at_collection_size) +{ + IndexPairs pairs{{4, 4}, {3, 3}, {2, 2}, {1, 1}, {0, 0}}; + BOOST_TEST(PairMosaicSelection(pairs, 1.0).materialise(4) == IndexPairs({{3, 3}, {3, 3}, {2, 2}, {1, 1}})); + BOOST_TEST(PairMosaicSelection(pairs, 2.0).materialise(3) == IndexPairs({{2, 2}, {2, 2}, {2, 2}, {1, 1}, {0, 0}, {2, 2}})); + +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() + +} diff --git a/test/yulPhaser/Phaser.cpp b/test/yulPhaser/Phaser.cpp new file mode 100644 index 000000000..aab34db61 --- /dev/null +++ b/test/yulPhaser/Phaser.cpp @@ -0,0 +1,353 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ + +#include + +#include +#include + +#include + +#include + +#include +#include + +#include + +using namespace std; +using namespace solidity::util; +using namespace solidity::langutil; + +namespace fs = boost::filesystem; + +namespace solidity::phaser::test +{ + +class GeneticAlgorithmFactoryFixture +{ +protected: + GeneticAlgorithmFactory::Options m_options = { + /* algorithm = */ Algorithm::Random, + /* minChromosomeLength = */ 50, + /* maxChromosomeLength = */ 100, + /* randomElitePoolSize = */ 0.5, + /* gewepMutationPoolSize = */ 0.1, + /* gewepCrossoverPoolSize = */ 0.1, + /* gewepRandomisationChance = */ 0.6, + /* gewepDeletionVsAdditionChance = */ 0.3, + /* gewepGenesToRandomise = */ 0.4, + /* gewepGenesToAddOrDelete = */ 0.2, + }; +}; + +class FitnessMetricFactoryFixture +{ +protected: + vector m_sourceStreams = { + CharStream("{}", ""), + CharStream("{{}}", ""), + CharStream("{{{}}}", ""), + }; + vector m_programs = { + get(Program::load(m_sourceStreams[0])), + get(Program::load(m_sourceStreams[1])), + get(Program::load(m_sourceStreams[2])), + }; + FitnessMetricFactory::Options m_options = { + /* metric = */ MetricChoice::CodeSize, + /* metricAggregator = */ MetricAggregatorChoice::Average, + /* relativeMetricScale = */ 5, + /* chromosomeRepetitions = */ 1, + }; +}; + +class PoulationFactoryFixture +{ +protected: + shared_ptr m_fitnessMetric = make_shared(); + PopulationFactory::Options m_options = { + /* minChromosomeLength = */ 0, + /* maxChromosomeLength = */ 0, + /* population = */ {}, + /* randomPopulation = */ {}, + /* populationFromFile = */ {}, + }; +}; + +BOOST_AUTO_TEST_SUITE(Phaser) +BOOST_AUTO_TEST_SUITE(PhaserTest) +BOOST_AUTO_TEST_SUITE(GeneticAlgorithmFactoryTest) + +BOOST_FIXTURE_TEST_CASE(build_should_select_the_right_algorithm_and_pass_the_options_to_it, GeneticAlgorithmFactoryFixture) +{ + m_options.algorithm = Algorithm::Random; + unique_ptr algorithm1 = GeneticAlgorithmFactory::build(m_options, 100); + BOOST_REQUIRE(algorithm1 != nullptr); + + auto randomAlgorithm = dynamic_cast(algorithm1.get()); + BOOST_REQUIRE(randomAlgorithm != nullptr); + BOOST_TEST(randomAlgorithm->options().elitePoolSize == m_options.randomElitePoolSize.value()); + BOOST_TEST(randomAlgorithm->options().minChromosomeLength == m_options.minChromosomeLength); + BOOST_TEST(randomAlgorithm->options().maxChromosomeLength == m_options.maxChromosomeLength); + + m_options.algorithm = Algorithm::GEWEP; + unique_ptr algorithm2 = GeneticAlgorithmFactory::build(m_options, 100); + BOOST_REQUIRE(algorithm2 != nullptr); + + auto gewepAlgorithm = dynamic_cast(algorithm2.get()); + BOOST_REQUIRE(gewepAlgorithm != nullptr); + BOOST_TEST(gewepAlgorithm->options().mutationPoolSize == m_options.gewepMutationPoolSize); + BOOST_TEST(gewepAlgorithm->options().crossoverPoolSize == m_options.gewepCrossoverPoolSize); + BOOST_TEST(gewepAlgorithm->options().randomisationChance == m_options.gewepRandomisationChance); + BOOST_TEST(gewepAlgorithm->options().deletionVsAdditionChance == m_options.gewepDeletionVsAdditionChance); + BOOST_TEST(gewepAlgorithm->options().percentGenesToRandomise == m_options.gewepGenesToRandomise.value()); + BOOST_TEST(gewepAlgorithm->options().percentGenesToAddOrDelete == m_options.gewepGenesToAddOrDelete.value()); +} + +BOOST_FIXTURE_TEST_CASE(build_should_set_random_algorithm_elite_pool_size_based_on_population_size_if_not_specified, GeneticAlgorithmFactoryFixture) +{ + m_options.algorithm = Algorithm::Random; + m_options.randomElitePoolSize = nullopt; + unique_ptr algorithm = GeneticAlgorithmFactory::build(m_options, 100); + BOOST_REQUIRE(algorithm != nullptr); + + auto randomAlgorithm = dynamic_cast(algorithm.get()); + BOOST_REQUIRE(randomAlgorithm != nullptr); + BOOST_TEST(randomAlgorithm->options().elitePoolSize == 1.0 / 100.0); +} + +BOOST_FIXTURE_TEST_CASE(build_should_set_gewep_mutation_percentages_based_on_maximum_chromosome_length_if_not_specified, GeneticAlgorithmFactoryFixture) +{ + m_options.algorithm = Algorithm::GEWEP; + m_options.gewepGenesToRandomise = nullopt; + m_options.gewepGenesToAddOrDelete = nullopt; + m_options.maxChromosomeLength = 125; + + unique_ptr algorithm = GeneticAlgorithmFactory::build(m_options, 100); + BOOST_REQUIRE(algorithm != nullptr); + + auto gewepAlgorithm = dynamic_cast(algorithm.get()); + BOOST_REQUIRE(gewepAlgorithm != nullptr); + BOOST_TEST(gewepAlgorithm->options().percentGenesToRandomise == 1.0 / 125.0); + BOOST_TEST(gewepAlgorithm->options().percentGenesToAddOrDelete == 1.0 / 125.0); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE(FitnessMetricFactoryTest) + +BOOST_FIXTURE_TEST_CASE(build_should_create_metric_of_the_right_type, FitnessMetricFactoryFixture) +{ + m_options.metric = MetricChoice::RelativeCodeSize; + m_options.metricAggregator = MetricAggregatorChoice::Sum; + unique_ptr metric = FitnessMetricFactory::build(m_options, {m_programs[0]}); + BOOST_REQUIRE(metric != nullptr); + + auto sumMetric = dynamic_cast(metric.get()); + BOOST_REQUIRE(sumMetric != nullptr); + BOOST_REQUIRE(sumMetric->metrics().size() == 1); + BOOST_REQUIRE(sumMetric->metrics()[0] != nullptr); + + auto relativeProgramSizeMetric = dynamic_cast(sumMetric->metrics()[0].get()); + BOOST_REQUIRE(relativeProgramSizeMetric != nullptr); + BOOST_TEST(toString(relativeProgramSizeMetric->program()) == toString(m_programs[0])); +} + +BOOST_FIXTURE_TEST_CASE(build_should_respect_chromosome_repetitions_option, FitnessMetricFactoryFixture) +{ + m_options.metric = MetricChoice::CodeSize; + m_options.metricAggregator = MetricAggregatorChoice::Average; + m_options.chromosomeRepetitions = 5; + unique_ptr metric = FitnessMetricFactory::build(m_options, {m_programs[0]}); + BOOST_REQUIRE(metric != nullptr); + + auto averageMetric = dynamic_cast(metric.get()); + BOOST_REQUIRE(averageMetric != nullptr); + BOOST_REQUIRE(averageMetric->metrics().size() == 1); + BOOST_REQUIRE(averageMetric->metrics()[0] != nullptr); + + auto programSizeMetric = dynamic_cast(averageMetric->metrics()[0].get()); + BOOST_REQUIRE(programSizeMetric != nullptr); + BOOST_TEST(programSizeMetric->repetitionCount() == m_options.chromosomeRepetitions); +} + +BOOST_FIXTURE_TEST_CASE(build_should_set_relative_metric_scale, FitnessMetricFactoryFixture) +{ + m_options.metric = MetricChoice::RelativeCodeSize; + m_options.metricAggregator = MetricAggregatorChoice::Average; + m_options.relativeMetricScale = 10; + unique_ptr metric = FitnessMetricFactory::build(m_options, {m_programs[0]}); + BOOST_REQUIRE(metric != nullptr); + + auto averageMetric = dynamic_cast(metric.get()); + BOOST_REQUIRE(averageMetric != nullptr); + BOOST_REQUIRE(averageMetric->metrics().size() == 1); + BOOST_REQUIRE(averageMetric->metrics()[0] != nullptr); + + auto relativeProgramSizeMetric = dynamic_cast(averageMetric->metrics()[0].get()); + BOOST_REQUIRE(relativeProgramSizeMetric != nullptr); + BOOST_TEST(relativeProgramSizeMetric->fixedPointPrecision() == m_options.relativeMetricScale); +} + +BOOST_FIXTURE_TEST_CASE(build_should_create_metric_for_each_input_program, FitnessMetricFactoryFixture) +{ + unique_ptr metric = FitnessMetricFactory::build(m_options, m_programs); + BOOST_REQUIRE(metric != nullptr); + + auto combinedMetric = dynamic_cast(metric.get()); + BOOST_REQUIRE(combinedMetric != nullptr); + BOOST_REQUIRE(combinedMetric->metrics().size() == m_programs.size()); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE(PopulationFactoryTest) + +BOOST_FIXTURE_TEST_CASE(build_should_create_an_empty_population_if_no_specific_options_given, PoulationFactoryFixture) +{ + m_options.population = {}; + m_options.randomPopulation = {}; + m_options.populationFromFile = {}; + BOOST_TEST( + PopulationFactory::build(m_options, m_fitnessMetric) == + Population(m_fitnessMetric, vector{}) + ); +} + +BOOST_FIXTURE_TEST_CASE(build_should_respect_population_option, PoulationFactoryFixture) +{ + m_options.population = {"a", "afc", "xadd"}; + BOOST_TEST( + PopulationFactory::build(m_options, m_fitnessMetric) == + Population(m_fitnessMetric, {Chromosome("a"), Chromosome("afc"), Chromosome("xadd")}) + ); +} + +BOOST_FIXTURE_TEST_CASE(build_should_respect_random_population_option, PoulationFactoryFixture) +{ + m_options.randomPopulation = {5, 3, 2}; + m_options.minChromosomeLength = 5; + m_options.maxChromosomeLength = 10; + + auto population = PopulationFactory::build(m_options, m_fitnessMetric); + + BOOST_TEST(population.individuals().size() == 10); + BOOST_TEST(all_of( + population.individuals().begin(), + population.individuals().end(), + [](auto const& individual){ return 5 <= individual.chromosome.length() && individual.chromosome.length() <= 10; } + )); +} + +BOOST_FIXTURE_TEST_CASE(build_should_respect_population_from_file_option, PoulationFactoryFixture) +{ + map> fileContent = { + {"a.txt", {"a", "fff", "", "jxccLTa"}}, + {"b.txt", {}}, + {"c.txt", {""}}, + {"d.txt", {"c", "T"}}, + }; + + TemporaryDirectory tempDir; + for (auto const& [fileName, chromosomes]: fileContent) + { + ofstream tmpFile(tempDir.memberPath(fileName)); + for (auto const& chromosome: chromosomes) + tmpFile << chromosome << endl; + + m_options.populationFromFile.push_back(tempDir.memberPath(fileName)); + } + + BOOST_TEST( + PopulationFactory::build(m_options, m_fitnessMetric) == + Population(m_fitnessMetric, { + Chromosome("a"), + Chromosome("fff"), + Chromosome(""), + Chromosome("jxccLTa"), + Chromosome(""), + Chromosome("c"), + Chromosome("T"), + }) + ); +} + +BOOST_FIXTURE_TEST_CASE(build_should_throw_FileOpenError_if_population_file_does_not_exist, PoulationFactoryFixture) +{ + m_options.populationFromFile = {"a-file-that-does-not-exist.abcdefgh"}; + assert(!fs::exists(m_options.populationFromFile[0])); + + BOOST_CHECK_THROW(PopulationFactory::build(m_options, m_fitnessMetric), FileOpenError); +} + +BOOST_FIXTURE_TEST_CASE(build_should_combine_populations_from_all_sources, PoulationFactoryFixture) +{ + TemporaryDirectory tempDir; + { + ofstream tmpFile(tempDir.memberPath("population.txt")); + tmpFile << "axc" << endl << "fcL" << endl; + } + + m_options.population = {"axc", "fcL"}; + m_options.randomPopulation = {2}; + m_options.populationFromFile = {tempDir.memberPath("population.txt")}; + m_options.minChromosomeLength = 3; + m_options.maxChromosomeLength = 3; + + auto population = PopulationFactory::build(m_options, m_fitnessMetric); + + auto begin = population.individuals().begin(); + auto end = population.individuals().end(); + BOOST_TEST(population.individuals().size() == 6); + BOOST_TEST(all_of(begin, end, [](auto const& individual){ return individual.chromosome.length() == 3; })); + BOOST_TEST(count(begin, end, Individual(Chromosome("axc"), *m_fitnessMetric)) >= 2); + BOOST_TEST(count(begin, end, Individual(Chromosome("fcL"), *m_fitnessMetric)) >= 2); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE(ProgramFactoryTest) + +BOOST_AUTO_TEST_CASE(build_should_load_programs_from_files) +{ + TemporaryDirectory tempDir; + vector sources{"{}", "{{}}", "{{{}}}"}; + ProgramFactory::Options options{/* inputFiles = */ { + tempDir.memberPath("program1.yul"), + tempDir.memberPath("program2.yul"), + tempDir.memberPath("program3.yul"), + }}; + + for (size_t i = 0; i < sources.size(); ++i) + { + ofstream tmpFile(options.inputFiles[i]); + tmpFile << sources[i] << endl; + } + + vector programs = ProgramFactory::build(options); + + BOOST_TEST(programs.size() == sources.size()); + for (size_t i = 0; i < sources.size(); ++i) + { + CharStream sourceStream(sources[i], options.inputFiles[i]); + BOOST_TEST(toString(programs[i]) == toString(get(Program::load(sourceStream)))); + } +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() + +} diff --git a/test/yulPhaser/Population.cpp b/test/yulPhaser/Population.cpp index 98532c9dc..7a9172749 100644 --- a/test/yulPhaser/Population.cpp +++ b/test/yulPhaser/Population.cpp @@ -15,9 +15,10 @@ along with solidity. If not, see . */ -#include +#include #include +#include #include #include #include @@ -31,6 +32,7 @@ #include +#include #include #include #include @@ -226,6 +228,70 @@ BOOST_FIXTURE_TEST_CASE(select_should_return_empty_population_if_selection_is_em BOOST_TEST(population.select(selection).individuals().empty()); } +BOOST_FIXTURE_TEST_CASE(mutate_should_return_population_containing_individuals_indicated_by_selection_with_mutation_applied, PopulationFixture) +{ + Population population(m_fitnessMetric, {Chromosome("aa"), Chromosome("cc"), Chromosome("gg"), Chromosome("hh")}); + RangeSelection selection(0.25, 0.75); + assert(selection.materialise(population.individuals().size()) == (vector{1, 2})); + + Population expectedPopulation(m_fitnessMetric, {Chromosome("fc"), Chromosome("fg")}); + + BOOST_TEST(population.mutate(selection, geneSubstitution(0, BlockFlattener::name)) == expectedPopulation); +} + +BOOST_FIXTURE_TEST_CASE(mutate_should_include_duplicates_if_selection_contains_duplicates, PopulationFixture) +{ + Population population(m_fitnessMetric, {Chromosome("aa"), Chromosome("aa")}); + RangeSelection selection(0.0, 1.0); + assert(selection.materialise(population.individuals().size()) == (vector{0, 1})); + + BOOST_TEST( + population.mutate(selection, geneSubstitution(0, BlockFlattener::name)) == + Population(m_fitnessMetric, {Chromosome("fa"), Chromosome("fa")}) + ); +} + +BOOST_FIXTURE_TEST_CASE(mutate_should_return_empty_population_if_selection_is_empty, PopulationFixture) +{ + Population population(m_fitnessMetric, {Chromosome("aa"), Chromosome("cc")}); + RangeSelection selection(0.0, 0.0); + assert(selection.materialise(population.individuals().size()).empty()); + + BOOST_TEST(population.mutate(selection, geneSubstitution(0, BlockFlattener::name)).individuals().empty()); +} + +BOOST_FIXTURE_TEST_CASE(crossover_should_return_population_containing_individuals_indicated_by_selection_with_crossover_applied, PopulationFixture) +{ + Population population(m_fitnessMetric, {Chromosome("aa"), Chromosome("cc"), Chromosome("gg"), Chromosome("hh")}); + PairMosaicSelection selection({{0, 1}, {2, 1}}, 1.0); + assert(selection.materialise(population.individuals().size()) == (vector>{{0, 1}, {2, 1}, {0, 1}, {2, 1}})); + + Population expectedPopulation(m_fitnessMetric, {Chromosome("ac"), Chromosome("ac"), Chromosome("gc"), Chromosome("gc")}); + + BOOST_TEST(population.crossover(selection, fixedPointCrossover(0.5)) == expectedPopulation); +} + +BOOST_FIXTURE_TEST_CASE(crossover_should_include_duplicates_if_selection_contains_duplicates, PopulationFixture) +{ + Population population(m_fitnessMetric, {Chromosome("aa"), Chromosome("aa")}); + PairMosaicSelection selection({{0, 0}, {1, 1}}, 2.0); + assert(selection.materialise(population.individuals().size()) == (vector>{{0, 0}, {1, 1}, {0, 0}, {1, 1}})); + + BOOST_TEST( + population.crossover(selection, fixedPointCrossover(0.5)) == + Population(m_fitnessMetric, {Chromosome("aa"), Chromosome("aa"), Chromosome("aa"), Chromosome("aa")}) + ); +} + +BOOST_FIXTURE_TEST_CASE(crossover_should_return_empty_population_if_selection_is_empty, PopulationFixture) +{ + Population population(m_fitnessMetric, {Chromosome("aa"), Chromosome("cc")}); + PairMosaicSelection selection({}, 0.0); + assert(selection.materialise(population.individuals().size()).empty()); + + BOOST_TEST(population.crossover(selection, fixedPointCrossover(0.5)).individuals().empty()); +} + BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() diff --git a/test/yulPhaser/Program.cpp b/test/yulPhaser/Program.cpp index 7d9c81cd3..5d4e012f3 100644 --- a/test/yulPhaser/Program.cpp +++ b/test/yulPhaser/Program.cpp @@ -15,7 +15,7 @@ along with solidity. If not, see . */ -#include +#include #include #include @@ -68,7 +68,7 @@ BOOST_AUTO_TEST_CASE(copy_constructor_should_make_deep_copy_of_ast) "}\n" ); CharStream sourceStream(sourceCode, current_test_case().p_name); - auto program = Program::load(sourceStream); + Program program = get(Program::load(sourceStream)); Program programCopy(program); @@ -91,7 +91,7 @@ BOOST_AUTO_TEST_CASE(load_should_rewind_the_stream) CharStream sourceStream(sourceCode, current_test_case().p_name); sourceStream.setPosition(5); - auto program = Program::load(sourceStream); + Program program = get(Program::load(sourceStream)); BOOST_TEST(CodeSize::codeSize(program.ast()) == 2); } @@ -109,7 +109,7 @@ BOOST_AUTO_TEST_CASE(load_should_disambiguate) "}\n" ); CharStream sourceStream(sourceCode, current_test_case().p_name); - auto program = Program::load(sourceStream); + Program program = get(Program::load(sourceStream)); // skipRedundantBlocks() makes the test independent of whether load() includes function grouping or not. Block const& parentBlock = skipRedundantBlocks(program.ast()); @@ -141,7 +141,7 @@ BOOST_AUTO_TEST_CASE(load_should_do_function_grouping_and_hoisting) "}\n" ); CharStream sourceStream(sourceCode, current_test_case().p_name); - auto program = Program::load(sourceStream); + Program program = get(Program::load(sourceStream)); BOOST_TEST(program.ast().statements.size() == 3); BOOST_TEST(holds_alternative(program.ast().statements[0])); @@ -159,7 +159,7 @@ BOOST_AUTO_TEST_CASE(load_should_do_loop_init_rewriting) "}\n" ); CharStream sourceStream(sourceCode, current_test_case().p_name); - auto program = Program::load(sourceStream); + Program program = get(Program::load(sourceStream)); // skipRedundantBlocks() makes the test independent of whether load() includes function grouping or not. Block const& parentBlock = skipRedundantBlocks(program.ast()); @@ -172,7 +172,7 @@ BOOST_AUTO_TEST_CASE(load_should_throw_InvalidProgram_if_program_cant_be_parsed) string sourceCode("invalid program\n"); CharStream sourceStream(sourceCode, current_test_case().p_name); - BOOST_CHECK_THROW(Program::load(sourceStream), InvalidProgram); + BOOST_TEST(holds_alternative(Program::load(sourceStream))); } BOOST_AUTO_TEST_CASE(load_should_throw_InvalidProgram_if_program_cant_be_analyzed) @@ -186,7 +186,7 @@ BOOST_AUTO_TEST_CASE(load_should_throw_InvalidProgram_if_program_cant_be_analyze ); CharStream sourceStream(sourceCode, current_test_case().p_name); - BOOST_CHECK_THROW(Program::load(sourceStream), InvalidProgram); + BOOST_TEST(holds_alternative(Program::load(sourceStream))); } BOOST_AUTO_TEST_CASE(optimise) @@ -200,7 +200,7 @@ BOOST_AUTO_TEST_CASE(optimise) "}\n" ); CharStream sourceStream(sourceCode, current_test_case().p_name); - auto program = Program::load(sourceStream); + Program program = get(Program::load(sourceStream)); [[maybe_unused]] Block const& parentBlockBefore = skipRedundantBlocks(program.ast()); assert(parentBlockBefore.statements.size() == 2); @@ -231,7 +231,7 @@ BOOST_AUTO_TEST_CASE(output_operator) "}\n" ); CharStream sourceStream(sourceCode, current_test_case().p_name); - auto program = Program::load(sourceStream); + Program program = get(Program::load(sourceStream)); // NOTE: The snippet above was chosen so that the few optimisations applied automatically by load() // as of now do not change the code significantly. If that changes, you may have to update it. @@ -250,7 +250,7 @@ BOOST_AUTO_TEST_CASE(toJson) "}\n" ); CharStream sourceStream(sourceCode, current_test_case().p_name); - auto program = Program::load(sourceStream); + Program program = get(Program::load(sourceStream)); Json::Value parsingResult; string errors; @@ -270,7 +270,7 @@ BOOST_AUTO_TEST_CASE(codeSize) "}\n" ); CharStream sourceStream(sourceCode, current_test_case().p_name); - auto program = Program::load(sourceStream); + Program program = get(Program::load(sourceStream)); BOOST_TEST(program.codeSize() == CodeSize::codeSizeIncludingFunctions(program.ast())); } diff --git a/test/yulPhaser/Selections.cpp b/test/yulPhaser/Selections.cpp index ce870ce80..02a85f4f3 100644 --- a/test/yulPhaser/Selections.cpp +++ b/test/yulPhaser/Selections.cpp @@ -15,7 +15,7 @@ along with solidity. If not, see . */ -#include +#include #include #include diff --git a/test/yulPhaser/SimulationRNG.cpp b/test/yulPhaser/SimulationRNG.cpp index f158fcbf6..0cdacc428 100644 --- a/test/yulPhaser/SimulationRNG.cpp +++ b/test/yulPhaser/SimulationRNG.cpp @@ -15,7 +15,7 @@ along with solidity. If not, see . */ -#include +#include #include diff --git a/test/yulPhaser/TestHelpers.cpp b/test/yulPhaser/TestHelpers.cpp new file mode 100644 index 000000000..2379016fe --- /dev/null +++ b/test/yulPhaser/TestHelpers.cpp @@ -0,0 +1,133 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ + +#include + +#include + +#include + +#include +#include + +using namespace std; +using namespace solidity; +using namespace solidity::yul; +using namespace solidity::phaser; +using namespace solidity::phaser::test; + +namespace fs = boost::filesystem; + +function phaser::test::wholeChromosomeReplacement(Chromosome _newChromosome) +{ + return [_newChromosome = move(_newChromosome)](Chromosome const&) { return _newChromosome; }; +} + +function phaser::test::geneSubstitution(size_t _geneIndex, string _geneValue) +{ + return [=](Chromosome const& _chromosome) + { + vector newGenes = _chromosome.optimisationSteps(); + assert(_geneIndex < newGenes.size()); + newGenes[_geneIndex] = _geneValue; + + return Chromosome(newGenes); + }; +} + +vector phaser::test::chromosomeLengths(Population const& _population) +{ + vector lengths; + for (auto const& individual: _population.individuals()) + lengths.push_back(individual.chromosome.length()); + + return lengths; +} + +map phaser::test::enumerateOptmisationSteps() +{ + map stepIndices; + size_t i = 0; + for (auto const& nameAndAbbreviation: OptimiserSuite::stepNameToAbbreviationMap()) + stepIndices.insert({nameAndAbbreviation.first, i++}); + + return stepIndices; +} + +size_t phaser::test::countDifferences(Chromosome const& _chromosome1, Chromosome const& _chromosome2) +{ + size_t count = 0; + for (size_t i = 0; i < min(_chromosome1.length(), _chromosome2.length()); ++i) + count += static_cast(_chromosome1.optimisationSteps()[i] != _chromosome2.optimisationSteps()[i]); + + return count + abs(static_cast(_chromosome1.length() - _chromosome2.length())); +} + +TemporaryDirectory::TemporaryDirectory(std::string const& _prefix): + m_path((fs::temp_directory_path() / fs::unique_path(_prefix + "%%%%-%%%%-%%%%-%%%%")).string()) +{ + // Prefix should just be a file name and not contain anything that would make us step out of /tmp. + assert(fs::path(_prefix) == fs::path(_prefix).stem()); + + fs::create_directory(m_path); +} + +TemporaryDirectory::~TemporaryDirectory() +{ + // A few paranoid sanity checks just to be extra sure we're not deleting someone's homework. + assert(m_path.find(fs::temp_directory_path().string()) == 0); + assert(fs::path(m_path) != fs::temp_directory_path()); + assert(fs::path(m_path) != fs::path(m_path).root_path()); + assert(!fs::path(m_path).empty()); + + boost::system::error_code errorCode; + uintmax_t numRemoved = fs::remove_all(m_path, errorCode); + if (errorCode.value() != boost::system::errc::success) + { + cerr << "Failed to completely remove temporary directory '" << m_path << "'. "; + cerr << "Only " << numRemoved << " files were actually removed." << endl; + cerr << "Reason: " << errorCode.message() << endl; + } +} + +string TemporaryDirectory::memberPath(string const& _relativePath) const +{ + assert(fs::path(_relativePath).is_relative()); + + return (fs::path(m_path) / _relativePath).string(); +} + +string phaser::test::stripWhitespace(string const& input) +{ + regex whitespaceRegex("\\s+"); + return regex_replace(input, whitespaceRegex, ""); +} + +size_t phaser::test::countSubstringOccurrences(string const& _inputString, string const& _substring) +{ + assert(_substring.size() > 0); + + size_t count = 0; + size_t lastOccurrence = 0; + while ((lastOccurrence = _inputString.find(_substring, lastOccurrence)) != string::npos) + { + ++count; + lastOccurrence += _substring.size(); + } + + return count; +} diff --git a/test/yulPhaser/Common.h b/test/yulPhaser/TestHelpers.h similarity index 72% rename from test/yulPhaser/Common.h rename to test/yulPhaser/TestHelpers.h index e73260d7a..2bf755b18 100644 --- a/test/yulPhaser/Common.h +++ b/test/yulPhaser/TestHelpers.h @@ -30,9 +30,11 @@ #include #include +#include #include #include +#include #include #include #include @@ -49,19 +51,59 @@ class ChromosomeLengthMetric: public FitnessMetric { public: using FitnessMetric::FitnessMetric; - size_t evaluate(Chromosome const& _chromosome) const override { return _chromosome.length(); } + size_t evaluate(Chromosome const& _chromosome) override { return _chromosome.length(); } }; +// MUTATIONS + +/// Mutation that always replaces the whole chromosome with the one specified in the parameter. +std::function wholeChromosomeReplacement(Chromosome _newChromosome); + +/// Mutation that always replaces the optimisation step at position @a _geneIndex with @a _geneValue. +/// +/// The chromosome must be long enough for this position to exist. +std::function geneSubstitution(size_t _geneIndex, std::string _geneValue); + // CHROMOSOME AND POPULATION HELPERS /// Returns a vector containing lengths of all chromosomes in the population (in the same order). std::vector chromosomeLengths(Population const& _population); +/// Returns the number of genes that differ between two chromosomes. +/// If the chromnosomes have different lengths, the positions that are present in only one of them +/// are counted as mismatches. +size_t countDifferences(Chromosome const& _chromosome1, Chromosome const& _chromosome2); + /// Assigns indices from 0 to N to all optimisation steps available in the OptimiserSuite. /// This is a convenience helper to make it easier to test their distribution with tools made for /// integers. std::map enumerateOptmisationSteps(); +// FILESYSTEM UTILITIES + +/** + * An object that creates a unique temporary directory and automatically deletes it and its + * content upon being destroyed. + * + * The directory is guaranteed to be newly created and empty. Directory names are generated + * randomly. If a directory with the same name already exists (very unlikely but possible) the + * object won't reuse it and will fail with an exception instead. + */ +class TemporaryDirectory +{ +public: + TemporaryDirectory(std::string const& _prefix = "yul-phaser-test-"); + ~TemporaryDirectory(); + + std::string const& path() const { return m_path; } + + /// Converts a path relative to the directory held by the object into an absolute one. + std::string memberPath(std::string const& _relativePath) const; + +private: + std::string m_path; +}; + // STRING UTILITIES /// Returns the input string with all the whitespace characters (spaces, line endings, etc.) removed. diff --git a/test/yulPhaser/CommonTest.cpp b/test/yulPhaser/TestHelpersTest.cpp similarity index 54% rename from test/yulPhaser/CommonTest.cpp rename to test/yulPhaser/TestHelpersTest.cpp index 9bcab9923..7fc4ef0af 100644 --- a/test/yulPhaser/CommonTest.cpp +++ b/test/yulPhaser/TestHelpersTest.cpp @@ -15,23 +15,27 @@ along with solidity. If not, see . */ -#include +#include #include +#include #include +#include #include using namespace std; using namespace solidity::yul; using namespace boost::test_tools; +namespace fs = boost::filesystem; + namespace solidity::phaser::test { BOOST_AUTO_TEST_SUITE(Phaser) -BOOST_AUTO_TEST_SUITE(CommonTest) +BOOST_AUTO_TEST_SUITE(TestHelpersTest) BOOST_AUTO_TEST_CASE(ChromosomeLengthMetric_evaluate_should_return_chromosome_length) { @@ -40,6 +44,23 @@ BOOST_AUTO_TEST_CASE(ChromosomeLengthMetric_evaluate_should_return_chromosome_le BOOST_TEST(ChromosomeLengthMetric{}.evaluate(Chromosome("aaaaa")) == 5); } +BOOST_AUTO_TEST_CASE(wholeChromosomeReplacement_should_replace_whole_chromosome_with_another) +{ + function mutation = wholeChromosomeReplacement(Chromosome("aaa")); + BOOST_TEST(mutation(Chromosome("ccc")) == Chromosome("aaa")); +} + +BOOST_AUTO_TEST_CASE(geneSubstitution_should_change_a_single_gene_at_a_given_index) +{ + Chromosome chromosome("aaccff"); + + function mutation1 = geneSubstitution(0, chromosome.optimisationSteps()[5]); + BOOST_TEST(mutation1(chromosome) == Chromosome("faccff")); + + function mutation2 = geneSubstitution(5, chromosome.optimisationSteps()[0]); + BOOST_TEST(mutation2(chromosome) == Chromosome("aaccfa")); +} + BOOST_AUTO_TEST_CASE(chromosomeLengths_should_return_lengths_of_all_chromosomes_in_a_population) { shared_ptr fitnessMetric = make_shared(); @@ -51,6 +72,34 @@ BOOST_AUTO_TEST_CASE(chromosomeLengths_should_return_lengths_of_all_chromosomes_ BOOST_TEST((chromosomeLengths(population2) == vector{})); } +BOOST_AUTO_TEST_CASE(countDifferences_should_return_zero_for_identical_chromosomes) +{ + BOOST_TEST(countDifferences(Chromosome(), Chromosome()) == 0); + BOOST_TEST(countDifferences(Chromosome("a"), Chromosome("a")) == 0); + BOOST_TEST(countDifferences(Chromosome("afxT"), Chromosome("afxT")) == 0); +} + +BOOST_AUTO_TEST_CASE(countDifferences_should_count_mismatched_positions_in_chromosomes_of_the_same_length) +{ + BOOST_TEST(countDifferences(Chromosome("a"), Chromosome("f")) == 1); + BOOST_TEST(countDifferences(Chromosome("aa"), Chromosome("ac")) == 1); + BOOST_TEST(countDifferences(Chromosome("ac"), Chromosome("cc")) == 1); + BOOST_TEST(countDifferences(Chromosome("aa"), Chromosome("cc")) == 2); + BOOST_TEST(countDifferences(Chromosome("afxT"), Chromosome("Txfa")) == 4); +} + +BOOST_AUTO_TEST_CASE(countDifferences_should_count_missing_characters_as_differences) +{ + BOOST_TEST(countDifferences(Chromosome(""), Chromosome("a")) == 1); + BOOST_TEST(countDifferences(Chromosome("a"), Chromosome("")) == 1); + BOOST_TEST(countDifferences(Chromosome("aa"), Chromosome("")) == 2); + BOOST_TEST(countDifferences(Chromosome("aaa"), Chromosome("")) == 3); + + BOOST_TEST(countDifferences(Chromosome("aa"), Chromosome("aaaa")) == 2); + BOOST_TEST(countDifferences(Chromosome("aa"), Chromosome("aacc")) == 2); + BOOST_TEST(countDifferences(Chromosome("aa"), Chromosome("cccc")) == 4); +} + BOOST_AUTO_TEST_CASE(enumerateOptimisationSteps_should_assing_indices_to_all_available_optimisation_steps) { map stepsAndAbbreviations = OptimiserSuite::stepNameToAbbreviationMap(); @@ -69,6 +118,63 @@ BOOST_AUTO_TEST_CASE(enumerateOptimisationSteps_should_assing_indices_to_all_ava } } +BOOST_AUTO_TEST_CASE(TemporaryDirectory_should_create_and_delete_a_unique_and_empty_directory) +{ + fs::path dirPath; + { + TemporaryDirectory tempDir("temporary-directory-test-"); + dirPath = tempDir.path(); + + BOOST_TEST(dirPath.stem().string().find("temporary-directory-test-") == 0); + BOOST_TEST(fs::equivalent(dirPath.parent_path(), fs::temp_directory_path())); + BOOST_TEST(fs::is_directory(dirPath)); + BOOST_TEST(fs::is_empty(dirPath)); + } + BOOST_TEST(!fs::exists(dirPath)); +} + +BOOST_AUTO_TEST_CASE(TemporaryDirectory_should_delete_its_directory_even_if_not_empty) +{ + fs::path dirPath; + { + TemporaryDirectory tempDir("temporary-directory-test-"); + dirPath = tempDir.path(); + + BOOST_TEST(fs::is_directory(dirPath)); + + { + ofstream tmpFile((dirPath / "test-file.txt").string()); + tmpFile << "Delete me!" << endl; + } + assert(fs::is_regular_file(dirPath / "test-file.txt")); + } + BOOST_TEST(!fs::exists(dirPath / "test-file.txt")); +} + +BOOST_AUTO_TEST_CASE(TemporaryDirectory_memberPath_should_construct_paths_relative_to_the_temporary_directory) +{ + TemporaryDirectory tempDir("temporary-directory-test-"); + + BOOST_TEST(fs::equivalent(tempDir.memberPath(""), tempDir.path())); + BOOST_TEST(fs::equivalent(tempDir.memberPath("."), tempDir.path() / fs::path("."))); + BOOST_TEST(fs::equivalent(tempDir.memberPath(".."), tempDir.path() / fs::path(".."))); + + // NOTE: fs::equivalent() only works with paths that actually exist + { + ofstream file; + file.open(tempDir.memberPath("file.txt"), ios::out); + } + BOOST_TEST(fs::equivalent(tempDir.memberPath("file.txt"), tempDir.path() / fs::path("file.txt"))); + + { + fs::create_directories(tempDir.memberPath("a/b/")); + + ofstream file; + file.open(tempDir.memberPath("a/b/file.txt"), ios::out); + } + BOOST_TEST(fs::equivalent(tempDir.memberPath("a/b/file.txt"), tempDir.path() / fs::path("a") / fs::path("b") / fs::path("file.txt"))); +} + BOOST_AUTO_TEST_CASE(stripWhitespace_should_remove_all_whitespace_characters_from_a_string) { BOOST_TEST(stripWhitespace("") == ""); diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 21c0b8c91..fd5f92bbe 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -15,6 +15,12 @@ install(TARGETS solidity-upgrade DESTINATION "${CMAKE_INSTALL_BINDIR}") add_executable(yul-phaser yulPhaser/main.cpp + yulPhaser/Common.h + yulPhaser/Common.cpp + yulPhaser/AlgorithmRunner.h + yulPhaser/AlgorithmRunner.cpp + yulPhaser/Phaser.h + yulPhaser/Phaser.cpp yulPhaser/GeneticAlgorithms.h yulPhaser/GeneticAlgorithms.cpp yulPhaser/Population.h @@ -23,6 +29,10 @@ add_executable(yul-phaser yulPhaser/FitnessMetrics.cpp yulPhaser/Chromosome.h yulPhaser/Chromosome.cpp + yulPhaser/Mutations.h + yulPhaser/Mutations.cpp + yulPhaser/PairSelections.h + yulPhaser/PairSelections.cpp yulPhaser/Selections.h yulPhaser/Selections.cpp yulPhaser/Program.h diff --git a/tools/yulPhaser/AlgorithmRunner.cpp b/tools/yulPhaser/AlgorithmRunner.cpp new file mode 100644 index 000000000..b9f22171b --- /dev/null +++ b/tools/yulPhaser/AlgorithmRunner.cpp @@ -0,0 +1,105 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ + +#include + +#include + +#include + +#include +#include +#include + +using namespace std; +using namespace solidity::phaser; + +void AlgorithmRunner::run(GeneticAlgorithm& _algorithm) +{ + populationAutosave(); + + for (size_t round = 0; !m_options.maxRounds.has_value() || round < m_options.maxRounds.value(); ++round) + { + m_population = _algorithm.runNextRound(m_population); + randomiseDuplicates(); + + m_outputStream << "---------- ROUND " << round + 1 << " ----------" << endl; + m_outputStream << m_population; + + populationAutosave(); + } +} + +void AlgorithmRunner::populationAutosave() const +{ + if (!m_options.populationAutosaveFile.has_value()) + return; + + ofstream outputStream(m_options.populationAutosaveFile.value(), ios::out | ios::trunc); + assertThrow( + outputStream.is_open(), + FileOpenError, + "Could not open file '" + m_options.populationAutosaveFile.value() + "': " + strerror(errno) + ); + + for (auto& individual: m_population.individuals()) + outputStream << individual.chromosome << endl; + + assertThrow( + !outputStream.bad(), + FileWriteError, + "Error while writing to file '" + m_options.populationAutosaveFile.value() + "': " + strerror(errno) + ); +} + +void AlgorithmRunner::randomiseDuplicates() +{ + if (m_options.randomiseDuplicates) + { + assert(m_options.minChromosomeLength.has_value()); + assert(m_options.maxChromosomeLength.has_value()); + + m_population = randomiseDuplicates( + m_population, + m_options.minChromosomeLength.value(), + m_options.maxChromosomeLength.value() + ); + } +} + +Population AlgorithmRunner::randomiseDuplicates( + Population _population, + size_t _minChromosomeLength, + size_t _maxChromosomeLength +) +{ + if (_population.individuals().size() == 0) + return _population; + + vector chromosomes{_population.individuals()[0].chromosome}; + size_t duplicateCount = 0; + for (size_t i = 1; i < _population.individuals().size(); ++i) + if (_population.individuals()[i].chromosome == _population.individuals()[i - 1].chromosome) + ++duplicateCount; + else + chromosomes.push_back(_population.individuals()[i].chromosome); + + return ( + Population(_population.fitnessMetric(), chromosomes) + + Population::makeRandom(_population.fitnessMetric(), duplicateCount, _minChromosomeLength, _maxChromosomeLength) + ); +} diff --git a/tools/yulPhaser/AlgorithmRunner.h b/tools/yulPhaser/AlgorithmRunner.h new file mode 100644 index 000000000..ff0d0e3c3 --- /dev/null +++ b/tools/yulPhaser/AlgorithmRunner.h @@ -0,0 +1,79 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +/** + * Contains the implementation of a class that manages the execution of a genetic algorithm. + */ + +#pragma once + +#include +#include + +#include +#include + +namespace solidity::phaser +{ + +/** + * Manages a population and executes a genetic algorithm on it. It's independent of the + * implementation details of a specific algorithm which is pluggable via @a GeneticAlgorithm class. + * + * The class is also responsible for providing text feedback on the execution of the algorithm + * to the associated output stream. + */ +class AlgorithmRunner +{ +public: + struct Options + { + std::optional maxRounds = std::nullopt; + std::optional populationAutosaveFile = std::nullopt; + bool randomiseDuplicates = false; + std::optional minChromosomeLength = std::nullopt; + std::optional maxChromosomeLength = std::nullopt; + }; + + AlgorithmRunner( + Population _initialPopulation, + Options _options, + std::ostream& _outputStream + ): + m_population(std::move(_initialPopulation)), + m_options(std::move(_options)), + m_outputStream(_outputStream) {} + + void run(GeneticAlgorithm& _algorithm); + + Options const& options() const { return m_options; } + Population const& population() const { return m_population; } + +private: + void populationAutosave() const; + void randomiseDuplicates(); + static Population randomiseDuplicates( + Population _population, + size_t _minChromosomeLength, + size_t _maxChromosomeLength + ); + + Population m_population; + Options m_options; + std::ostream& m_outputStream; +}; + +} diff --git a/tools/yulPhaser/Common.cpp b/tools/yulPhaser/Common.cpp new file mode 100644 index 000000000..aa7ba85b5 --- /dev/null +++ b/tools/yulPhaser/Common.cpp @@ -0,0 +1,45 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ + +#include + +#include + +#include + +#include +#include +#include + +using namespace std; +using namespace solidity; +using namespace solidity::phaser; + +vector phaser::readLinesFromFile(string const& _path) +{ + ifstream inputStream(_path); + assertThrow(inputStream.is_open(), FileOpenError, "Could not open file '" + _path + "': " + strerror(errno)); + + string line; + vector lines; + while (!getline(inputStream, line).fail()) + lines.push_back(line); + + assertThrow(!inputStream.bad(), FileReadError, "Error while reading from file '" + _path + "': " + strerror(errno)); + + return lines; +} diff --git a/tools/yulPhaser/Common.h b/tools/yulPhaser/Common.h new file mode 100644 index 000000000..c37afa2fb --- /dev/null +++ b/tools/yulPhaser/Common.h @@ -0,0 +1,77 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +/** + * Miscellaneous utilities for use in yul-phaser. + */ + +#pragma once + +#include +#include +#include +#include + +namespace solidity::phaser +{ + +/// Loads the whole file into memory, splits the content into lines, strips newlines and +/// returns the result as a list of strings. +/// +/// Throws FileOpenError if the file does not exist or cannot be opened for reading. +/// Throws FileReadError if any read operation fails during the whole process. +std::vector readLinesFromFile(std::string const& _path); + +/// Reads a token from the input stream and translates it to a string using a map. +/// Sets the failbit in the stream if there's no matching value in the map. +template +std::istream& deserializeChoice( + std::istream& _inputStream, + C& _choice, + std::map const& _stringToValueMap +) +{ + std::string deserializedValue; + _inputStream >> deserializedValue; + + auto const& pair = _stringToValueMap.find(deserializedValue); + if (pair != _stringToValueMap.end()) + _choice = pair->second; + else + _inputStream.setstate(std::ios_base::failbit); + + return _inputStream; +} + +/// Translates a value to a string using a map and prints it to the output stream. +/// Sets the failbit if the value is not in the map. +template +std::ostream& serializeChoice( + std::ostream& _outputStream, + C const& _choice, + std::map const& _valueToStringMap +) +{ + auto const& pair = _valueToStringMap.find(_choice); + if (pair != _valueToStringMap.end()) + _outputStream << pair->second; + else + _outputStream.setstate(std::ios_base::failbit); + + return _outputStream; +} + +} diff --git a/tools/yulPhaser/Exceptions.h b/tools/yulPhaser/Exceptions.h index ae75d19ef..6807d7180 100644 --- a/tools/yulPhaser/Exceptions.h +++ b/tools/yulPhaser/Exceptions.h @@ -22,6 +22,13 @@ namespace solidity::phaser { -struct InvalidProgram: virtual util::Exception {}; +struct BadInput: virtual util::Exception {}; +struct InvalidProgram: virtual BadInput {}; +struct NoInputFiles: virtual BadInput {}; +struct MissingFile: virtual BadInput {}; + +struct FileOpenError: virtual util::Exception {}; +struct FileReadError: virtual util::Exception {}; +struct FileWriteError: virtual util::Exception {}; } diff --git a/tools/yulPhaser/FitnessMetrics.cpp b/tools/yulPhaser/FitnessMetrics.cpp index be7ea5497..49482d0af 100644 --- a/tools/yulPhaser/FitnessMetrics.cpp +++ b/tools/yulPhaser/FitnessMetrics.cpp @@ -17,14 +17,80 @@ #include +#include + using namespace std; using namespace solidity::phaser; -size_t ProgramSize::evaluate(Chromosome const& _chromosome) const +Program ProgramBasedMetric::optimisedProgram(Chromosome const& _chromosome) const { Program programCopy = m_program; for (size_t i = 0; i < m_repetitionCount; ++i) programCopy.optimise(_chromosome.optimisationSteps()); - return programCopy.codeSize(); + return programCopy; +} + +size_t ProgramSize::evaluate(Chromosome const& _chromosome) +{ + return optimisedProgram(_chromosome).codeSize(); +} + +size_t RelativeProgramSize::evaluate(Chromosome const& _chromosome) +{ + size_t const scalingFactor = pow(10, m_fixedPointPrecision); + + size_t unoptimisedSize = optimisedProgram(Chromosome("")).codeSize(); + if (unoptimisedSize == 0) + return scalingFactor; + + size_t optimisedSize = optimisedProgram(_chromosome).codeSize(); + + return static_cast(round( + static_cast(optimisedSize) / unoptimisedSize * scalingFactor + )); +} + +size_t FitnessMetricAverage::evaluate(Chromosome const& _chromosome) +{ + assert(m_metrics.size() > 0); + + size_t total = m_metrics[0]->evaluate(_chromosome); + for (size_t i = 1; i < m_metrics.size(); ++i) + total += m_metrics[i]->evaluate(_chromosome); + + return total / m_metrics.size(); +} + +size_t FitnessMetricSum::evaluate(Chromosome const& _chromosome) +{ + assert(m_metrics.size() > 0); + + size_t total = m_metrics[0]->evaluate(_chromosome); + for (size_t i = 1; i < m_metrics.size(); ++i) + total += m_metrics[i]->evaluate(_chromosome); + + return total; +} + +size_t FitnessMetricMaximum::evaluate(Chromosome const& _chromosome) +{ + assert(m_metrics.size() > 0); + + size_t maximum = m_metrics[0]->evaluate(_chromosome); + for (size_t i = 1; i < m_metrics.size(); ++i) + maximum = max(maximum, m_metrics[i]->evaluate(_chromosome)); + + return maximum; +} + +size_t FitnessMetricMinimum::evaluate(Chromosome const& _chromosome) +{ + assert(m_metrics.size() > 0); + + size_t minimum = m_metrics[0]->evaluate(_chromosome); + for (size_t i = 1; i < m_metrics.size(); ++i) + minimum = min(minimum, m_metrics[i]->evaluate(_chromosome)); + + return minimum; } diff --git a/tools/yulPhaser/FitnessMetrics.h b/tools/yulPhaser/FitnessMetrics.h index 7fac5f080..e79d99ff4 100644 --- a/tools/yulPhaser/FitnessMetrics.h +++ b/tools/yulPhaser/FitnessMetrics.h @@ -43,25 +43,130 @@ public: FitnessMetric& operator=(FitnessMetric const&) = delete; virtual ~FitnessMetric() = default; - virtual size_t evaluate(Chromosome const& _chromosome) const = 0; + virtual size_t evaluate(Chromosome const& _chromosome) = 0; }; /** - * Fitness metric based on the size of a specific program after applying the optimisations from the - * chromosome to it. + * Abstract base class for fitness metrics that return values based on program size. + * + * The class provides utilities for optimising programs according to the information stored in + * chromosomes. + * + * It can also store weights for the @a CodeSize metric. It does not do anything with + * them because it does not actually compute the code size but they are readily available for use + * by derived classes. */ -class ProgramSize: public FitnessMetric +class ProgramBasedMetric: public FitnessMetric { public: - explicit ProgramSize(Program _program, size_t _repetitionCount = 1): + explicit ProgramBasedMetric( + Program _program, + size_t _repetitionCount = 1 + ): m_program(std::move(_program)), m_repetitionCount(_repetitionCount) {} - size_t evaluate(Chromosome const& _chromosome) const override; + Program const& program() const { return m_program; } + size_t repetitionCount() const { return m_repetitionCount; } + + Program optimisedProgram(Chromosome const& _chromosome) const; private: Program m_program; size_t m_repetitionCount; }; +/** + * Fitness metric based on the size of a specific program after applying the optimisations from the + * chromosome to it. + */ +class ProgramSize: public ProgramBasedMetric +{ +public: + using ProgramBasedMetric::ProgramBasedMetric; + size_t evaluate(Chromosome const& _chromosome) override; +}; + +/** + * Fitness metric based on the size of a specific program after applying the optimisations from the + * chromosome to it in relation to the original, unoptimised program. + * + * Since metric values are integers, the class multiplies the ratio by 10^@a _fixedPointPrecision + * before rounding it. + */ +class RelativeProgramSize: public ProgramBasedMetric +{ +public: + explicit RelativeProgramSize( + Program _program, + size_t _fixedPointPrecision, + size_t _repetitionCount = 1 + ): + ProgramBasedMetric(std::move(_program), _repetitionCount), + m_fixedPointPrecision(_fixedPointPrecision) {} + + size_t fixedPointPrecision() const { return m_fixedPointPrecision; } + + size_t evaluate(Chromosome const& _chromosome) override; + +private: + size_t m_fixedPointPrecision; +}; + +/** + * Abstract base class for fitness metrics that compute their value based on values of multiple + * other, nested metrics. + */ +class FitnessMetricCombination: public FitnessMetric +{ +public: + explicit FitnessMetricCombination(std::vector> _metrics): + m_metrics(std::move(_metrics)) {} + + std::vector> const& metrics() const { return m_metrics; } + +protected: + std::vector> m_metrics; +}; + +/** + * Fitness metric that returns the average of values of its nested metrics. + */ +class FitnessMetricAverage: public FitnessMetricCombination +{ +public: + using FitnessMetricCombination::FitnessMetricCombination; + size_t evaluate(Chromosome const& _chromosome) override; +}; + +/** + * Fitness metric that returns the sum of values of its nested metrics. + */ +class FitnessMetricSum: public FitnessMetricCombination +{ +public: + using FitnessMetricCombination::FitnessMetricCombination; + size_t evaluate(Chromosome const& _chromosome) override; +}; + +/** + * Fitness metric that returns the highest of values of its nested metrics. + */ +class FitnessMetricMaximum: public FitnessMetricCombination +{ +public: + using FitnessMetricCombination::FitnessMetricCombination; + size_t evaluate(Chromosome const& _chromosome) override; +}; + +/** + * Fitness metric that returns the lowest of values of its nested metrics. + */ +class FitnessMetricMinimum: public FitnessMetricCombination +{ +public: + using FitnessMetricCombination::FitnessMetricCombination; + size_t evaluate(Chromosome const& _chromosome) override; +}; + } diff --git a/tools/yulPhaser/GeneticAlgorithms.cpp b/tools/yulPhaser/GeneticAlgorithms.cpp index 756a410f7..432f3fe38 100644 --- a/tools/yulPhaser/GeneticAlgorithms.cpp +++ b/tools/yulPhaser/GeneticAlgorithms.cpp @@ -16,35 +16,51 @@ */ #include +#include #include +#include using namespace std; using namespace solidity::phaser; -void GeneticAlgorithm::run(optional _numRounds) -{ - for (size_t round = 0; !_numRounds.has_value() || round < _numRounds.value(); ++round) - { - runNextRound(); - - m_outputStream << "---------- ROUND " << round << " ----------" << endl; - m_outputStream << m_population; - } -} - -void RandomAlgorithm::runNextRound() +Population RandomAlgorithm::runNextRound(Population _population) { RangeSelection elite(0.0, m_options.elitePoolSize); - Population elitePopulation = m_population.select(elite); - size_t replacementCount = m_population.individuals().size() - elitePopulation.individuals().size(); + Population elitePopulation = _population.select(elite); + size_t replacementCount = _population.individuals().size() - elitePopulation.individuals().size(); - m_population = + return move(elitePopulation) + Population::makeRandom( - m_population.fitnessMetric(), + _population.fitnessMetric(), replacementCount, m_options.minChromosomeLength, m_options.maxChromosomeLength ); } + +Population GenerationalElitistWithExclusivePools::runNextRound(Population _population) +{ + double elitePoolSize = 1.0 - (m_options.mutationPoolSize + m_options.crossoverPoolSize); + RangeSelection elite(0.0, elitePoolSize); + + return + _population.select(elite) + + _population.select(elite).mutate( + RandomSelection(m_options.mutationPoolSize / elitePoolSize), + alternativeMutations( + m_options.randomisationChance, + geneRandomisation(m_options.percentGenesToRandomise), + alternativeMutations( + m_options.deletionVsAdditionChance, + geneDeletion(m_options.percentGenesToAddOrDelete), + geneAddition(m_options.percentGenesToAddOrDelete) + ) + ) + ) + + _population.select(elite).crossover( + RandomPairSelection(m_options.crossoverPoolSize / elitePoolSize), + randomPointCrossover() + ); +} diff --git a/tools/yulPhaser/GeneticAlgorithms.h b/tools/yulPhaser/GeneticAlgorithms.h index a7600d894..a2a7484d6 100644 --- a/tools/yulPhaser/GeneticAlgorithms.h +++ b/tools/yulPhaser/GeneticAlgorithms.h @@ -22,45 +22,25 @@ #include -#include -#include - namespace solidity::phaser { /** * Abstract base class for genetic algorithms. - * - * The main feature is the @a run() method that executes the algorithm, updating the internal - * population during each round and printing the results to the stream provided to the constructor. - * - * Derived classes can provide specific methods for updating the population by implementing - * the @a runNextRound() method. + * The main feature is the @a runNextRound() method that executes one round of the algorithm, + * on the supplied population. */ class GeneticAlgorithm { public: - GeneticAlgorithm(Population _initialPopulation, std::ostream& _outputStream): - m_population(std::move(_initialPopulation)), - m_outputStream(_outputStream) {} - + GeneticAlgorithm() {} GeneticAlgorithm(GeneticAlgorithm const&) = delete; GeneticAlgorithm& operator=(GeneticAlgorithm const&) = delete; virtual ~GeneticAlgorithm() = default; - Population const& population() const { return m_population; } - - void run(std::optional _numRounds = std::nullopt); - /// The method that actually implements the algorithm. Should use @a m_population as input and /// replace it with the updated state after the round. - virtual void runNextRound() = 0; - -protected: - Population m_population; - -private: - std::ostream& m_outputStream; + virtual Population runNextRound(Population _population) = 0; }; /** @@ -95,18 +75,65 @@ public: } }; - explicit RandomAlgorithm( - Population _initialPopulation, - std::ostream& _outputStream, - Options const& _options - ): - GeneticAlgorithm(_initialPopulation, _outputStream), + explicit RandomAlgorithm(Options const& _options): m_options(_options) { assert(_options.isValid()); } - void runNextRound() override; + Options const& options() const { return m_options; } + + Population runNextRound(Population _population) override; + +private: + Options m_options; +}; + +/** + * A generational, elitist genetic algorithm that replaces the population by mutating and crossing + * over chromosomes from the elite. + * + * The elite consists of individuals not included in the crossover and mutation pools. + * The crossover operator used is @a randomPointCrossover. The mutation operator is randomly chosen + * from three possibilities: @a geneRandomisation, @a geneDeletion or @a geneAddition (with + * configurable probabilities). Each mutation also has a parameter determining the chance of a gene + * being affected by it. + */ +class GenerationalElitistWithExclusivePools: public GeneticAlgorithm +{ +public: + struct Options + { + double mutationPoolSize; ///< Percentage of population to regenerate using mutations in each round. + double crossoverPoolSize; ///< Percentage of population to regenerate using crossover in each round. + double randomisationChance; ///< The chance of choosing @a geneRandomisation as the mutation to perform + double deletionVsAdditionChance; ///< The chance of choosing @a geneDeletion as the mutation if randomisation was not chosen. + double percentGenesToRandomise; ///< The chance of any given gene being mutated in gene randomisation. + double percentGenesToAddOrDelete; ///< The chance of a gene being added (or deleted) in gene addition (or deletion). + + bool isValid() const + { + return ( + 0 <= mutationPoolSize && mutationPoolSize <= 1.0 && + 0 <= crossoverPoolSize && crossoverPoolSize <= 1.0 && + 0 <= randomisationChance && randomisationChance <= 1.0 && + 0 <= deletionVsAdditionChance && deletionVsAdditionChance <= 1.0 && + 0 <= percentGenesToRandomise && percentGenesToRandomise <= 1.0 && + 0 <= percentGenesToAddOrDelete && percentGenesToAddOrDelete <= 1.0 && + mutationPoolSize + crossoverPoolSize <= 1.0 + ); + } + }; + + GenerationalElitistWithExclusivePools(Options const& _options): + m_options(_options) + { + assert(_options.isValid()); + } + + Options const& options() const { return m_options; } + + Population runNextRound(Population _population) override; private: Options m_options; diff --git a/tools/yulPhaser/Mutations.cpp b/tools/yulPhaser/Mutations.cpp new file mode 100644 index 000000000..86f815198 --- /dev/null +++ b/tools/yulPhaser/Mutations.cpp @@ -0,0 +1,147 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ + +#include + +#include + +#include + +#include +#include +#include +#include +#include + +using namespace std; +using namespace solidity; +using namespace solidity::phaser; + +function phaser::geneRandomisation(double _chance) +{ + return [=](Chromosome const& _chromosome) + { + vector optimisationSteps; + for (auto const& step: _chromosome.optimisationSteps()) + optimisationSteps.push_back( + SimulationRNG::bernoulliTrial(_chance) ? + Chromosome::randomOptimisationStep() : + step + ); + + return Chromosome(move(optimisationSteps)); + }; +} + +function phaser::geneDeletion(double _chance) +{ + return [=](Chromosome const& _chromosome) + { + vector optimisationSteps; + for (auto const& step: _chromosome.optimisationSteps()) + if (!SimulationRNG::bernoulliTrial(_chance)) + optimisationSteps.push_back(step); + + return Chromosome(move(optimisationSteps)); + }; +} + +function phaser::geneAddition(double _chance) +{ + return [=](Chromosome const& _chromosome) + { + vector optimisationSteps; + + if (SimulationRNG::bernoulliTrial(_chance)) + optimisationSteps.push_back(Chromosome::randomOptimisationStep()); + + for (auto const& step: _chromosome.optimisationSteps()) + { + optimisationSteps.push_back(step); + if (SimulationRNG::bernoulliTrial(_chance)) + optimisationSteps.push_back(Chromosome::randomOptimisationStep()); + } + + return Chromosome(move(optimisationSteps)); + }; +} + +function phaser::alternativeMutations( + double _firstMutationChance, + function _mutation1, + function _mutation2 +) +{ + return [=](Chromosome const& _chromosome) + { + if (SimulationRNG::bernoulliTrial(_firstMutationChance)) + return _mutation1(_chromosome); + else + return _mutation2(_chromosome); + }; +} + +namespace +{ + +Chromosome buildChromosomesBySwappingParts( + Chromosome const& _chromosome1, + Chromosome const& _chromosome2, + size_t _crossoverPoint +) +{ + assert(_crossoverPoint <= _chromosome1.length()); + assert(_crossoverPoint <= _chromosome2.length()); + + auto begin1 = _chromosome1.optimisationSteps().begin(); + auto begin2 = _chromosome2.optimisationSteps().begin(); + + return Chromosome( + vector(begin1, begin1 + _crossoverPoint) + + vector(begin2 + _crossoverPoint, _chromosome2.optimisationSteps().end()) + ); +} + +} + +function phaser::randomPointCrossover() +{ + return [=](Chromosome const& _chromosome1, Chromosome const& _chromosome2) + { + size_t minLength = min(_chromosome1.length(), _chromosome2.length()); + + // Don't use position 0 (because this just swaps the values) unless it's the only choice. + size_t minPoint = (minLength > 0? 1 : 0); + assert(minPoint <= minLength); + + size_t randomPoint = SimulationRNG::uniformInt(minPoint, minLength); + return buildChromosomesBySwappingParts(_chromosome1, _chromosome2, randomPoint); + }; +} + +function phaser::fixedPointCrossover(double _crossoverPoint) +{ + assert(0.0 <= _crossoverPoint && _crossoverPoint <= 1.0); + + return [=](Chromosome const& _chromosome1, Chromosome const& _chromosome2) + { + size_t minLength = min(_chromosome1.length(), _chromosome2.length()); + size_t concretePoint = static_cast(round(minLength * _crossoverPoint)); + + return buildChromosomesBySwappingParts(_chromosome1, _chromosome2, concretePoint); + }; +} diff --git a/tools/yulPhaser/Mutations.h b/tools/yulPhaser/Mutations.h new file mode 100644 index 000000000..bff48c52b --- /dev/null +++ b/tools/yulPhaser/Mutations.h @@ -0,0 +1,73 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +/** + * Mutation and crossover operators for use in genetic algorithms. + */ + +#pragma once + +#include + +#include +#include + +namespace solidity::phaser +{ + +using Mutation = Chromosome(Chromosome const&); +using Crossover = Chromosome(Chromosome const&, Chromosome const&); + +// MUTATIONS + +/// Creates a mutation operator that iterates over all genes in a chromosome and with probability +/// @a _chance replaces a gene with a random one (which could also be the same as the original). +std::function geneRandomisation(double _chance); + +/// Creates a mutation operator that iterates over all genes in a chromosome and with probability +/// @a _chance deletes it. +std::function geneDeletion(double _chance); + +/// Creates a mutation operator that iterates over all positions in a chromosome (including spots +/// at the beginning and at the end of the sequence) and with probability @a _chance insert a new, +/// randomly chosen gene. +std::function geneAddition(double _chance); + +/// Creates a mutation operator that always applies one of the mutations passed to it. +/// The probability that the chosen mutation is the first one is @a _firstMutationChance. +/// randomly chosen gene. +std::function alternativeMutations( + double _firstMutationChance, + std::function _mutation1, + std::function _mutation2 +); + +// CROSSOVER + +/// Creates a crossover operator that randomly selects a number between 0 and 1 and uses it as the +/// position at which to perform perform @a fixedPointCrossover. +std::function randomPointCrossover(); + +/// Creates a crossover operator that always chooses a point that lies at @a _crossoverPoint +/// percent of the length of the shorter chromosome. Then creates a new chromosome by +/// splitting both inputs at the crossover point and stitching output from the first half or first +/// input and the second half of the second input. +/// +/// Avoids selecting position 0 (since this just produces a chromosome identical to the second one) +/// unless there is no other choice (i.e. one of the chromosomes is empty). +std::function fixedPointCrossover(double _crossoverPoint); + +} diff --git a/tools/yulPhaser/PairSelections.cpp b/tools/yulPhaser/PairSelections.cpp new file mode 100644 index 000000000..8f3fd0f7f --- /dev/null +++ b/tools/yulPhaser/PairSelections.cpp @@ -0,0 +1,65 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ + +#include + +#include + +#include + +using namespace std; +using namespace solidity::phaser; + +vector> RandomPairSelection::materialise(size_t _poolSize) const +{ + if (_poolSize < 2) + return {}; + + size_t count = static_cast(round(_poolSize * m_selectionSize)); + + vector> selection; + for (size_t i = 0; i < count; ++i) + { + size_t index1 = SimulationRNG::uniformInt(0, _poolSize - 1); + size_t index2; + do + { + index2 = SimulationRNG::uniformInt(0, _poolSize - 1); + } while (index1 == index2); + + selection.push_back({index1, index2}); + } + + return selection; +} + +vector> PairMosaicSelection::materialise(size_t _poolSize) const +{ + if (_poolSize < 2) + return {}; + + size_t count = static_cast(round(_poolSize * m_selectionSize)); + + vector> selection; + for (size_t i = 0; i < count; ++i) + { + tuple pair = m_pattern[i % m_pattern.size()]; + selection.push_back({min(get<0>(pair), _poolSize - 1), min(get<1>(pair), _poolSize - 1)}); + } + + return selection; +} diff --git a/tools/yulPhaser/PairSelections.h b/tools/yulPhaser/PairSelections.h new file mode 100644 index 000000000..7778d6567 --- /dev/null +++ b/tools/yulPhaser/PairSelections.h @@ -0,0 +1,99 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +/** + * Contains an abstract base class representing a selection of pairs of elements from a collection + * and its concrete implementations. + */ + +#pragma once + +#include +#include +#include + +namespace solidity::phaser +{ + +/** + * Abstract base class for selections of pairs elements from a collection. + * + * An instance of this class represents a specific method of selecting a set of pairs of elements + * from containers of arbitrary sizes. The selected pairs always point at a subset of the elements + * from the container but may indicate the same element more than once. The pairs themselves can + * repeat too. The selection may or may not be fixed - it's up to a specific implementation whether + * subsequent calls for the same container produce the same indices or not. + * + * Derived classes are meant to override the @a materialise() method. + * This method is expected to produce pairs of selected elements given the size of the collection. + */ +class PairSelection +{ +public: + PairSelection() = default; + PairSelection(PairSelection const&) = delete; + PairSelection& operator=(PairSelection const&) = delete; + virtual ~PairSelection() = default; + + virtual std::vector> materialise(size_t _poolSize) const = 0; +}; + +/** + * A selection that selects pairs of random elements from a container. The resulting set of pairs + * may contain the same pair more than once but does not contain pairs of duplicates. Always + * selects as many pairs as the size of the container multiplied by @a _selectionSize (unless the + * container is empty). + */ +class RandomPairSelection: public PairSelection +{ +public: + explicit RandomPairSelection(double _selectionSize): + m_selectionSize(_selectionSize) {} + + std::vector> materialise(size_t _poolSize) const override; + +private: + double m_selectionSize; +}; + +/** + * A selection that selects pairs of elements at specific, fixed positions indicated by a repeating + * "pattern". If the positions in the pattern exceed the size of the container, they are capped at + * the maximum available position. Always selects as many pairs as the size of the container + * multiplied by @a _selectionSize (unless the container is empty). + * + * E.g. if the pattern is {{0, 1}, {3, 9}} and collection size is 5, the selection will materialise + * into {{0, 1}, {3, 4}, {0, 1}, {3, 4}, {0, 1}}. If the size is 3, it will be + * {{0, 1}, {2, 2}, {0, 1}}. + */ +class PairMosaicSelection: public PairSelection +{ +public: + explicit PairMosaicSelection(std::vector> _pattern, double _selectionSize = 1.0): + m_pattern(move(_pattern)), + m_selectionSize(_selectionSize) + { + assert(m_pattern.size() > 0 || _selectionSize == 0.0); + } + + std::vector> materialise(size_t _poolSize) const override; + +private: + std::vector> m_pattern; + double m_selectionSize; +}; + +} diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp new file mode 100644 index 000000000..da0296eff --- /dev/null +++ b/tools/yulPhaser/Phaser.cpp @@ -0,0 +1,565 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include + +#include + +using namespace std; +using namespace solidity; +using namespace solidity::langutil; +using namespace solidity::util; +using namespace solidity::phaser; + +namespace po = boost::program_options; + +namespace +{ + +map const AlgorithmToStringMap = +{ + {Algorithm::Random, "random"}, + {Algorithm::GEWEP, "GEWEP"}, +}; +map const StringToAlgorithmMap = invertMap(AlgorithmToStringMap); + +map MetricChoiceToStringMap = +{ + {MetricChoice::CodeSize, "code-size"}, + {MetricChoice::RelativeCodeSize, "relative-code-size"}, +}; +map const StringToMetricChoiceMap = invertMap(MetricChoiceToStringMap); + +map const MetricAggregatorChoiceToStringMap = +{ + {MetricAggregatorChoice::Average, "average"}, + {MetricAggregatorChoice::Sum, "sum"}, + {MetricAggregatorChoice::Maximum, "maximum"}, + {MetricAggregatorChoice::Minimum, "minimum"}, +}; +map const StringToMetricAggregatorChoiceMap = invertMap(MetricAggregatorChoiceToStringMap); + +} + +istream& phaser::operator>>(istream& _inputStream, Algorithm& _algorithm) { return deserializeChoice(_inputStream, _algorithm, StringToAlgorithmMap); } +ostream& phaser::operator<<(ostream& _outputStream, Algorithm _algorithm) { return serializeChoice(_outputStream, _algorithm, AlgorithmToStringMap); } +istream& phaser::operator>>(istream& _inputStream, MetricChoice& _metric) { return deserializeChoice(_inputStream, _metric, StringToMetricChoiceMap); } +ostream& phaser::operator<<(ostream& _outputStream, MetricChoice _metric) { return serializeChoice(_outputStream, _metric, MetricChoiceToStringMap); } +istream& phaser::operator>>(istream& _inputStream, MetricAggregatorChoice& _aggregator) { return deserializeChoice(_inputStream, _aggregator, StringToMetricAggregatorChoiceMap); } +ostream& phaser::operator<<(ostream& _outputStream, MetricAggregatorChoice _aggregator) { return serializeChoice(_outputStream, _aggregator, MetricAggregatorChoiceToStringMap); } + +GeneticAlgorithmFactory::Options GeneticAlgorithmFactory::Options::fromCommandLine(po::variables_map const& _arguments) +{ + return { + _arguments["algorithm"].as(), + _arguments["min-chromosome-length"].as(), + _arguments["max-chromosome-length"].as(), + _arguments.count("random-elite-pool-size") > 0 ? + _arguments["random-elite-pool-size"].as() : + optional{}, + _arguments["gewep-mutation-pool-size"].as(), + _arguments["gewep-crossover-pool-size"].as(), + _arguments["gewep-randomisation-chance"].as(), + _arguments["gewep-deletion-vs-addition-chance"].as(), + _arguments.count("gewep-genes-to-randomise") > 0 ? + _arguments["gewep-genes-to-randomise"].as() : + optional{}, + _arguments.count("gewep-genes-to-add-or-delete") > 0 ? + _arguments["gewep-genes-to-add-or-delete"].as() : + optional{}, + }; +} + +unique_ptr GeneticAlgorithmFactory::build( + Options const& _options, + size_t _populationSize +) +{ + assert(_populationSize > 0); + + switch (_options.algorithm) + { + case Algorithm::Random: + { + double elitePoolSize = 1.0 / _populationSize; + + if (_options.randomElitePoolSize.has_value()) + elitePoolSize = _options.randomElitePoolSize.value(); + + return make_unique(RandomAlgorithm::Options{ + /* elitePoolSize = */ elitePoolSize, + /* minChromosomeLength = */ _options.minChromosomeLength, + /* maxChromosomeLength = */ _options.maxChromosomeLength, + }); + } + case Algorithm::GEWEP: + { + double percentGenesToRandomise = 1.0 / _options.maxChromosomeLength; + double percentGenesToAddOrDelete = percentGenesToRandomise; + + if (_options.gewepGenesToRandomise.has_value()) + percentGenesToRandomise = _options.gewepGenesToRandomise.value(); + if (_options.gewepGenesToAddOrDelete.has_value()) + percentGenesToAddOrDelete = _options.gewepGenesToAddOrDelete.value(); + + return make_unique(GenerationalElitistWithExclusivePools::Options{ + /* mutationPoolSize = */ _options.gewepMutationPoolSize, + /* crossoverPoolSize = */ _options.gewepCrossoverPoolSize, + /* randomisationChance = */ _options.gewepRandomisationChance, + /* deletionVsAdditionChance = */ _options.gewepDeletionVsAdditionChance, + /* percentGenesToRandomise = */ percentGenesToRandomise, + /* percentGenesToAddOrDelete = */ percentGenesToAddOrDelete, + }); + } + default: + assertThrow(false, solidity::util::Exception, "Invalid Algorithm value."); + } +} + +FitnessMetricFactory::Options FitnessMetricFactory::Options::fromCommandLine(po::variables_map const& _arguments) +{ + return { + _arguments["metric"].as(), + _arguments["metric-aggregator"].as(), + _arguments["relative-metric-scale"].as(), + _arguments["chromosome-repetitions"].as(), + }; +} + +unique_ptr FitnessMetricFactory::build( + Options const& _options, + vector _programs +) +{ + assert(_programs.size() > 0 && "Validations should prevent this from being executed with zero files."); + + vector> metrics; + switch (_options.metric) + { + case MetricChoice::CodeSize: + { + for (Program& program: _programs) + metrics.push_back(make_unique( + move(program), + _options.chromosomeRepetitions + )); + + break; + } + case MetricChoice::RelativeCodeSize: + { + for (Program& program: _programs) + metrics.push_back(make_unique( + move(program), + _options.relativeMetricScale, + _options.chromosomeRepetitions + )); + break; + } + default: + assertThrow(false, solidity::util::Exception, "Invalid MetricChoice value."); + } + + switch (_options.metricAggregator) + { + case MetricAggregatorChoice::Average: + return make_unique(move(metrics)); + case MetricAggregatorChoice::Sum: + return make_unique(move(metrics)); + case MetricAggregatorChoice::Maximum: + return make_unique(move(metrics)); + case MetricAggregatorChoice::Minimum: + return make_unique(move(metrics)); + default: + assertThrow(false, solidity::util::Exception, "Invalid MetricAggregatorChoice value."); + } +} + +PopulationFactory::Options PopulationFactory::Options::fromCommandLine(po::variables_map const& _arguments) +{ + return { + _arguments["min-chromosome-length"].as(), + _arguments["max-chromosome-length"].as(), + _arguments.count("population") > 0 ? + _arguments["population"].as>() : + vector{}, + _arguments.count("random-population") > 0 ? + _arguments["random-population"].as>() : + vector{}, + _arguments.count("population-from-file") > 0 ? + _arguments["population-from-file"].as>() : + vector{}, + }; +} + +Population PopulationFactory::build( + Options const& _options, + shared_ptr _fitnessMetric +) +{ + Population population = buildFromStrings(_options.population, _fitnessMetric); + + size_t combinedSize = 0; + for (size_t populationSize: _options.randomPopulation) + combinedSize += populationSize; + + population = move(population) + buildRandom( + combinedSize, + _options.minChromosomeLength, + _options.maxChromosomeLength, + _fitnessMetric + ); + + for (string const& populationFilePath: _options.populationFromFile) + population = move(population) + buildFromFile(populationFilePath, _fitnessMetric); + + return population; +} + +Population PopulationFactory::buildFromStrings( + vector const& _geneSequences, + shared_ptr _fitnessMetric +) +{ + vector chromosomes; + for (string const& geneSequence: _geneSequences) + chromosomes.emplace_back(geneSequence); + + return Population(move(_fitnessMetric), move(chromosomes)); +} + +Population PopulationFactory::buildRandom( + size_t _populationSize, + size_t _minChromosomeLength, + size_t _maxChromosomeLength, + shared_ptr _fitnessMetric +) +{ + return Population::makeRandom( + move(_fitnessMetric), + _populationSize, + _minChromosomeLength, + _maxChromosomeLength + ); +} + +Population PopulationFactory::buildFromFile( + string const& _filePath, + shared_ptr _fitnessMetric +) +{ + return buildFromStrings(readLinesFromFile(_filePath), move(_fitnessMetric)); +} + +ProgramFactory::Options ProgramFactory::Options::fromCommandLine(po::variables_map const& _arguments) +{ + return { + _arguments["input-files"].as>(), + }; +} + +vector ProgramFactory::build(Options const& _options) +{ + vector inputPrograms; + for (auto& path: _options.inputFiles) + { + CharStream sourceCode = loadSource(path); + variant programOrErrors = Program::load(sourceCode); + if (holds_alternative(programOrErrors)) + { + cerr << get(programOrErrors) << endl; + assertThrow(false, InvalidProgram, "Failed to load program " + path); + } + inputPrograms.push_back(move(get(programOrErrors))); + } + + return inputPrograms; +} + +CharStream ProgramFactory::loadSource(string const& _sourcePath) +{ + assertThrow(boost::filesystem::exists(_sourcePath), MissingFile, "Source file does not exist: " + _sourcePath); + + string sourceCode = readFileAsString(_sourcePath); + return CharStream(sourceCode, _sourcePath); +} + +void Phaser::main(int _argc, char** _argv) +{ + optional arguments = parseCommandLine(_argc, _argv); + if (!arguments.has_value()) + return; + + initialiseRNG(arguments.value()); + + runAlgorithm(arguments.value()); +} + +Phaser::CommandLineDescription Phaser::buildCommandLineDescription() +{ + size_t const lineLength = po::options_description::m_default_line_length; + size_t const minDescriptionLength = lineLength - 23; + + po::options_description keywordDescription( + "yul-phaser, a tool for finding the best sequence of Yul optimisation phases.\n" + "\n" + "Usage: yul-phaser [options] \n" + "Reads as Yul code and tries to find the best order in which to run optimisation" + " phases using a genetic algorithm.\n" + "Example:\n" + "yul-phaser program.yul\n" + "\n" + "Allowed options", + lineLength, + minDescriptionLength + ); + + po::options_description generalDescription("GENERAL", lineLength, minDescriptionLength); + generalDescription.add_options() + ("help", "Show help message and exit.") + ("input-files", po::value>()->required()->value_name(""), "Input files.") + ("seed", po::value()->value_name(""), "Seed for the random number generator.") + ( + "rounds", + po::value()->value_name(""), + "The number of rounds after which the algorithm should stop. (default=no limit)." + ) + ; + keywordDescription.add(generalDescription); + + po::options_description algorithmDescription("ALGORITHM", lineLength, minDescriptionLength); + algorithmDescription.add_options() + ( + "algorithm", + po::value()->value_name("")->default_value(Algorithm::GEWEP), + "Algorithm" + ) + ( + "no-randomise-duplicates", + po::bool_switch(), + "By default, after each round of the algorithm duplicate chromosomes are removed from" + "the population and replaced with randomly generated ones. " + "This option disables this postprocessing." + ) + ( + "min-chromosome-length", + po::value()->value_name("")->default_value(12), + "Minimum length of randomly generated chromosomes." + ) + ( + "max-chromosome-length", + po::value()->value_name("")->default_value(30), + "Maximum length of randomly generated chromosomes." + ) + ; + keywordDescription.add(algorithmDescription); + + po::options_description gewepAlgorithmDescription("GEWEP ALGORITHM", lineLength, minDescriptionLength); + gewepAlgorithmDescription.add_options() + ( + "gewep-mutation-pool-size", + po::value()->value_name("")->default_value(0.25), + "Percentage of population to regenerate using mutations in each round." + ) + ( + "gewep-crossover-pool-size", + po::value()->value_name("")->default_value(0.25), + "Percentage of population to regenerate using crossover in each round." + ) + ( + "gewep-randomisation-chance", + po::value()->value_name("")->default_value(0.9), + "The chance of choosing gene randomisation as the mutation to perform." + ) + ( + "gewep-deletion-vs-addition-chance", + po::value()->value_name("")->default_value(0.5), + "The chance of choosing gene deletion as the mutation if randomisation was not chosen." + ) + ( + "gewep-genes-to-randomise", + po::value()->value_name(""), + "The chance of any given gene being mutated in gene randomisation. " + "(default=1/max-chromosome-length)" + ) + ( + "gewep-genes-to-add-or-delete", + po::value()->value_name(""), + "The chance of a gene being added (or deleted) in gene addition (or deletion). " + "(default=1/max-chromosome-length)" + ) + ; + keywordDescription.add(gewepAlgorithmDescription); + + po::options_description randomAlgorithmDescription("RANDOM ALGORITHM", lineLength, minDescriptionLength); + randomAlgorithmDescription.add_options() + ( + "random-elite-pool-size", + po::value()->value_name(""), + "Percentage of the population preserved in each round. " + "(default=one individual, regardless of population size)" + ) + ; + keywordDescription.add(randomAlgorithmDescription); + + po::options_description populationDescription("POPULATION", lineLength, minDescriptionLength); + populationDescription.add_options() + ( + "population", + po::value>()->multitoken()->value_name(""), + "List of chromosomes to be included in the initial population. " + "You can specify multiple values separated with spaces or invoke the option multiple times " + "and all the values will be included." + ) + ( + "random-population", + po::value>()->value_name(""), + "The number of randomly generated chromosomes to be included in the initial population." + ) + ( + "population-from-file", + po::value>()->value_name(""), + "A text file with a list of chromosomes (one per line) to be included in the initial population." + ) + ( + "population-autosave", + po::value()->value_name(""), + "If specified, the population is saved in the specified file after each round. (default=autosave disabled)" + ) + ; + keywordDescription.add(populationDescription); + + po::options_description metricsDescription("METRICS", lineLength, minDescriptionLength); + metricsDescription.add_options() + ( + "metric", + po::value()->value_name("")->default_value(MetricChoice::RelativeCodeSize), + "Metric used to evaluate the fitness of a chromosome." + ) + ( + "metric-aggregator", + po::value()->value_name("")->default_value(MetricAggregatorChoice::Average), + "Operator used to combine multiple fitness metric obtained by evaluating a chromosome " + "separately for each input program." + ) + ( + "relative-metric-scale", + po::value()->value_name("")->default_value(3), + "Scaling factor for values produced by relative fitness metrics. \n" + "Since all metrics must produce integer values, the fractional part of the result is discarded. " + "To keep the numbers meaningful, a relative metric multiples its values by a scaling factor " + "and this option specifies the exponent of this factor. " + "For example with value of 3 the factor is 10^3 = 1000 and the metric will return " + "500 to represent 0.5, 1000 for 1.0, 2000 for 2.0 and so on. " + "Using a bigger factor allows discerning smaller relative differences between chromosomes " + "but makes the numbers less readable and may also lose precision if the numbers are very large." + ) + ( + "chromosome-repetitions", + po::value()->value_name("")->default_value(1), + "Number of times to repeat the sequence optimisation steps represented by a chromosome." + ) + ; + keywordDescription.add(metricsDescription); + + po::positional_options_description positionalDescription; + positionalDescription.add("input-files", -1); + + return {keywordDescription, positionalDescription}; +} + +optional Phaser::parseCommandLine(int _argc, char** _argv) +{ + auto [keywordDescription, positionalDescription] = buildCommandLineDescription(); + + po::variables_map arguments; + po::notify(arguments); + + po::command_line_parser parser(_argc, _argv); + parser.options(keywordDescription).positional(positionalDescription); + po::store(parser.run(), arguments); + + if (arguments.count("help") > 0) + { + cout << keywordDescription << endl; + return nullopt; + } + + if (arguments.count("input-files") == 0) + assertThrow(false, NoInputFiles, "Missing argument: input-files."); + + return arguments; +} + +void Phaser::initialiseRNG(po::variables_map const& _arguments) +{ + uint32_t seed; + if (_arguments.count("seed") > 0) + seed = _arguments["seed"].as(); + else + seed = SimulationRNG::generateSeed(); + + SimulationRNG::reset(seed); + cout << "Random seed: " << seed << endl; +} + +AlgorithmRunner::Options Phaser::buildAlgorithmRunnerOptions(po::variables_map const& _arguments) +{ + return { + _arguments.count("rounds") > 0 ? static_cast>(_arguments["rounds"].as()) : nullopt, + _arguments.count("population-autosave") > 0 ? static_cast>(_arguments["population-autosave"].as()) : nullopt, + !_arguments["no-randomise-duplicates"].as(), + _arguments["min-chromosome-length"].as(), + _arguments["max-chromosome-length"].as(), + }; +} + +void Phaser::runAlgorithm(po::variables_map const& _arguments) +{ + auto programOptions = ProgramFactory::Options::fromCommandLine(_arguments); + auto metricOptions = FitnessMetricFactory::Options::fromCommandLine(_arguments); + auto populationOptions = PopulationFactory::Options::fromCommandLine(_arguments); + auto algorithmOptions = GeneticAlgorithmFactory::Options::fromCommandLine(_arguments); + + vector programs = ProgramFactory::build(programOptions); + unique_ptr fitnessMetric = FitnessMetricFactory::build(metricOptions, move(programs)); + Population population = PopulationFactory::build(populationOptions, move(fitnessMetric)); + + unique_ptr geneticAlgorithm = GeneticAlgorithmFactory::build( + algorithmOptions, + population.individuals().size() + ); + + AlgorithmRunner algorithmRunner(population, buildAlgorithmRunnerOptions(_arguments), cout); + algorithmRunner.run(*geneticAlgorithm); +} diff --git a/tools/yulPhaser/Phaser.h b/tools/yulPhaser/Phaser.h new file mode 100644 index 000000000..2e72c31f6 --- /dev/null +++ b/tools/yulPhaser/Phaser.h @@ -0,0 +1,207 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +/** + * Contains the main class that controls yul-phaser based on command-line parameters and + * associated factories for building instances of phaser's components. + */ + +#pragma once + +#include + +#include + +#include +#include +#include +#include +#include + +namespace solidity::langutil +{ + +class CharStream; + +} + +namespace solidity::phaser +{ + +class FitnessMetric; +class GeneticAlgorithm; +class Population; +class Program; + +enum class Algorithm +{ + Random, + GEWEP, +}; + +enum class MetricChoice +{ + CodeSize, + RelativeCodeSize, +}; + +enum class MetricAggregatorChoice +{ + Average, + Sum, + Maximum, + Minimum, +}; + +std::istream& operator>>(std::istream& _inputStream, solidity::phaser::Algorithm& _algorithm); +std::ostream& operator<<(std::ostream& _outputStream, solidity::phaser::Algorithm _algorithm); +std::istream& operator>>(std::istream& _inputStream, solidity::phaser::MetricChoice& _metric); +std::ostream& operator<<(std::ostream& _outputStream, solidity::phaser::MetricChoice _metric); +std::istream& operator>>(std::istream& _inputStream, solidity::phaser::MetricAggregatorChoice& _aggregator); +std::ostream& operator<<(std::ostream& _outputStream, solidity::phaser::MetricAggregatorChoice _aggregator); + +/** + * Builds and validates instances of @a GeneticAlgorithm and its derived classes. + */ +class GeneticAlgorithmFactory +{ +public: + struct Options + { + Algorithm algorithm; + size_t minChromosomeLength; + size_t maxChromosomeLength; + std::optional randomElitePoolSize; + double gewepMutationPoolSize; + double gewepCrossoverPoolSize; + double gewepRandomisationChance; + double gewepDeletionVsAdditionChance; + std::optional gewepGenesToRandomise; + std::optional gewepGenesToAddOrDelete; + + static Options fromCommandLine(boost::program_options::variables_map const& _arguments); + }; + + static std::unique_ptr build( + Options const& _options, + size_t _populationSize + ); +}; + +/** + * Builds and validates instances of @a FitnessMetric and its derived classes. + */ +class FitnessMetricFactory +{ +public: + struct Options + { + MetricChoice metric; + MetricAggregatorChoice metricAggregator; + size_t relativeMetricScale; + size_t chromosomeRepetitions; + + static Options fromCommandLine(boost::program_options::variables_map const& _arguments); + }; + + static std::unique_ptr build( + Options const& _options, + std::vector _programs + ); +}; + +/** + * Builds and validates instances of @a Population. + */ +class PopulationFactory +{ +public: + struct Options + { + size_t minChromosomeLength; + size_t maxChromosomeLength; + std::vector population; + std::vector randomPopulation; + std::vector populationFromFile; + + static Options fromCommandLine(boost::program_options::variables_map const& _arguments); + }; + + static Population build( + Options const& _options, + std::shared_ptr _fitnessMetric + ); + static Population buildFromStrings( + std::vector const& _geneSequences, + std::shared_ptr _fitnessMetric + ); + static Population buildRandom( + size_t _populationSize, + size_t _minChromosomeLength, + size_t _maxChromosomeLength, + std::shared_ptr _fitnessMetric + ); + static Population buildFromFile( + std::string const& _filePath, + std::shared_ptr _fitnessMetric + ); +}; + +/** + * Builds and validates instances of @a Program. + */ +class ProgramFactory +{ +public: + struct Options + { + std::vector inputFiles; + + static Options fromCommandLine(boost::program_options::variables_map const& _arguments); + }; + + static std::vector build(Options const& _options); + +private: + static langutil::CharStream loadSource(std::string const& _sourcePath); +}; + +/** + * Main class that controls yul-phaser based on command-line parameters. The class is responsible + * for command-line parsing, initialisation of global objects (like the random number generator), + * creating instances of main components using factories and feeding them into @a AlgorithmRunner. + */ +class Phaser +{ +public: + static void main(int argc, char** argv); + +private: + struct CommandLineDescription + { + boost::program_options::options_description keywordDescription; + boost::program_options::positional_options_description positionalDescription; + }; + + static CommandLineDescription buildCommandLineDescription(); + static std::optional parseCommandLine(int _argc, char** _argv); + static void initialiseRNG(boost::program_options::variables_map const& _arguments); + static AlgorithmRunner::Options buildAlgorithmRunnerOptions(boost::program_options::variables_map const& _arguments); + + static void runAlgorithm(boost::program_options::variables_map const& _arguments); +}; + +} diff --git a/tools/yulPhaser/Population.cpp b/tools/yulPhaser/Population.cpp index b39f5dad5..87df4e59b 100644 --- a/tools/yulPhaser/Population.cpp +++ b/tools/yulPhaser/Population.cpp @@ -17,6 +17,7 @@ #include +#include #include #include @@ -58,7 +59,7 @@ bool phaser::isFitter(Individual const& a, Individual const& b) } Population Population::makeRandom( - shared_ptr _fitnessMetric, + shared_ptr _fitnessMetric, size_t _size, function _chromosomeLengthGenerator ) @@ -71,7 +72,7 @@ Population Population::makeRandom( } Population Population::makeRandom( - shared_ptr _fitnessMetric, + shared_ptr _fitnessMetric, size_t _size, size_t _minChromosomeLength, size_t _maxChromosomeLength @@ -93,6 +94,30 @@ Population Population::select(Selection const& _selection) const return Population(m_fitnessMetric, selectedIndividuals); } +Population Population::mutate(Selection const& _selection, function _mutation) const +{ + vector mutatedIndividuals; + for (size_t i: _selection.materialise(m_individuals.size())) + mutatedIndividuals.emplace_back(_mutation(m_individuals[i].chromosome), *m_fitnessMetric); + + return Population(m_fitnessMetric, mutatedIndividuals); +} + +Population Population::crossover(PairSelection const& _selection, function _crossover) const +{ + vector crossedIndividuals; + for (auto const& [i, j]: _selection.materialise(m_individuals.size())) + { + auto childChromosome = _crossover( + m_individuals[i].chromosome, + m_individuals[j].chromosome + ); + crossedIndividuals.emplace_back(move(childChromosome), *m_fitnessMetric); + } + + return Population(m_fitnessMetric, crossedIndividuals); +} + Population operator+(Population _a, Population _b) { // This operator is meant to be used only with populations sharing the same metric (and, to make @@ -120,7 +145,7 @@ ostream& phaser::operator<<(ostream& _stream, Population const& _population) } vector Population::chromosomesToIndividuals( - FitnessMetric const& _fitnessMetric, + FitnessMetric& _fitnessMetric, vector _chromosomes ) { diff --git a/tools/yulPhaser/Population.h b/tools/yulPhaser/Population.h index f4f42346d..f8f12632e 100644 --- a/tools/yulPhaser/Population.h +++ b/tools/yulPhaser/Population.h @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -39,6 +40,7 @@ solidity::phaser::Population operator+(solidity::phaser::Population _a, solidity namespace solidity::phaser { +class PairSelection; class Selection; /** @@ -53,7 +55,7 @@ struct Individual Individual(Chromosome _chromosome, size_t _fitness): chromosome(std::move(_chromosome)), fitness(_fitness) {} - Individual(Chromosome _chromosome, FitnessMetric const& _fitnessMetric): + Individual(Chromosome _chromosome, FitnessMetric& _fitnessMetric): chromosome(std::move(_chromosome)), fitness(_fitnessMetric.evaluate(chromosome)) {} @@ -83,7 +85,7 @@ class Population { public: explicit Population( - std::shared_ptr _fitnessMetric, + std::shared_ptr _fitnessMetric, std::vector _chromosomes = {} ): Population( @@ -92,21 +94,23 @@ public: ) {} static Population makeRandom( - std::shared_ptr _fitnessMetric, + std::shared_ptr _fitnessMetric, size_t _size, std::function _chromosomeLengthGenerator ); static Population makeRandom( - std::shared_ptr _fitnessMetric, + std::shared_ptr _fitnessMetric, size_t _size, size_t _minChromosomeLength, size_t _maxChromosomeLength ); Population select(Selection const& _selection) const; + Population mutate(Selection const& _selection, std::function _mutation) const; + Population crossover(PairSelection const& _selection, std::function _crossover) const; friend Population (::operator+)(Population _a, Population _b); - std::shared_ptr fitnessMetric() const { return m_fitnessMetric; } + std::shared_ptr fitnessMetric() { return m_fitnessMetric; } std::vector const& individuals() const { return m_individuals; } static size_t uniformChromosomeLength(size_t _min, size_t _max) { return SimulationRNG::uniformInt(_min, _max); } @@ -118,17 +122,17 @@ public: friend std::ostream& operator<<(std::ostream& _stream, Population const& _population); private: - explicit Population(std::shared_ptr _fitnessMetric, std::vector _individuals): + explicit Population(std::shared_ptr _fitnessMetric, std::vector _individuals): m_fitnessMetric(std::move(_fitnessMetric)), m_individuals{sortedIndividuals(std::move(_individuals))} {} static std::vector chromosomesToIndividuals( - FitnessMetric const& _fitnessMetric, + FitnessMetric& _fitnessMetric, std::vector _chromosomes ); static std::vector sortedIndividuals(std::vector _individuals); - std::shared_ptr m_fitnessMetric; + std::shared_ptr m_fitnessMetric; std::vector m_individuals; }; diff --git a/tools/yulPhaser/Program.cpp b/tools/yulPhaser/Program.cpp index 42cc8bf61..c397cd1f4 100644 --- a/tools/yulPhaser/Program.cpp +++ b/tools/yulPhaser/Program.cpp @@ -17,11 +17,9 @@ #include -#include - #include #include -#include +#include #include #include @@ -57,6 +55,16 @@ ostream& operator<<(ostream& _stream, Program const& _program); } +ostream& std::operator<<(ostream& _outputStream, ErrorList const& _errors) +{ + SourceReferenceFormatter formatter(_outputStream); + + for (auto const& error: _errors) + formatter.printErrorInformation(*error); + + return _outputStream; +} + Program::Program(Program const& program): m_ast(make_unique(get(ASTCopier{}(*program.m_ast)))), m_dialect{program.m_dialect}, @@ -64,16 +72,29 @@ Program::Program(Program const& program): { } -Program Program::load(CharStream& _sourceCode) +variant Program::load(CharStream& _sourceCode) { // ASSUMPTION: parseSource() rewinds the stream on its own Dialect const& dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion{}); - unique_ptr ast = parseSource(dialect, _sourceCode); - unique_ptr analysisInfo = analyzeAST(dialect, *ast); + + variant, ErrorList> astOrErrors = parseSource(dialect, _sourceCode); + if (holds_alternative(astOrErrors)) + return get(astOrErrors); + + variant, ErrorList> analysisInfoOrErrors = analyzeAST( + dialect, + *get>(astOrErrors) + ); + if (holds_alternative(analysisInfoOrErrors)) + return get(analysisInfoOrErrors); Program program( dialect, - disambiguateAST(dialect, *ast, *analysisInfo) + disambiguateAST( + dialect, + *get>(astOrErrors), + *get>(analysisInfoOrErrors) + ) ); program.optimise({ FunctionHoister::name, @@ -100,7 +121,7 @@ string Program::toJson() const return jsonPrettyPrint(serializedAst); } -unique_ptr Program::parseSource(Dialect const& _dialect, CharStream _source) +variant, ErrorList> Program::parseSource(Dialect const& _dialect, CharStream _source) { ErrorList errors; ErrorReporter errorReporter(errors); @@ -108,13 +129,14 @@ unique_ptr Program::parseSource(Dialect const& _dialect, CharStream _sour Parser parser(errorReporter, _dialect); unique_ptr ast = parser.parse(scanner, false); - assertThrow(ast != nullptr, InvalidProgram, "Error parsing source"); - assert(errorReporter.errors().empty()); + if (ast == nullptr) + return errors; - return ast; + assert(errorReporter.errors().empty()); + return variant, ErrorList>(move(ast)); } -unique_ptr Program::analyzeAST(Dialect const& _dialect, Block const& _ast) +variant, ErrorList> Program::analyzeAST(Dialect const& _dialect, Block const& _ast) { ErrorList errors; ErrorReporter errorReporter(errors); @@ -122,10 +144,11 @@ unique_ptr Program::analyzeAST(Dialect const& _dialect, Block c AsmAnalyzer analyzer(*analysisInfo, errorReporter, _dialect); bool analysisSuccessful = analyzer.analyze(_ast); - assertThrow(analysisSuccessful, InvalidProgram, "Error analyzing source"); - assert(errorReporter.errors().empty()); + if (!analysisSuccessful) + return errors; - return analysisInfo; + assert(errorReporter.errors().empty()); + return variant, ErrorList>(move(analysisInfo)); } unique_ptr Program::disambiguateAST( diff --git a/tools/yulPhaser/Program.h b/tools/yulPhaser/Program.h index 5e240e98d..6da9751b9 100644 --- a/tools/yulPhaser/Program.h +++ b/tools/yulPhaser/Program.h @@ -20,10 +20,13 @@ #include #include +#include + #include #include #include #include +#include #include namespace solidity::langutil @@ -41,6 +44,13 @@ struct Dialect; } +namespace std +{ + +std::ostream& operator<<(std::ostream& _outputStream, solidity::langutil::ErrorList const& _errors); + +} + namespace solidity::phaser { @@ -65,7 +75,7 @@ public: Program operator=(Program const& program) = delete; Program operator=(Program&& program) = delete; - static Program load(langutil::CharStream& _sourceCode); + static std::variant load(langutil::CharStream& _sourceCode); void optimise(std::vector const& _optimisationSteps); size_t codeSize() const { return computeCodeSize(*m_ast); } @@ -84,11 +94,11 @@ private: m_nameDispenser(_dialect, *m_ast, {}) {} - static std::unique_ptr parseSource( + static std::variant, langutil::ErrorList> parseSource( yul::Dialect const& _dialect, langutil::CharStream _source ); - static std::unique_ptr analyzeAST( + static std::variant, langutil::ErrorList> analyzeAST( yul::Dialect const& _dialect, yul::Block const& _ast ); diff --git a/tools/yulPhaser/main.cpp b/tools/yulPhaser/main.cpp index 321ebe088..d0c00fcda 100644 --- a/tools/yulPhaser/main.cpp +++ b/tools/yulPhaser/main.cpp @@ -16,157 +16,74 @@ */ #include -#include -#include -#include -#include -#include +#include -#include -#include -#include - -#include -#include +#include #include -#include - -using namespace std; -using namespace solidity::langutil; -using namespace solidity::phaser; -using namespace solidity::util; - -namespace po = boost::program_options; - -namespace -{ - -struct CommandLineParsingResult -{ - int exitCode; - po::variables_map arguments; -}; - - -void initializeRNG(po::variables_map const& arguments) -{ - uint32_t seed; - if (arguments.count("seed") > 0) - seed = arguments["seed"].as(); - else - seed = SimulationRNG::generateSeed(); - - SimulationRNG::reset(seed); - cout << "Random seed: " << seed << endl; -} - -CharStream loadSource(string const& _sourcePath) -{ - assertThrow(boost::filesystem::exists(_sourcePath), InvalidProgram, "Source file does not exist"); - - string sourceCode = readFileAsString(_sourcePath); - return CharStream(sourceCode, _sourcePath); -} - -void runAlgorithm(string const& _sourcePath) -{ - constexpr size_t populationSize = 20; - constexpr size_t minChromosomeLength = 12; - constexpr size_t maxChromosomeLength = 30; - - CharStream sourceCode = loadSource(_sourcePath); - shared_ptr fitnessMetric = make_shared(Program::load(sourceCode), 5); - auto population = Population::makeRandom( - fitnessMetric, - populationSize, - minChromosomeLength, - maxChromosomeLength - ); - RandomAlgorithm( - population, - cout, - { - /* elitePoolSize = */ 1.0 / populationSize, - /* minChromosomeLength = */ minChromosomeLength, - /* maxChromosomeLength = */ maxChromosomeLength, - } - ).run(); -} - -CommandLineParsingResult parseCommandLine(int argc, char** argv) -{ - po::options_description description( - "yul-phaser, a tool for finding the best sequence of Yul optimisation phases.\n" - "\n" - "Usage: yul-phaser [options] \n" - "Reads as Yul code and tries to find the best order in which to run optimisation" - " phases using a genetic algorithm.\n" - "Example:\n" - "yul-phaser program.yul\n" - "\n" - "Allowed options", - po::options_description::m_default_line_length, - po::options_description::m_default_line_length - 23 - ); - - description.add_options() - ("help", "Show help message and exit.") - ("input-file", po::value()->required(), "Input file") - ("seed", po::value(), "Seed for the random number generator") - ; - - po::positional_options_description positionalDescription; - po::variables_map arguments; - positionalDescription.add("input-file", 1); - po::notify(arguments); - - try - { - po::command_line_parser parser(argc, argv); - parser.options(description).positional(positionalDescription); - po::store(parser.run(), arguments); - } - catch (po::error const & _exception) - { - cerr << _exception.what() << endl; - return {1, move(arguments)}; - } - - if (arguments.count("help") > 0) - { - cout << description << endl; - return {2, move(arguments)}; - } - - if (arguments.count("input-file") == 0) - { - cerr << "Missing argument: input-file." << endl; - return {1, move(arguments)}; - } - - return {0, arguments}; -} - -} int main(int argc, char** argv) { - CommandLineParsingResult parsingResult = parseCommandLine(argc, argv); - if (parsingResult.exitCode != 0) - return parsingResult.exitCode; - - initializeRNG(parsingResult.arguments); - try { - runAlgorithm(parsingResult.arguments["input-file"].as()); + solidity::phaser::Phaser::main(argc, argv); + return 0; } - catch (InvalidProgram const& _exception) + catch (boost::program_options::error const& exception) { - cerr << "ERROR: " << _exception.what() << endl; + // Bad input data. Invalid command-line parameters. + + std::cerr << std::endl; + std::cerr << "ERROR: " << exception.what() << std::endl; return 1; } + catch (solidity::phaser::BadInput const& exception) + { + // Bad input data. Syntax errors in the input program, semantic errors in command-line + // parameters, etc. - return 0; + std::cerr << std::endl; + std::cerr << "ERROR: " << exception.what() << std::endl; + return 1; + } + catch (solidity::util::Exception const& exception) + { + // Something's seriously wrong. Probably a bug in the program or a missing handler (which + // is really also a bug). The exception should have been handled gracefully by this point + // if it's something that can happen in normal usage. E.g. an error in the input or a + // failure of some part of the system that's outside of control of the application (disk, + // network, etc.). The bug should be reported and investigated so our job here is just to + // provide as much useful information about it as possible. + + std::cerr << std::endl; + std::cerr << "UNCAUGHT EXCEPTION!" << std::endl; + + // We can print some useful diagnostic info for this particular exception type. + std::cerr << "Location: " << exception.lineInfo() << std::endl; + + char const* const* function = boost::get_error_info(exception); + if (function != nullptr) + std::cerr << "Function: " << *function << std::endl; + + // Let it crash. The terminate() will print some more stuff useful for debugging like + // what() and the actual exception type. + throw; + } + catch (std::exception const&) + { + // Again, probably a bug but this time it's just plain std::exception so there's no point + // in doing anything special. terminate() will do an adequate job. + std::cerr << std::endl; + std::cerr << "UNCAUGHT EXCEPTION!" << std::endl; + throw; + } + catch (...) + { + // Some people don't believe these exist. + // I have no idea what this is and it's flying towards me so technically speaking it's an + // unidentified flying object. + std::cerr << std::endl; + std::cerr << "UFO SPOTTED!" << std::endl; + throw; + } }