diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 48dbb625408e..8a0e183221c2 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -3329,6 +3329,19 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) _memberAccess.annotation().requiredLookup = requiredLookup; + // Sanity check. Only module, struct and contract instances as well as contract types can have accessible variables. + if (dynamic_cast(_memberAccess.annotation().referencedDeclaration)) + { + if (owningObjectType->category() == Type::Category::TypeType) + solAssert(static_cast(owningObjectType)->actualType()->category() == Type::Category::Contract); + else + solAssert( + owningObjectType->category() == Type::Category::Module || + owningObjectType->category() == Type::Category::Struct || + owningObjectType->category() == Type::Category::Contract + ); + } + switch (owningObjectType->category()) { case Type::Category::Struct: @@ -3430,13 +3443,75 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) } case Type::Category::Contract: { + // Member of a contract accessed by the contract name (not contract instance). + + // ContractType has only user-defined members, so accessedMemberAnnotation.referencedDeclaration is not `NULL`. + // See `ContractType::nativeMembers` for details. + solAssert(_memberAccess.annotation().referencedDeclaration); _memberAccess.annotation().isLValue = _memberAccess.annotation().referencedDeclaration->isLValue(); - if ( - auto const* accessedMemberFunctionType = dynamic_cast(type(_memberAccess)); - accessedMemberFunctionType && - accessedMemberFunctionType->kind() == FunctionType::Kind::Declaration - ) - _memberAccess.annotation().isPure = *_memberAccess.expression().annotation().isPure; + // Expressions like `C.foo;`, `C.Ev;` are pure and they must generate `Statement has no effect.` warning. + // TODO: However, in case a function this does not allow to assign the expression to a constant variable, + // TODO: because of different kind. Left-hand side of the variable declaration never has `Declaration` kind. + if (auto const* functionTypeMember = dynamic_cast(_memberAccess.annotation().type)) + { + // By default, all pure function invocation kinds are pure. Additionally, `C.Ev` is pure too. + // Note: This means also that a member function of a foreign contract accessed via the contract type + // name is pure, but a member function of a library accessed via the library name is not pure, because + // `C.foo` cannot be called (it needs a contract instance instead), but `Lib.foo` can be called. + if ( + functionTypeMember->isPure() || + functionTypeMember->kind() == FunctionType::Kind::Event + ) + _memberAccess.annotation().isPure = true; + else if (functionTypeMember->kind() == FunctionType::Kind::Internal) + { + // A variable declaration of constant function pointer. + if ( + auto const* variableDeclarationMember = + dynamic_cast(_memberAccess.annotation().referencedDeclaration) + ) + _memberAccess.annotation().isPure = variableDeclarationMember->isConstant(); + else if (dynamic_cast(_memberAccess.annotation().referencedDeclaration)) + _memberAccess.annotation().isPure = true; + else + solAssert(false, "Impossible declaration type for internal function call kind"); + } + else if (functionTypeMember->kind() == FunctionType::Kind::External) + { + // A variable declaration of constant function pointer. + if ( + auto const* variableDeclarationMember = + dynamic_cast(_memberAccess.annotation().referencedDeclaration) + ) + _memberAccess.annotation().isPure = variableDeclarationMember->isConstant(); + else + solAssert( + dynamic_cast(_memberAccess.annotation().referencedDeclaration), + "Impossible declaration type for external function call kind" + ); + } + else + // Library function declaration is not pure. It requires the library address. + solAssert(functionTypeMember->kind() == FunctionType::Kind::DelegateCall); + } + else if (auto const* typeTypeMember = dynamic_cast(_memberAccess.annotation().type)) + { + solAssert( + typeTypeMember->actualType()->category() == Type::Category::Struct || + typeTypeMember->actualType()->category() == Type::Category::Enum || + // Note: We add Contract intentionally, to cover a possible contract nesting case. + typeTypeMember->actualType()->category() == Type::Category::Contract || + typeTypeMember->actualType()->category() == Type::Category::UserDefinedValueType, + "Impossible `TypeType` category as contract member." + ); + _memberAccess.annotation().isPure = true; + } + // In case `Base.value` or `Lib.value` and when `value` is constant, the expression is pure. + else if (auto const* varDecl = dynamic_cast(_memberAccess.annotation().referencedDeclaration)) + _memberAccess.annotation().isPure = varDecl->isConstant(); + else + solAssert(false, "Unexpected annotation type"); + break; } case Type::Category::Enum: @@ -3547,9 +3622,57 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) break; } case Type::Category::Module: - _memberAccess.annotation().isPure = *_memberAccess.expression().annotation().isPure; + { + // Module has only exported symbols members, so accessedMemberAnnotation.referencedDeclaration is not `NULL`. + // See `ModuleType::nativeMembers` for details. + solAssert(_memberAccess.annotation().referencedDeclaration); + // All currently accessible members via a module type are pure. + _memberAccess.annotation().isPure = true; _memberAccess.annotation().isLValue = false; + + // Below only the sanity checks. + solAssert( + _memberAccess.annotation().type->category() == Type::Category::Function || + _memberAccess.annotation().type->category() == Type::Category::TypeType || + _memberAccess.annotation().type->category() == Type::Category::Module || + dynamic_cast(_memberAccess.annotation().referencedDeclaration), + "Impossible member type for module type member access" + ); + + if (_memberAccess.annotation().type->category() == Type::Category::Function) + { + auto const* functionTypeMember = static_cast(_memberAccess.annotation().type); + solAssert ( + functionTypeMember->isPure() || + functionTypeMember->kind() == FunctionType::Kind::Event || + functionTypeMember->kind() == FunctionType::Kind::Internal, + "Impossible declaration type for function call kind" + ); + + if (functionTypeMember->kind() == FunctionType::Kind::Internal) + solAssert(dynamic_cast(_memberAccess.annotation().referencedDeclaration), "Impossible declaration type for internal function call kind"); + } + + if (_memberAccess.annotation().type->category() == Type::Category::TypeType) + { + auto const* typeTypeMember = static_cast(_memberAccess.annotation().type); + solAssert( + typeTypeMember->actualType()->category() == Type::Category::Struct || + typeTypeMember->actualType()->category() == Type::Category::Enum || + typeTypeMember->actualType()->category() == Type::Category::Contract || + typeTypeMember->actualType()->category() == Type::Category::UserDefinedValueType, + "Impossible `TypeType` category as module member." + ); + } + + if ( + auto const* accessedMemberVariableDeclaration = + dynamic_cast(_memberAccess.annotation().referencedDeclaration) + ) + solAssert(accessedMemberVariableDeclaration->isConstant(), "Only constant variables are allowed at file level."); + break; + } case Type::Category::Address: if (memberName == "codehash" && !m_evmVersion.hasExtCodeHash()) m_errorReporter.typeError( @@ -3559,6 +3682,47 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) ); _memberAccess.annotation().isLValue = false; break; + // Contract instance case + case Type::Category::Contract: + { + solAssert( + _memberAccess.annotation().type->category() == Type::Category::Function, + "Via contract instance only a function or a variable getter can be accessed." + ); + // When contract is constant its members are also constant. + _memberAccess.annotation().isPure = *_memberAccess.expression().annotation().isPure; + _memberAccess.annotation().isLValue = false; + + // Below only the sanity checks. + if (dynamic_cast(_memberAccess.annotation().referencedDeclaration)) + { + auto const* accessedMemberFunctionType = static_cast(_memberAccess.annotation().type); + // In case when an internal library function is attached to a contract, the function invoke kind can be + // `Internal` or `DelegateCall`. It depends on the function declaration in the library. + solAssert( + accessedMemberFunctionType->kind() == FunctionType::Kind::Internal || + accessedMemberFunctionType->kind() == FunctionType::Kind::External || + accessedMemberFunctionType->kind() == FunctionType::Kind::DelegateCall, + "Impossible function call kind for contract type member." + ); + } + else if (dynamic_cast(_memberAccess.annotation().referencedDeclaration)) + { + // If a constant variable of contract type (owning expression) is pure, then the accessed member is pure. + // Note: It does not matter that the being accessed declaration is constant, because when accessing via + // a contract instance we always have a getter function but not the variable itself. Moreover, the getter of + // a constant variable contained by non-constant contract should not be constant. + auto const* accessedMemberFunctionType = static_cast(_memberAccess.annotation().type); + solAssert( + accessedMemberFunctionType->kind() == FunctionType::Kind::External, + "Impossible function call kind for contract type member." + ); + } + else + solAssert(false, "Invalid declaration type for contract instance member."); + + break; + } case Type::Category::Integer: case Type::Category::RationalNumber: case Type::Category::StringLiteral: @@ -3567,7 +3731,6 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) case Type::Category::FixedBytes: case Type::Category::Array: case Type::Category::ArraySlice: - case Type::Category::Contract: case Type::Category::Enum: case Type::Category::UserDefinedValueType: case Type::Category::Tuple: @@ -3580,18 +3743,10 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) solAssert(_memberAccess.annotation().isLValue.set()); - // TODO: Leave it for now, but it should be moved to TypeType -> Contract case. - // We do not want to change the logic in refactor PR. - if ( - auto const* varDecl = dynamic_cast(_memberAccess.annotation().referencedDeclaration); - !_memberAccess.annotation().isPure.set() && - varDecl && - varDecl->isConstant() - ) - { - solAssert(owningObjectType->category() != Type::Category::Magic); - _memberAccess.annotation().isPure = true; - } + // // TODO: Leave it for now, but it should be moved to TypeType -> Contract case. + // // We do not want to change the logic in refactor PR. + // if (dynamic_cast(accessedMemberAnnotation.referencedDeclaration)) + // solAssert(accessedMemberAnnotation.isPure.set()); if (!_memberAccess.annotation().isPure.set()) diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index b58ba987e5fb..4b6195226ce8 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -3714,7 +3714,9 @@ bool FunctionType::isPure() const m_kind == Kind::Unwrap || m_kind == Kind::BytesConcat || m_kind == Kind::StringConcat || - m_kind == Kind::ERC7201; + m_kind == Kind::ERC7201 || + m_kind == Kind::Error || + m_kind == Kind::Declaration; } TypePointers FunctionType::parseElementaryTypeVector(strings const& _types) diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index d5cb27b6e1df..a2435f28d8f1 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -346,7 +346,7 @@ std::string IRGeneratorForStatements::constantValueFunction(VariableDeclaration function () -> { - := + := () } )"); templ("sourceLocationComment", dispenseLocationComment(_constant, m_context)); @@ -354,6 +354,8 @@ std::string IRGeneratorForStatements::constantValueFunction(VariableDeclaration IRGeneratorForStatements generator(m_context, m_utils, m_optimiserSettings); solAssert(_constant.value()); Type const& constantType = *_constant.type(); + // Need to use the convert function which is an identity function to handle a case with more than one value. + templ("identity", m_utils.conversionFunction(constantType, constantType)); templ("value", generator.evaluateExpression(*_constant.value(), constantType).commaSeparatedList()); templ("code", generator.code()); templ("ret", IRVariable("ret", constantType).commaSeparatedList()); diff --git a/test/cmdlineTests/standard_debug_info_in_yul_location/output.json b/test/cmdlineTests/standard_debug_info_in_yul_location/output.json index 16220fd619b0..bf47e957757e 100644 --- a/test/cmdlineTests/standard_debug_info_in_yul_location/output.json +++ b/test/cmdlineTests/standard_debug_info_in_yul_location/output.json @@ -303,14 +303,18 @@ object \"C_54\" { } - function cleanup_t_rational_41_by_1(value) -> cleaned { - cleaned := value - } - function identity(value) -> ret { ret := value } + function convert_t_int256_to_t_int256(value) -> converted { + converted := cleanup_t_int256(identity(cleanup_t_int256(value))) + } + + function cleanup_t_rational_41_by_1(value) -> cleaned { + cleaned := value + } + function convert_t_rational_41_by_1_to_t_int256(value) -> converted { converted := cleanup_t_int256(identity(cleanup_t_rational_41_by_1(value))) } @@ -321,7 +325,7 @@ object \"C_54\" { let expr_4 := 0x29 let _1 := convert_t_rational_41_by_1_to_t_int256(expr_4) - ret := _1 + ret := convert_t_int256_to_t_int256(_1) } /// @ast-id 5 @@ -428,10 +432,6 @@ object \"C_54\" { result := or(value, and(toInsert, mask)) } - function convert_t_int256_to_t_int256(value) -> converted { - converted := cleanup_t_int256(identity(cleanup_t_int256(value))) - } - function prepare_store_t_int256(value) -> ret { ret := value } @@ -1140,14 +1140,18 @@ object \"D_72\" { } - function cleanup_t_rational_41_by_1(value) -> cleaned { - cleaned := value - } - function identity(value) -> ret { ret := value } + function convert_t_int256_to_t_int256(value) -> converted { + converted := cleanup_t_int256(identity(cleanup_t_int256(value))) + } + + function cleanup_t_rational_41_by_1(value) -> cleaned { + cleaned := value + } + function convert_t_rational_41_by_1_to_t_int256(value) -> converted { converted := cleanup_t_int256(identity(cleanup_t_rational_41_by_1(value))) } @@ -1158,7 +1162,7 @@ object \"D_72\" { let expr_4 := 0x29 let _1 := convert_t_rational_41_by_1_to_t_int256(expr_4) - ret := _1 + ret := convert_t_int256_to_t_int256(_1) } /// @ast-id 5 @@ -1265,10 +1269,6 @@ object \"D_72\" { result := or(value, and(toInsert, mask)) } - function convert_t_int256_to_t_int256(value) -> converted { - converted := cleanup_t_int256(identity(cleanup_t_int256(value))) - } - function prepare_store_t_int256(value) -> ret { ret := value } diff --git a/test/libsolidity/ASTJSON/ast_internal_function_different_ids_export.json b/test/libsolidity/ASTJSON/ast_internal_function_different_ids_export.json index f94345ffcd92..abf9312dd63b 100644 --- a/test/libsolidity/ASTJSON/ast_internal_function_different_ids_export.json +++ b/test/libsolidity/ASTJSON/ast_internal_function_different_ids_export.json @@ -249,7 +249,7 @@ "id": 6, "isConstant": false, "isLValue": false, - "isPure": false, + "isPure": true, "lValueRequested": false, "memberLocation": "62:1:2", "memberName": "g", @@ -266,7 +266,7 @@ "isConstant": false, "isInlineArray": false, "isLValue": false, - "isPure": false, + "isPure": true, "lValueRequested": false, "nodeType": "TupleExpression", "src": "59:5:2", @@ -369,7 +369,7 @@ "id": 16, "isConstant": false, "isLValue": false, - "isPure": false, + "isPure": true, "lValueRequested": false, "memberLocation": "98:1:2", "memberName": "h", @@ -386,7 +386,7 @@ "isConstant": false, "isInlineArray": false, "isLValue": false, - "isPure": false, + "isPure": true, "lValueRequested": false, "nodeType": "TupleExpression", "src": "95:5:2", @@ -496,7 +496,7 @@ "id": 27, "isConstant": false, "isLValue": false, - "isPure": false, + "isPure": true, "lValueRequested": false, "memberLocation": "162:1:2", "memberName": "h", @@ -513,7 +513,7 @@ "isConstant": false, "isInlineArray": false, "isLValue": false, - "isPure": false, + "isPure": true, "lValueRequested": false, "nodeType": "TupleExpression", "src": "159:5:2", @@ -710,7 +710,7 @@ "id": 44, "isConstant": false, "isLValue": false, - "isPure": false, + "isPure": true, "lValueRequested": false, "memberLocation": "62:1:3", "memberName": "g", @@ -727,7 +727,7 @@ "isConstant": false, "isInlineArray": false, "isLValue": false, - "isPure": false, + "isPure": true, "lValueRequested": false, "nodeType": "TupleExpression", "src": "59:5:3", @@ -830,7 +830,7 @@ "id": 54, "isConstant": false, "isLValue": false, - "isPure": false, + "isPure": true, "lValueRequested": false, "memberLocation": "98:1:3", "memberName": "h", @@ -847,7 +847,7 @@ "isConstant": false, "isInlineArray": false, "isLValue": false, - "isPure": false, + "isPure": true, "lValueRequested": false, "nodeType": "TupleExpression", "src": "95:5:3", diff --git a/test/libsolidity/ASTJSON/ast_internal_function_id_export.json b/test/libsolidity/ASTJSON/ast_internal_function_id_export.json index cbbc962c027a..7d2fdef8d8d0 100644 --- a/test/libsolidity/ASTJSON/ast_internal_function_id_export.json +++ b/test/libsolidity/ASTJSON/ast_internal_function_id_export.json @@ -822,7 +822,7 @@ "id": 90, "isConstant": false, "isLValue": false, - "isPure": false, + "isPure": true, "lValueRequested": false, "memberLocation": "654:4:1", "memberName": "inr1", @@ -1099,7 +1099,7 @@ "id": 116, "isConstant": false, "isLValue": false, - "isPure": false, + "isPure": true, "lValueRequested": false, "memberLocation": "787:4:1", "memberName": "inr2", @@ -1116,7 +1116,7 @@ "isConstant": false, "isInlineArray": false, "isLValue": false, - "isPure": false, + "isPure": true, "lValueRequested": false, "nodeType": "TupleExpression", "src": "784:8:1", diff --git a/test/libsolidity/ASTJSON/constant_access_via_getter.json b/test/libsolidity/ASTJSON/constant_access_via_getter.json new file mode 100644 index 000000000000..f845ef8d4a99 --- /dev/null +++ b/test/libsolidity/ASTJSON/constant_access_via_getter.json @@ -0,0 +1,164 @@ +{ + "absolutePath": "a", + "exportedSymbols": { + "Counter": [ + 13 + ] + }, + "id": 14, + "nodeType": "SourceUnit", + "nodes": [ + { + "abstract": false, + "baseContracts": [], + "canonicalName": "Counter", + "contractDependencies": [], + "contractKind": "contract", + "fullyImplemented": true, + "id": 13, + "linearizedBaseContracts": [ + 13 + ], + "name": "Counter", + "nameLocation": "9:7:1", + "nodeType": "ContractDefinition", + "nodes": [ + { + "constant": true, + "functionSelector": "21b77d63", + "id": 3, + "mutability": "constant", + "name": "MIN_LIQUIDITY", + "nameLocation": "47:13:1", + "nodeType": "VariableDeclaration", + "scope": 13, + "src": "23:44:1", + "stateVariable": true, + "storageLocation": "default", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + }, + "typeName": { + "id": 1, + "name": "uint256", + "nodeType": "ElementaryTypeName", + "src": "23:7:1", + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + }, + "value": { + "hexValue": "31303030", + "id": 2, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "number", + "lValueRequested": false, + "nodeType": "Literal", + "src": "63:4:1", + "typeDescriptions": { + "typeIdentifier": "t_rational_1000_by_1", + "typeString": "int_const 1000" + }, + "value": "1000" + }, + "visibility": "public" + }, + { + "body": { + "id": 11, + "nodeType": "Block", + "src": "100:37:1", + "statements": [ + { + "expression": { + "arguments": [], + "expression": { + "argumentTypes": [], + "expression": { + "id": 6, + "name": "this", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": -28, + "src": "110:4:1", + "typeDescriptions": { + "typeIdentifier": "t_contract$_Counter_$13", + "typeString": "contract Counter" + } + }, + "id": 8, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "memberLocation": "115:13:1", + "memberName": "MIN_LIQUIDITY", + "nodeType": "MemberAccess", + "referencedDeclaration": 3, + "src": "110:18:1", + "typeDescriptions": { + "typeIdentifier": "t_function_external_view$__$returns$_t_uint256_$", + "typeString": "function () view external returns (uint256)" + } + }, + "id": 9, + "isConstant": false, + "isLValue": false, + "isPure": false, + "kind": "functionCall", + "lValueRequested": false, + "nameLocations": [], + "names": [], + "nodeType": "FunctionCall", + "src": "110:20:1", + "tryCall": false, + "typeDescriptions": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + }, + "id": 10, + "nodeType": "ExpressionStatement", + "src": "110:20:1" + } + ] + }, + "functionSelector": "c0406226", + "id": 12, + "implemented": true, + "kind": "function", + "modifiers": [], + "name": "run", + "nameLocation": "82:3:1", + "nodeType": "FunctionDefinition", + "parameters": { + "id": 4, + "nodeType": "ParameterList", + "parameters": [], + "src": "85:2:1" + }, + "returnParameters": { + "id": 5, + "nodeType": "ParameterList", + "parameters": [], + "src": "100:0:1" + }, + "scope": 13, + "src": "73:64:1", + "stateMutability": "view", + "virtual": false, + "visibility": "public" + } + ], + "scope": 14, + "src": "0:139:1", + "usedErrors": [], + "usedEvents": [] + } + ], + "src": "0:140:1" +} diff --git a/test/libsolidity/ASTJSON/constant_access_via_getter.sol b/test/libsolidity/ASTJSON/constant_access_via_getter.sol new file mode 100644 index 000000000000..053147758e44 --- /dev/null +++ b/test/libsolidity/ASTJSON/constant_access_via_getter.sol @@ -0,0 +1,8 @@ +contract Counter { + uint256 public constant MIN_LIQUIDITY = 1000; + function run() view public { + this.MIN_LIQUIDITY(); + } +} + +// ---- diff --git a/test/libsolidity/ASTJSON/emit_event_from_module_via_member_access.json b/test/libsolidity/ASTJSON/emit_event_from_module_via_member_access.json index a33847450bc2..c05dca5ca8dc 100644 --- a/test/libsolidity/ASTJSON/emit_event_from_module_via_member_access.json +++ b/test/libsolidity/ASTJSON/emit_event_from_module_via_member_access.json @@ -970,7 +970,7 @@ "id": 60, "isConstant": false, "isLValue": false, - "isPure": false, + "isPure": true, "lValueRequested": false, "memberLocation": "275:17:2", "memberName": "TransferAContract", diff --git a/test/libsolidity/ASTJSON/error_from_module_via_member_access.json b/test/libsolidity/ASTJSON/error_from_module_via_member_access.json index db9062891a9b..cc4bc6b061dc 100644 --- a/test/libsolidity/ASTJSON/error_from_module_via_member_access.json +++ b/test/libsolidity/ASTJSON/error_from_module_via_member_access.json @@ -359,7 +359,7 @@ "id": 30, "isConstant": false, "isLValue": false, - "isPure": false, + "isPure": true, "kind": "functionCall", "lValueRequested": false, "nameLocations": [], @@ -468,7 +468,7 @@ "id": 40, "isConstant": false, "isLValue": false, - "isPure": false, + "isPure": true, "lValueRequested": false, "memberLocation": "294:14:2", "memberName": "ErrorAContract", @@ -483,7 +483,7 @@ "id": 42, "isConstant": false, "isLValue": false, - "isPure": false, + "isPure": true, "kind": "functionCall", "lValueRequested": false, "nameLocations": [], diff --git a/test/libsolidity/ASTJSON/event_emited_in_base_contract.json b/test/libsolidity/ASTJSON/event_emited_in_base_contract.json index 40bb3bae44aa..ac0bdb77509f 100644 --- a/test/libsolidity/ASTJSON/event_emited_in_base_contract.json +++ b/test/libsolidity/ASTJSON/event_emited_in_base_contract.json @@ -144,7 +144,7 @@ "id": 10, "isConstant": false, "isLValue": false, - "isPure": false, + "isPure": true, "lValueRequested": false, "memberLocation": "80:1:1", "memberName": "E", diff --git a/test/libsolidity/ASTJSON/event_emitted_from_foreign_contract.json b/test/libsolidity/ASTJSON/event_emitted_from_foreign_contract.json index 92de58cf8b2a..66e7bd3e673a 100644 --- a/test/libsolidity/ASTJSON/event_emitted_from_foreign_contract.json +++ b/test/libsolidity/ASTJSON/event_emitted_from_foreign_contract.json @@ -153,7 +153,7 @@ "id": 12, "isConstant": false, "isLValue": false, - "isPure": false, + "isPure": true, "lValueRequested": false, "memberLocation": "123:1:1", "memberName": "E", diff --git a/test/libsolidity/ASTJSON/indirect_event.json b/test/libsolidity/ASTJSON/indirect_event.json index 691e814e51ef..22aa36d1c317 100644 --- a/test/libsolidity/ASTJSON/indirect_event.json +++ b/test/libsolidity/ASTJSON/indirect_event.json @@ -175,7 +175,7 @@ "id": 17, "isConstant": false, "isLValue": false, - "isPure": false, + "isPure": true, "lValueRequested": false, "memberLocation": "161:1:1", "memberName": "f", diff --git a/test/libsolidity/semanticTests/constants/constant_contract_functions_pointers_evaluation.sol b/test/libsolidity/semanticTests/constants/constant_contract_functions_pointers_evaluation.sol new file mode 100644 index 000000000000..00d0640a7387 --- /dev/null +++ b/test/libsolidity/semanticTests/constants/constant_contract_functions_pointers_evaluation.sol @@ -0,0 +1,39 @@ +library L { + function fooLibInternal(C c) internal {} + function fooLibExternal(C c) external {} + function fooLibPublic(C c) public {} +} + +using L for C; + +contract C { + function fooPublic() public {} + function fooExternal() external {} +} + +contract T { + C constant cConst = C(address(0x886677)); + function () external constant public fooPublicConstPtr = cConst.fooPublic; + function () external constant public fooExternalConstPtr = cConst.fooExternal; + + function test() public { + require(C.fooPublic.selector == fooPublicConstPtr.selector); + require(cConst.fooPublic.selector == fooPublicConstPtr.selector); + require(cConst.fooPublic.address == fooPublicConstPtr.address); + + require(C.fooExternal.selector == fooExternalConstPtr.selector); + require(cConst.fooExternal.selector == fooExternalConstPtr.selector); + require(cConst.fooExternal.address == fooExternalConstPtr.address); + } + + function testLibFunction() pure public { + require(cConst.fooLibExternal.selector == L.fooLibExternal.selector); + require(cConst.fooLibPublic.selector == L.fooLibPublic.selector); + } +} +// ---- +// library: L +// test() -> +// testLibFunction() -> +// fooPublicConstPtr() -> 0x886677d08ff2e70000000000000000 +// fooExternalConstPtr() -> 0x8866773bebdd5a0000000000000000 diff --git a/test/libsolidity/semanticTests/constants/constant_struct_members_evaluation.sol b/test/libsolidity/semanticTests/constants/constant_struct_members_evaluation.sol new file mode 100644 index 000000000000..3a285bc28c24 --- /dev/null +++ b/test/libsolidity/semanticTests/constants/constant_struct_members_evaluation.sol @@ -0,0 +1,43 @@ +pragma abicoder v2; + +struct S { + uint value; +} + +library L { + function getValue(S memory s) internal pure returns(uint) { + return s.value; + } + + function getValueExternal(S memory s) external pure returns(uint) { + return s.value; + } + + function getValuePublic(S memory s) public pure returns(uint) { + return s.value; + } +} + +using L for S; + +contract C { + uint constant public structValue = S(11).value; + + function testAttachedFunction() pure public returns(uint, uint) { + return (S(3).getValue(), S(5).value); + } + + function testAttachedExternalFunction() pure public returns(uint) { + return S(7).getValueExternal(); + } + + function testAttachedPublicFunction() pure public returns(uint) { + return S(9).getValuePublic(); + } +} +// ---- +// library: L +// testAttachedFunction() -> 3, 5 +// testAttachedExternalFunction() -> 7 +// testAttachedPublicFunction() -> 9 +// structValue() -> 11 diff --git a/test/libsolidity/semanticTests/constants/module_constant_members_evaluation.sol b/test/libsolidity/semanticTests/constants/module_constant_members_evaluation.sol new file mode 100644 index 000000000000..81fa87fc7b6d --- /dev/null +++ b/test/libsolidity/semanticTests/constants/module_constant_members_evaluation.sol @@ -0,0 +1,33 @@ +==== Source: B.sol ==== +function foo() pure returns(uint) { return 5; } +uint constant CONST_VALUE = 7; +bytes constant globalBytes = hex"123456"; +bytes4 constant globalStaticBytes = hex"01020304"; + +==== Source: C.sol ==== +import * as B from "B.sol"; + +contract C { + function () pure returns(uint) constant private fooConstPtr = B.foo; + + function testFunctionPointer() pure public returns(uint) { + return fooConstPtr(); + } + + function testGlobalVariable() pure public returns(uint) { + return B.CONST_VALUE; + } + + function testGlobalBytes() pure public returns(bytes memory) { + return B.globalBytes; + } + + function testGlobalStaticBytes() pure public returns(bytes4) { + return B.globalStaticBytes; + } +} +// ---- +// testFunctionPointer() -> 5 +// testGlobalVariable() -> 7 +// testGlobalBytes() -> 0x20, 3, 0x1234560000000000000000000000000000000000000000000000000000000000 +// testGlobalStaticBytes() -> 0x0102030400000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/syntaxTests/errors/error_with_non_pure_arguments.sol b/test/libsolidity/syntaxTests/errors/error_with_non_pure_arguments.sol new file mode 100644 index 000000000000..82a73da8f772 --- /dev/null +++ b/test/libsolidity/syntaxTests/errors/error_with_non_pure_arguments.sol @@ -0,0 +1,52 @@ +==== Source: C.sol ==== +import * as EMod from "Error.sol"; + +error ErGlobal(uint); + +contract Base { + error ErBase(uint); +} + +contract C is Base { + error Er(uint); + + uint g_error; + + function test1() pure private { + revert EMod.ErGlobal(g_error); + } + function test2() pure private { + revert EMod.E.Er(g_error); + } + function test3() pure private { + revert ErGlobal(g_error); + } + function test4() pure private { + revert Er(g_error); + } + function test5() pure private { + revert C.Er(g_error); + } + function test6() pure private { + revert ErBase(g_error); + } + function test7() pure private { + revert Base.ErBase(g_error); + } +} +==== Source: Error.sol ==== + +error ErGlobal(uint); + +contract E { + error Er(uint); +} + +// ---- +// TypeError 2527: (C.sol:228-235): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view". +// TypeError 2527: (C.sol:305-312): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view". +// TypeError 2527: (C.sol:381-388): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view". +// TypeError 2527: (C.sol:451-458): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view". +// TypeError 2527: (C.sol:523-530): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view". +// TypeError 2527: (C.sol:597-604): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view". +// TypeError 2527: (C.sol:676-683): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view". diff --git a/test/libsolidity/syntaxTests/errors/error_with_pure_arguments.sol b/test/libsolidity/syntaxTests/errors/error_with_pure_arguments.sol new file mode 100644 index 000000000000..5d7474f7c397 --- /dev/null +++ b/test/libsolidity/syntaxTests/errors/error_with_pure_arguments.sol @@ -0,0 +1,44 @@ +==== Source: Error.sol ==== + +error ErGlobal(uint); + +contract E { + error Er(uint); +} + +==== Source: C.sol ==== +import * as EMod from "Error.sol"; + +error ErGlobal(uint); + +contract Base { + error ErBase(uint); +} + +contract C is Base { + error Er(uint); + + uint constant g_error = 1; + + function test1() pure private { + revert EMod.ErGlobal(g_error); + } + function test2() pure private { + revert EMod.E.Er(g_error); + } + function test3() pure private { + revert ErGlobal(g_error); + } + function test4() pure private { + revert Er(g_error); + } + function test5() pure private { + revert C.Er(g_error); + } + function test6() pure private { + revert ErBase(g_error); + } + function test7() pure private { + revert Base.ErBase(g_error); + } +} \ No newline at end of file diff --git a/test/libsolidity/syntaxTests/immutable/inheritance_virtual_functions_direct_call.sol b/test/libsolidity/syntaxTests/immutable/inheritance_virtual_functions_direct_call.sol index b8ca24a2febd..46d184a7e782 100644 --- a/test/libsolidity/syntaxTests/immutable/inheritance_virtual_functions_direct_call.sol +++ b/test/libsolidity/syntaxTests/immutable/inheritance_virtual_functions_direct_call.sol @@ -16,3 +16,4 @@ contract C is B { } } // ---- +// Warning 6133: (167-174): Statement has no effect. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/134_enum_name_resolution_under_current_contract_name.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/134_enum_name_resolution_under_current_contract_name.sol index 8b0bfae43a8b..25a27ffdded2 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/134_enum_name_resolution_under_current_contract_name.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/134_enum_name_resolution_under_current_contract_name.sol @@ -9,4 +9,5 @@ contract A { } } // ---- +// Warning 6133: (99-104): Statement has no effect. // Warning 2018: (69-111): Function state mutability can be restricted to pure diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/250_member_access_parser_ambiguity.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/250_member_access_parser_ambiguity.sol index 0ab3c1984c31..a534ed803255 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/250_member_access_parser_ambiguity.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/250_member_access_parser_ambiguity.sol @@ -14,3 +14,4 @@ contract C { } } // ---- +// Warning 6133: (228-235): Statement has no effect. diff --git a/test/libsolidity/syntaxTests/purity/declaration_contract_type.sol b/test/libsolidity/syntaxTests/purity/declaration_contract_type.sol new file mode 100644 index 000000000000..73bdce382097 --- /dev/null +++ b/test/libsolidity/syntaxTests/purity/declaration_contract_type.sol @@ -0,0 +1,36 @@ +==== Source: a ==== +contract A {} +library Lib {} +==== Source: b ==== +import "a" as Mod; + +library L { + function f() public pure { + Mod.A; + Mod.Lib; + L; + C; + C.f; + } +} + +contract C { + function f() public pure { + Mod.A; + Mod.Lib; + L; + C; + C.f; + } +} +// ---- +// Warning 6133: (b:71-76): Statement has no effect. +// Warning 6133: (b:86-93): Statement has no effect. +// Warning 6133: (b:103-104): Statement has no effect. +// Warning 6133: (b:114-115): Statement has no effect. +// Warning 6133: (b:125-128): Statement has no effect. +// Warning 6133: (b:191-196): Statement has no effect. +// Warning 6133: (b:206-213): Statement has no effect. +// Warning 6133: (b:223-224): Statement has no effect. +// Warning 6133: (b:234-235): Statement has no effect. +// Warning 6133: (b:245-248): Statement has no effect. diff --git a/test/libsolidity/syntaxTests/purity/declaration_enum_type.sol b/test/libsolidity/syntaxTests/purity/declaration_enum_type.sol new file mode 100644 index 000000000000..469932e844d4 --- /dev/null +++ b/test/libsolidity/syntaxTests/purity/declaration_enum_type.sol @@ -0,0 +1,38 @@ +==== Source: a ==== +enum A { Red, Blue } + +library ALib { + enum LibraryEnum { Red, Blue } +} + +==== Source: b ==== +import "a" as Mod; +enum GlobalEnum { Red, Blue } + +library Lib { + enum LibraryEnum { Red, Blue } +} + +contract C { + enum ContractEnum { Red, Blue } + + function f() public pure { + Mod.A; + GlobalEnum; + C.ContractEnum; + ContractEnum; + Lib.LibraryEnum; + Mod.ALib.LibraryEnum; + GlobalEnum; + ContractEnum; + } +} +// ---- +// Warning 6133: (b:191-196): Statement has no effect. +// Warning 6133: (b:206-216): Statement has no effect. +// Warning 6133: (b:226-240): Statement has no effect. +// Warning 6133: (b:250-262): Statement has no effect. +// Warning 6133: (b:272-287): Statement has no effect. +// Warning 6133: (b:297-317): Statement has no effect. +// Warning 6133: (b:327-337): Statement has no effect. +// Warning 6133: (b:347-359): Statement has no effect. diff --git a/test/libsolidity/syntaxTests/purity/declaration_error_type.sol b/test/libsolidity/syntaxTests/purity/declaration_error_type.sol new file mode 100644 index 000000000000..9186289ae58d --- /dev/null +++ b/test/libsolidity/syntaxTests/purity/declaration_error_type.sol @@ -0,0 +1,38 @@ +==== Source: a ==== +error ErrGlobalMod(); + +contract A { + error ErrContractMod(); +} +library LibMod { + error ErrLibMod(); +} +==== Source: b ==== +import "a" as Mod; + +error ErrGlobal(); + +library Lib { + error ErrLib(); +} + +contract C { + error ErrContract(); + + function f() public pure { + Mod.ErrGlobalMod; + Mod.A.ErrContractMod; + Mod.LibMod.ErrLibMod; + C.ErrContract; + Lib.ErrLib; + // FIXME: These two should generate warnings too. + ErrGlobal; + ErrContract; + } +} +// ---- +// Warning 6133: (b:155-171): Statement has no effect. +// Warning 6133: (b:181-201): Statement has no effect. +// Warning 6133: (b:211-231): Statement has no effect. +// Warning 6133: (b:241-254): Statement has no effect. +// Warning 6133: (b:264-274): Statement has no effect. diff --git a/test/libsolidity/syntaxTests/purity/declaration_event_type.sol b/test/libsolidity/syntaxTests/purity/declaration_event_type.sol new file mode 100644 index 000000000000..9d660a063031 --- /dev/null +++ b/test/libsolidity/syntaxTests/purity/declaration_event_type.sol @@ -0,0 +1,38 @@ +==== Source: a ==== +event EvGlobalMod(); + +contract A { + event EvContractMod(); +} +library LibMod { + event EvLibMod(); +} +==== Source: b ==== +import "a" as Mod; + +event EvGlobal(); + +library Lib { + event EvLib(); +} + +contract C { + event EvContract(); + + function f() public pure { + Mod.EvGlobalMod; + Mod.A.EvContractMod; + Mod.LibMod.EvLibMod; + C.EvContract; + Lib.EvLib; + // FIXME: These two should generate warnings too. + EvGlobal; + EvContract; + } +} +// ---- +// Warning 6133: (b:152-167): Statement has no effect. +// Warning 6133: (b:177-196): Statement has no effect. +// Warning 6133: (b:206-225): Statement has no effect. +// Warning 6133: (b:235-247): Statement has no effect. +// Warning 6133: (b:257-266): Statement has no effect. diff --git a/test/libsolidity/syntaxTests/purity/declaration_function_type.sol b/test/libsolidity/syntaxTests/purity/declaration_function_type.sol new file mode 100644 index 000000000000..e18bb3a33aab --- /dev/null +++ b/test/libsolidity/syntaxTests/purity/declaration_function_type.sol @@ -0,0 +1,56 @@ +==== Source: a ==== +function fooA () {} + +library ALib { + function fooALibInternal () internal {} + function fooALibPublic () public {} + function fooALibExternal () external {} +} + +==== Source: b ==== +import "a" as Mod; +function foo () {} + +library Lib { + function fooLibInternal () internal {} + function fooLibPublic () public {} + function fooLibExternal () external {} +} + +contract B { + function fooBaseInternal() internal {} + function fooBasePublic() public {} + function fooBaseExternal() external {} +} + +contract C is B { + function fooContractPrivate () private {} + function fooContractPublic () public {} + + function f() public pure { + Mod.fooA; + fooContractPublic; // FIXME: This should generate warning too. + fooContractPrivate; // FIXME: This should generate warning too. + C.fooContractPublic; + B.fooBaseInternal; + B.fooBasePublic; + B.fooBaseExternal; + Lib.fooLibInternal; + Mod.ALib.fooALibInternal; + + // TODO: Below functions use external call (delegate call). They need to access the state. They are not pure. + // TODO: On the other hand they can be referenced in `pure` function. + Lib.fooLibPublic; + Lib.fooLibExternal; + Mod.ALib.fooALibPublic; + Mod.ALib.fooALibExternal; + } +} +// ---- +// Warning 6133: (b:470-478): Statement has no effect. +// Warning 6133: (b:632-651): Statement has no effect. +// Warning 6133: (b:661-678): Statement has no effect. +// Warning 6133: (b:688-703): Statement has no effect. +// Warning 6133: (b:713-730): Statement has no effect. +// Warning 6133: (b:740-758): Statement has no effect. +// Warning 6133: (b:768-792): Statement has no effect. diff --git a/test/libsolidity/syntaxTests/purity/declaration_struct_type.sol b/test/libsolidity/syntaxTests/purity/declaration_struct_type.sol new file mode 100644 index 000000000000..75526b51533f --- /dev/null +++ b/test/libsolidity/syntaxTests/purity/declaration_struct_type.sol @@ -0,0 +1,38 @@ +==== Source: a ==== +struct A { uint x; } + +library ALib { + struct LibraryStruct { uint x; } +} + +==== Source: b ==== +import "a" as Mod; +struct GlobalStruct { uint x; } + +library Lib { + struct LibraryStruct { uint x; } +} + +contract C { + struct ContractStruct { uint x; } + + function f() public pure { + Mod.A; + GlobalStruct; + C.ContractStruct; + ContractStruct; + Lib.LibraryStruct; + Mod.ALib.LibraryStruct; + GlobalStruct; + ContractStruct; + } +} +// ---- +// Warning 6133: (b:197-202): Statement has no effect. +// Warning 6133: (b:212-224): Statement has no effect. +// Warning 6133: (b:234-250): Statement has no effect. +// Warning 6133: (b:260-274): Statement has no effect. +// Warning 6133: (b:284-301): Statement has no effect. +// Warning 6133: (b:311-333): Statement has no effect. +// Warning 6133: (b:343-355): Statement has no effect. +// Warning 6133: (b:365-379): Statement has no effect. diff --git a/test/libsolidity/syntaxTests/purity/member_access/contract_instance/constant_contract_functions_declarations_are_pure.sol b/test/libsolidity/syntaxTests/purity/member_access/contract_instance/constant_contract_functions_declarations_are_pure.sol new file mode 100644 index 000000000000..9fdd0bd08c46 --- /dev/null +++ b/test/libsolidity/syntaxTests/purity/member_access/contract_instance/constant_contract_functions_declarations_are_pure.sol @@ -0,0 +1,32 @@ +library L { + function fooLibInternal(C c) internal {} + function fooLibExternal(C c) external {} + function fooLibPublic(C c) public {} +} + +using L for C; + +contract C { + function fooPublic() public {} + function fooExternal() external {} +} + +contract T { + C constant cConst = C(address(1)); + function () external constant fooPublicConstPtr = cConst.fooPublic; + function () external constant fooExternalConstPtr = cConst.fooExternal; + + function test() pure private { + cConst.fooPublic; + cConst.fooExternal; + cConst.fooLibInternal; + cConst.fooLibExternal; + cConst.fooLibPublic; + } +} +// ---- +// Warning 6133: (496-512): Statement has no effect. +// Warning 6133: (522-540): Statement has no effect. +// Warning 6133: (550-571): Statement has no effect. +// Warning 6133: (581-602): Statement has no effect. +// Warning 6133: (612-631): Statement has no effect. diff --git a/test/libsolidity/syntaxTests/purity/member_access/contract_instance/constant_contract_member_getters_are_pure.sol b/test/libsolidity/syntaxTests/purity/member_access/contract_instance/constant_contract_member_getters_are_pure.sol new file mode 100644 index 000000000000..725d6ff15d9b --- /dev/null +++ b/test/libsolidity/syntaxTests/purity/member_access/contract_instance/constant_contract_member_getters_are_pure.sol @@ -0,0 +1,44 @@ +contract A { + function foo() public {} +} + +contract C { + uint256 public value = 0; + uint256 public constant constValue = 0; + + function foo() external {} + function () external public fooPtr = this.foo; + + A constant aConst = A(address(1)); + function () external public constant aFooPtr = aConst.foo; +} + +contract T { + C constant cConst = C(address(1)); + function () external returns(uint256) constant valueGetterConstPtr = cConst.value; + function () external returns(uint256) constant constValueGetterConstPtr = cConst.constValue; + function () external returns(function () external) constant fooPtrGetter = cConst.fooPtr; + function () external returns(function () external) constant aFooPtrGetter = cConst.aFooPtr; + + function test() pure private { + // FIX: "Function declared as pure, but this expression (potentially) reads from the environment or state and + // thus requires "view"." This is not a call of a function but only a function pointer. In case when `cConst` is + // constant is should be pure, similar to `cConst.constValue;`. It is properly marked as pure in `TypeChecker` + // (see warning below), but the `ViewPureChecker` mask this as view, but ir does not read the state. Only + // calling of this function would read the state. + // cConst.value; + // cConst.fooPtr; + cConst.constValue; + cConst.aFooPtr; + } + + function testView() view private { + cConst.value; + cConst.fooPtr; + } +} +// ---- +// Warning 6133: (1372-1389): Statement has no effect. +// Warning 6133: (1399-1413): Statement has no effect. +// Warning 6133: (1469-1481): Statement has no effect. +// Warning 6133: (1491-1504): Statement has no effect. diff --git a/test/libsolidity/syntaxTests/purity/member_access/contract_instance/constant_function_poointer_getter_in_non_constant_contract_is_not_pure.sol b/test/libsolidity/syntaxTests/purity/member_access/contract_instance/constant_function_poointer_getter_in_non_constant_contract_is_not_pure.sol new file mode 100644 index 000000000000..251b0c98a733 --- /dev/null +++ b/test/libsolidity/syntaxTests/purity/member_access/contract_instance/constant_function_poointer_getter_in_non_constant_contract_is_not_pure.sol @@ -0,0 +1,15 @@ +contract A { + function foo() public {} +} + +contract C { + A constant aConst = A(address(1)); + function () external public constant aFooPtr = aConst.foo; +} + +contract T { + C c = C(address(1)); + function () external returns(function () external) constant aFooPtrGetter1 = c.aFooPtr; +} +// ---- +// TypeError 8349: (282-291): Initial value for constant variable has to be compile-time constant. diff --git a/test/libsolidity/syntaxTests/purity/member_access/contract_instance/constant_variable_in_constant_contract_is_not_pure.sol b/test/libsolidity/syntaxTests/purity/member_access/contract_instance/constant_variable_in_constant_contract_is_not_pure.sol new file mode 100644 index 000000000000..78189cc2cbae --- /dev/null +++ b/test/libsolidity/syntaxTests/purity/member_access/contract_instance/constant_variable_in_constant_contract_is_not_pure.sol @@ -0,0 +1,10 @@ +contract C { + uint256 constant public CONST_VAR = 0; +} + +contract T { + C constant c = C(address(1)); + uint256 constant constVarCopy = c.CONST_VAR(); +} +// ---- +// TypeError 8349: (142-155): Initial value for constant variable has to be compile-time constant. diff --git a/test/libsolidity/syntaxTests/purity/member_access/contract_instance/constant_variable_in_non_constant_contract_is_not_pure.sol b/test/libsolidity/syntaxTests/purity/member_access/contract_instance/constant_variable_in_non_constant_contract_is_not_pure.sol new file mode 100644 index 000000000000..ca9d4eff479f --- /dev/null +++ b/test/libsolidity/syntaxTests/purity/member_access/contract_instance/constant_variable_in_non_constant_contract_is_not_pure.sol @@ -0,0 +1,10 @@ +contract C { + uint256 constant public CONST_VAR = 0; +} + +contract T { + C c = C(address(1)); + uint256 constant constVarCopy = c.CONST_VAR(); +} +// ---- +// TypeError 8349: (133-146): Initial value for constant variable has to be compile-time constant. diff --git a/test/libsolidity/syntaxTests/purity/member_access/contract_instance/non_constant_variable_in_constant_contract_is_not_pure.sol b/test/libsolidity/syntaxTests/purity/member_access/contract_instance/non_constant_variable_in_constant_contract_is_not_pure.sol new file mode 100644 index 000000000000..20f85e953b11 --- /dev/null +++ b/test/libsolidity/syntaxTests/purity/member_access/contract_instance/non_constant_variable_in_constant_contract_is_not_pure.sol @@ -0,0 +1,10 @@ +contract C { + uint256 public CONST_VAR = 0; +} + +contract T { + C constant c = C(address(1)); + uint256 constant constVarCopy = c.CONST_VAR(); +} +// ---- +// TypeError 8349: (133-146): Initial value for constant variable has to be compile-time constant. diff --git a/test/libsolidity/syntaxTests/purity/member_access/contract_type_name/constant_variable_is_pure.sol b/test/libsolidity/syntaxTests/purity/member_access/contract_type_name/constant_variable_is_pure.sol new file mode 100644 index 000000000000..4e08f750ccd1 --- /dev/null +++ b/test/libsolidity/syntaxTests/purity/member_access/contract_type_name/constant_variable_is_pure.sol @@ -0,0 +1,23 @@ +library L { + uint constant vLib = 1; +} + +contract B { + uint constant vBase = 1; +} + +contract C is B { + uint256 constant a = L.vLib; + uint256 constant v = C.a; + uint256 constant vBaseCopy = B.vBase; + + function test() pure public { + L.vLib; + C.v; + B.vBase; + } +} +// ---- +// Warning 6133: (254-260): Statement has no effect. +// Warning 6133: (270-273): Statement has no effect. +// Warning 6133: (283-290): Statement has no effect. diff --git a/test/libsolidity/syntaxTests/purity/member_access/contract_type_name/enum_type_is_pure.sol b/test/libsolidity/syntaxTests/purity/member_access/contract_type_name/enum_type_is_pure.sol new file mode 100644 index 000000000000..3201d30a71fc --- /dev/null +++ b/test/libsolidity/syntaxTests/purity/member_access/contract_type_name/enum_type_is_pure.sol @@ -0,0 +1,21 @@ +library L { + enum E { V } +} + +contract Ext { + enum E { V } +} + +contract C { + enum E { V } + + function test() pure public { + L.E; + Ext.E; + C.E; + } +} +// ---- +// Warning 6133: (140-143): Statement has no effect. +// Warning 6133: (153-158): Statement has no effect. +// Warning 6133: (168-171): Statement has no effect. diff --git a/test/libsolidity/syntaxTests/purity/member_access/contract_type_name/error_is_pure.sol b/test/libsolidity/syntaxTests/purity/member_access/contract_type_name/error_is_pure.sol new file mode 100644 index 000000000000..b1d2c2167587 --- /dev/null +++ b/test/libsolidity/syntaxTests/purity/member_access/contract_type_name/error_is_pure.sol @@ -0,0 +1,21 @@ +library L { + error Err(); +} + +contract Ext { + error Err(); +} + +contract C { + error Err(); + + function test() pure public { + L.Err; + Ext.Err; + C.Err; + } +} +// ---- +// Warning 6133: (140-145): Statement has no effect. +// Warning 6133: (155-162): Statement has no effect. +// Warning 6133: (172-177): Statement has no effect. diff --git a/test/libsolidity/syntaxTests/purity/member_access/contract_type_name/event_is_pure.sol b/test/libsolidity/syntaxTests/purity/member_access/contract_type_name/event_is_pure.sol new file mode 100644 index 000000000000..2da437e9b590 --- /dev/null +++ b/test/libsolidity/syntaxTests/purity/member_access/contract_type_name/event_is_pure.sol @@ -0,0 +1,20 @@ +library L { + event Ev(); +} + +contract Ext { + event Ev(); +} + +contract C { + event Ev(); + function test() pure public { + L.Ev; + Ext.Ev; + C.Ev; + } +} +// ---- +// Warning 6133: (136-140): Statement has no effect. +// Warning 6133: (150-156): Statement has no effect. +// Warning 6133: (166-170): Statement has no effect. diff --git a/test/libsolidity/syntaxTests/purity/member_access/contract_type_name/foreign_function_pointer_is_pure.sol b/test/libsolidity/syntaxTests/purity/member_access/contract_type_name/foreign_function_pointer_is_pure.sol new file mode 100644 index 000000000000..209d41d530a3 --- /dev/null +++ b/test/libsolidity/syntaxTests/purity/member_access/contract_type_name/foreign_function_pointer_is_pure.sol @@ -0,0 +1,41 @@ +library L { + function fooInternal() internal {} + + E constant eConst = E(address(1)); + function () external constant public fooPublicEConstPtr = eConst.fooPublic; + function () external constant public fooExternalEConstPtr = eConst.fooExternal; +} + +contract E { + function fooPublic() public {} + function fooExternal() external {} +} + +contract C { + function () internal constant fooInternalLibPtr = L.fooInternal; + + E constant eConst = E(address(1)); + function () external constant fooPublicExtConstPtr = eConst.fooPublic; + function () external constant fooPublicExtConstPtrCopy = C.fooPublicExtConstPtr; + function () external constant fooExternalExtConstPtr = eConst.fooExternal; + function () external constant fooExternalExtConstPtrCopy = C.fooExternalExtConstPtr; + + function () external constant fooLibPublicEConstPtr = L.fooPublicEConstPtr; + function () external constant fooLibExternalEConstPtr = L.fooExternalEConstPtr; + + function test() pure public { + L.fooInternal; + + E.fooPublic; + E.fooExternal; + + C.fooPublicExtConstPtr; + C.fooExternalExtConstPtr; + } +} +// ---- +// Warning 6133: (1006-1019): Statement has no effect. +// Warning 6133: (1030-1041): Statement has no effect. +// Warning 6133: (1051-1064): Statement has no effect. +// Warning 6133: (1075-1097): Statement has no effect. +// Warning 6133: (1107-1131): Statement has no effect. diff --git a/test/libsolidity/syntaxTests/purity/member_access/contract_type_name/local_function_pointer_is_pure.sol b/test/libsolidity/syntaxTests/purity/member_access/contract_type_name/local_function_pointer_is_pure.sol new file mode 100644 index 000000000000..dc4962845673 --- /dev/null +++ b/test/libsolidity/syntaxTests/purity/member_access/contract_type_name/local_function_pointer_is_pure.sol @@ -0,0 +1,56 @@ +contract E { + function fooPublic() public {} + function fooExternal() external {} +} + +contract B { + function fooBasePublic() public {} + function fooBaseExternal() external {} + function fooBaseInternal() internal {} + + E constant eConst = E(address(1)); + function () external constant public fooPublicEConstPtr = eConst.fooPublic; + function () external constant public fooExternalEConstPtr = eConst.fooExternal; +} + +contract C is B { + function () internal constant fooPublicPtr = C.fooPublic; + function () internal constant fooInternalPtr = C.fooInternal; + + function () external constant fooBPublicEConstPtrCopy = C.fooBPublicEConstPtr; + + function () internal constant fooBasePublicPtr = B.fooBasePublic; + function () internal constant fooBaseInternalPtr = B.fooBaseInternal; + + function () external constant fooBPublicEConstPtr = B.fooPublicEConstPtr; + function () external constant fooBExternalEConstPtr = B.fooExternalEConstPtr; + + function fooPublic() public {} + function fooExternal() external {} + function fooInternal() internal {} + + function test() pure public { + C.fooPublic; + C.fooExternal; + C.fooInternal; + + C.fooBPublicEConstPtr; + + B.fooBasePublic; + B.fooBaseExternal; + B.fooBaseInternal; + + B.fooPublicEConstPtr; + B.fooExternalEConstPtr; + } +} +// ---- +// Warning 6133: (1128-1139): Statement has no effect. +// Warning 6133: (1149-1162): Statement has no effect. +// Warning 6133: (1172-1185): Statement has no effect. +// Warning 6133: (1196-1217): Statement has no effect. +// Warning 6133: (1228-1243): Statement has no effect. +// Warning 6133: (1253-1270): Statement has no effect. +// Warning 6133: (1280-1297): Statement has no effect. +// Warning 6133: (1308-1328): Statement has no effect. +// Warning 6133: (1338-1360): Statement has no effect. diff --git a/test/libsolidity/syntaxTests/purity/member_access/contract_type_name/non_constant_base_contract_variable_is_not_pure.sol b/test/libsolidity/syntaxTests/purity/member_access/contract_type_name/non_constant_base_contract_variable_is_not_pure.sol new file mode 100644 index 000000000000..1a0415d2c438 --- /dev/null +++ b/test/libsolidity/syntaxTests/purity/member_access/contract_type_name/non_constant_base_contract_variable_is_not_pure.sol @@ -0,0 +1,10 @@ +contract B { + uint vBase = 1; +} + +contract D1 is B { + uint256 constant vBaseCopy = B.vBase; +} + +// ---- +// TypeError 8349: (88-95): Initial value for constant variable has to be compile-time constant. diff --git a/test/libsolidity/syntaxTests/purity/member_access/contract_type_name/non_constant_local_variable_is_not_pure.sol b/test/libsolidity/syntaxTests/purity/member_access/contract_type_name/non_constant_local_variable_is_not_pure.sol new file mode 100644 index 000000000000..0e13b5bf4d34 --- /dev/null +++ b/test/libsolidity/syntaxTests/purity/member_access/contract_type_name/non_constant_local_variable_is_not_pure.sol @@ -0,0 +1,9 @@ +contract C { + uint v = 1; + function foo() pure private { + C.v; + } +} + +// ---- +// TypeError 2527: (71-74): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view". diff --git a/test/libsolidity/syntaxTests/purity/member_access/contract_type_name/non_internal_library_function_pointer_is_not_pure.sol b/test/libsolidity/syntaxTests/purity/member_access/contract_type_name/non_internal_library_function_pointer_is_not_pure.sol new file mode 100644 index 000000000000..e6009551e2a7 --- /dev/null +++ b/test/libsolidity/syntaxTests/purity/member_access/contract_type_name/non_internal_library_function_pointer_is_not_pure.sol @@ -0,0 +1,14 @@ +library L { + function fooPublic() public {} + function fooExternal() external {} +} + +contract C { + function () external constant fooPublicLibPtr = L.fooPublic; + function () external constant fooExternalLibPtr = L.fooExternal; +} +// ---- +// TypeError 7407: (154-165): Type function () is not implicitly convertible to expected type function () external. Special functions cannot be converted to function types. +// TypeError 8349: (154-165): Initial value for constant variable has to be compile-time constant. +// TypeError 7407: (221-234): Type function () is not implicitly convertible to expected type function () external. Special functions cannot be converted to function types. +// TypeError 8349: (221-234): Initial value for constant variable has to be compile-time constant. diff --git a/test/libsolidity/syntaxTests/purity/member_access/contract_type_name/struct_type_is_pure.sol b/test/libsolidity/syntaxTests/purity/member_access/contract_type_name/struct_type_is_pure.sol new file mode 100644 index 000000000000..c68935a5241d --- /dev/null +++ b/test/libsolidity/syntaxTests/purity/member_access/contract_type_name/struct_type_is_pure.sol @@ -0,0 +1,15 @@ +contract Ext { + struct S { uint256 v; } +} + +contract C { + struct S { uint256 v; } + + function test() pure public { + C.S; + Ext.S; + } +} +// ---- +// Warning 6133: (130-133): Statement has no effect. +// Warning 6133: (143-148): Statement has no effect. diff --git a/test/libsolidity/syntaxTests/purity/member_access/contract_type_name/udvt_is_pure.sol b/test/libsolidity/syntaxTests/purity/member_access/contract_type_name/udvt_is_pure.sol new file mode 100644 index 000000000000..81fd4870173b --- /dev/null +++ b/test/libsolidity/syntaxTests/purity/member_access/contract_type_name/udvt_is_pure.sol @@ -0,0 +1,21 @@ +library L { + type TLib is uint; +} + +contract B { + type TBase is uint; +} + +contract C is B { + type T is uint; + + function test() pure public { + L.TLib; + B.TBase; + C.T; + } +} +// ---- +// Warning 6133: (159-165): Statement has no effect. +// Warning 6133: (175-182): Statement has no effect. +// Warning 6133: (192-195): Statement has no effect. diff --git a/test/libsolidity/syntaxTests/purity/member_access/module/imported_constant_variable_declaration_is_pure.sol b/test/libsolidity/syntaxTests/purity/member_access/module/imported_constant_variable_declaration_is_pure.sol new file mode 100644 index 000000000000..251bba336b2a --- /dev/null +++ b/test/libsolidity/syntaxTests/purity/member_access/module/imported_constant_variable_declaration_is_pure.sol @@ -0,0 +1,18 @@ +==== Source: A.sol ==== +uint256 constant GLOBAL_CONST_VAR = 0; +contract C {} +C constant cInstance = C(address(1)); +==== Source: B.sol ==== +import * as A from "A.sol"; + +contract C { + uint256 constant globalVarConstCopy = A.GLOBAL_CONST_VAR; + + function test() pure private { + A.GLOBAL_CONST_VAR; + A.cInstance; + } +} +// ---- +// Warning 6133: (B.sol:148-166): Statement has no effect. +// Warning 6133: (B.sol:176-187): Statement has no effect. diff --git a/test/libsolidity/syntaxTests/purity/member_access/module/imported_declaration_is_pure.sol b/test/libsolidity/syntaxTests/purity/member_access/module/imported_declaration_is_pure.sol new file mode 100644 index 000000000000..ecf2064316ce --- /dev/null +++ b/test/libsolidity/syntaxTests/purity/member_access/module/imported_declaration_is_pure.sol @@ -0,0 +1,36 @@ +==== Source: A.sol ==== +==== Source: B.sol ==== +import * as A from "A.sol"; +contract BContract {} +enum Enum { VAL } +struct S { uint256 v; } +type UInt is uint256; +error Err(); +event Ev(); +function foo() {} +==== Source: C.sol ==== +import * as B from "B.sol"; + +contract C { + function () constant fooConstPtr = B.foo; + + function test() pure private { + B.BContract; + B.Enum; + B.S; + B.UInt; + B.Err; + B.Ev; + B.foo; + B.A; + } +} +// ---- +// Warning 6133: (C.sol:131-142): Statement has no effect. +// Warning 6133: (C.sol:151-157): Statement has no effect. +// Warning 6133: (C.sol:166-169): Statement has no effect. +// Warning 6133: (C.sol:178-184): Statement has no effect. +// Warning 6133: (C.sol:193-198): Statement has no effect. +// Warning 6133: (C.sol:207-211): Statement has no effect. +// Warning 6133: (C.sol:220-225): Statement has no effect. +// Warning 6133: (C.sol:234-237): Statement has no effect. diff --git a/test/libsolidity/syntaxTests/specialFunctions/abidecode/abi_decode_member_acess.sol b/test/libsolidity/syntaxTests/specialFunctions/abidecode/abi_decode_member_acess.sol index 5078fcdebf3c..b2d8a0fdcfb1 100644 --- a/test/libsolidity/syntaxTests/specialFunctions/abidecode/abi_decode_member_acess.sol +++ b/test/libsolidity/syntaxTests/specialFunctions/abidecode/abi_decode_member_acess.sol @@ -17,3 +17,7 @@ contract C { } } // ---- +// Warning 6133: (210-231): Statement has no effect. +// Warning 6133: (241-266): Statement has no effect. +// Warning 6133: (276-297): Statement has no effect. +// Warning 6133: (307-332): Statement has no effect. diff --git a/test/libsolidity/syntaxTests/storageLayoutSpecifier/struct_defined_in_other_contract.sol b/test/libsolidity/syntaxTests/storageLayoutSpecifier/struct_defined_in_other_contract.sol index bb1bcc0e13ba..826ce4d5a08d 100644 --- a/test/libsolidity/syntaxTests/storageLayoutSpecifier/struct_defined_in_other_contract.sol +++ b/test/libsolidity/syntaxTests/storageLayoutSpecifier/struct_defined_in_other_contract.sol @@ -8,4 +8,4 @@ contract A { contract C is A layout at A.SA { } // ---- -// TypeError 1139: (115-119): The base slot of the storage layout must be a compile-time constant expression. +// TypeError 1763: (115-119): The base slot of the storage layout must evaluate to an integer.