From 9eafa1fa1a9fba62ee51365d63966e005dfd4077 Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Wed, 14 Oct 2020 11:17:53 +0200 Subject: [PATCH 1/2] Change type of super to TypeType --- libsolidity/analysis/GlobalContext.cpp | 2 +- libsolidity/analysis/TypeChecker.cpp | 16 ++- libsolidity/analysis/ViewPureChecker.cpp | 5 +- libsolidity/ast/Types.cpp | 109 +++++++------- libsolidity/codegen/ExpressionCompiler.cpp | 136 ++++++++++-------- .../codegen/ir/IRGeneratorForStatements.cpp | 73 ++++++---- 6 files changed, 190 insertions(+), 151 deletions(-) diff --git a/libsolidity/analysis/GlobalContext.cpp b/libsolidity/analysis/GlobalContext.cpp index 2bf893675..29de12009 100644 --- a/libsolidity/analysis/GlobalContext.cpp +++ b/libsolidity/analysis/GlobalContext.cpp @@ -140,7 +140,7 @@ MagicVariableDeclaration const* GlobalContext::currentSuper() const { Type const* type = TypeProvider::emptyTuple(); if (m_currentContract) - type = TypeProvider::contract(*m_currentContract, true); + type = TypeProvider::typeType(TypeProvider::contract(*m_currentContract, true)); m_superPointer[m_currentContract] = make_shared(magicVariableToID("super"), "super", type); } diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index f02673405..5d9e23242 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -2760,9 +2760,12 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) ); if (!funType->bound()) - if (auto contractType = dynamic_cast(exprType)) - if (contractType->isSuper()) + if (auto typeType = dynamic_cast(exprType)) + { + auto contractType = dynamic_cast(typeType->actualType()); + if (contractType && contractType->isSuper()) requiredLookup = VirtualLookup::Super; + } } annotation.requiredLookup = requiredLookup; @@ -2837,8 +2840,13 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) _memberAccess.location(), "\"runtimeCode\" is not available for contracts containing immutable variables." ); - - if (m_currentContract) + if (accessedContractType.isSuper()) + m_errorReporter.typeError( + 3625_error, + _memberAccess.location(), + "\"creationCode\" and \"runtimeCode\" are not available for the \"super\" contract." + ); + else if (m_currentContract) { // TODO in the same way as with ``new``, // this is not properly detecting creation-cycles if they go through diff --git a/libsolidity/analysis/ViewPureChecker.cpp b/libsolidity/analysis/ViewPureChecker.cpp index 385f01b55..375973f21 100644 --- a/libsolidity/analysis/ViewPureChecker.cpp +++ b/libsolidity/analysis/ViewPureChecker.cpp @@ -194,8 +194,8 @@ void ViewPureChecker::endVisit(Identifier const& _identifier) switch (magicVar->type()->category()) { case Type::Category::Contract: - solAssert(_identifier.name() == "this" || _identifier.name() == "super", ""); - if (!dynamic_cast(*magicVar->type()).isSuper()) + solAssert(_identifier.name() == "this", ""); + if (dynamic_cast(magicVar->type())) // reads the address mutability = StateMutability::View; break; @@ -440,4 +440,3 @@ void ViewPureChecker::endVisit(ModifierInvocation const& _modifier) else solAssert(dynamic_cast(_modifier.name().annotation().referencedDeclaration), ""); } - diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index d74efa8c4..b21d867ca 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -2158,36 +2158,8 @@ string ContractType::canonicalName() const MemberList::MemberMap ContractType::nativeMembers(ASTNode const*) const { MemberList::MemberMap members; - if (m_super) - { - // add the most derived of all functions which are visible in derived contracts - auto bases = m_contract.annotation().linearizedBaseContracts; - solAssert(bases.size() >= 1, "linearizedBaseContracts should at least contain the most derived contract."); - // `sliced(1, ...)` ignores the most derived contract, which should not be searchable from `super`. - for (ContractDefinition const* base: bases | boost::adaptors::sliced(1, bases.size())) - for (FunctionDefinition const* function: base->definedFunctions()) - { - if (!function->isVisibleInDerivedContracts() || !function->isImplemented()) - continue; - - auto functionType = TypeProvider::function(*function, FunctionType::Kind::Internal); - bool functionWithEqualArgumentsFound = false; - for (auto const& member: members) - { - if (member.name != function->name()) - continue; - auto memberType = dynamic_cast(member.type); - solAssert(!!memberType, "Override changes type."); - if (!memberType->hasEqualParameterTypes(*functionType)) - continue; - functionWithEqualArgumentsFound = true; - break; - } - if (!functionWithEqualArgumentsFound) - members.emplace_back(function->name(), functionType, function); - } - } - else if (!m_contract.isLibrary()) + solAssert(!m_super, ""); + if (!m_contract.isLibrary()) for (auto const& it: m_contract.interfaceFunctions()) members.emplace_back( it.second->declaration().name(), @@ -3838,7 +3810,11 @@ vector> TypeType::makeStackItems() const { if (auto contractType = dynamic_cast(m_actualType)) if (contractType->contractDefinition().isLibrary()) + { + solAssert(!contractType->isSuper(), ""); return {make_tuple("address", TypeProvider::address())}; + } + return {}; } @@ -3847,32 +3823,65 @@ MemberList::MemberMap TypeType::nativeMembers(ASTNode const* _currentScope) cons MemberList::MemberMap members; if (m_actualType->category() == Category::Contract) { - auto const* contractScope = dynamic_cast(_currentScope); - ContractDefinition const& contract = dynamic_cast(*m_actualType).contractDefinition(); - bool inDerivingScope = contractScope && contractScope->derivesFrom(contract); - - for (auto const* declaration: contract.declarations()) + auto contractType = dynamic_cast(m_actualType); + ContractDefinition const& contract = contractType->contractDefinition(); + if (contractType->isSuper()) { - if (dynamic_cast(declaration)) - continue; - if (declaration->name().empty()) - continue; + // add the most derived of all functions which are visible in derived contracts + auto bases = contract.annotation().linearizedBaseContracts; + solAssert(bases.size() >= 1, "linearizedBaseContracts should at least contain the most derived contract."); + // `sliced(1, ...)` ignores the most derived contract, which should not be searchable from `super`. + for (ContractDefinition const* base: bases | boost::adaptors::sliced(1, bases.size())) + for (FunctionDefinition const* function: base->definedFunctions()) + { + if (!function->isVisibleInDerivedContracts() || !function->isImplemented()) + continue; - if (!contract.isLibrary() && inDerivingScope && declaration->isVisibleInDerivedContracts()) + auto functionType = TypeProvider::function(*function, FunctionType::Kind::Internal); + bool functionWithEqualArgumentsFound = false; + for (auto const& member: members) + { + if (member.name != function->name()) + continue; + auto memberType = dynamic_cast(member.type); + solAssert(!!memberType, "Override changes type."); + if (!memberType->hasEqualParameterTypes(*functionType)) + continue; + functionWithEqualArgumentsFound = true; + break; + } + if (!functionWithEqualArgumentsFound) + members.emplace_back(function->name(), functionType, function); + } + } + else + { + auto const* contractScope = dynamic_cast(_currentScope); + bool inDerivingScope = contractScope && contractScope->derivesFrom(contract); + + for (auto const* declaration: contract.declarations()) { - if ( - auto const* functionDefinition = dynamic_cast(declaration); - functionDefinition && !functionDefinition->isImplemented() + if (dynamic_cast(declaration)) + continue; + if (declaration->name().empty()) + continue; + + if (!contract.isLibrary() && inDerivingScope && declaration->isVisibleInDerivedContracts()) + { + if ( + auto const* functionDefinition = dynamic_cast(declaration); + functionDefinition && !functionDefinition->isImplemented() + ) + members.emplace_back(declaration->name(), declaration->typeViaContractName(), declaration); + else + members.emplace_back(declaration->name(), declaration->type(), declaration); + } + else if ( + (contract.isLibrary() && declaration->isVisibleAsLibraryMember()) || + declaration->isVisibleViaContractTypeAccess() ) members.emplace_back(declaration->name(), declaration->typeViaContractName(), declaration); - else - members.emplace_back(declaration->name(), declaration->type(), declaration); } - else if ( - (contract.isLibrary() && declaration->isVisibleAsLibraryMember()) || - declaration->isVisibleViaContractTypeAccess() - ) - members.emplace_back(declaration->name(), declaration->typeViaContractName(), declaration); } } else if (m_actualType->category() == Category::Enum) diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 0d36fa7de..6f7e1a66a 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1355,59 +1355,72 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) // for internal functions, or enum/struct definitions. if (TypeType const* type = dynamic_cast(_memberAccess.expression().annotation().type)) { - if (dynamic_cast(type->actualType())) + if (auto contractType = dynamic_cast(type->actualType())) { solAssert(_memberAccess.annotation().type, "_memberAccess has no type"); - if (auto variable = dynamic_cast(_memberAccess.annotation().referencedDeclaration)) - appendVariable(*variable, static_cast(_memberAccess)); - else if (auto funType = dynamic_cast(_memberAccess.annotation().type)) + if (contractType->isSuper()) { - switch (funType->kind()) - { - case FunctionType::Kind::Declaration: - break; - case FunctionType::Kind::Internal: - // We do not visit the expression here on purpose, because in the case of an - // internal library function call, this would push the library address forcing - // us to link against it although we actually do not need it. - if (auto const* function = dynamic_cast(_memberAccess.annotation().referencedDeclaration)) - { - solAssert(*_memberAccess.annotation().requiredLookup == VirtualLookup::Static, ""); - utils().pushCombinedFunctionEntryLabel(*function); - } - else - solAssert(false, "Function not found in member access"); - break; - case FunctionType::Kind::Event: - if (!dynamic_cast(_memberAccess.annotation().referencedDeclaration)) - solAssert(false, "event not found"); - // no-op, because the parent node will do the job - break; - case FunctionType::Kind::DelegateCall: - _memberAccess.expression().accept(*this); - m_context << funType->externalIdentifier(); - break; - case FunctionType::Kind::External: - case FunctionType::Kind::Creation: - case FunctionType::Kind::Send: - case FunctionType::Kind::BareCall: - case FunctionType::Kind::BareCallCode: - case FunctionType::Kind::BareDelegateCall: - case FunctionType::Kind::BareStaticCall: - case FunctionType::Kind::Transfer: - case FunctionType::Kind::ECRecover: - case FunctionType::Kind::SHA256: - case FunctionType::Kind::RIPEMD160: - default: - solAssert(false, "unsupported member function"); - } - } - else if (dynamic_cast(_memberAccess.annotation().type)) - { - // no-op + _memberAccess.expression().accept(*this); + solAssert(_memberAccess.annotation().referencedDeclaration, "Referenced declaration not resolved."); + solAssert(*_memberAccess.annotation().requiredLookup == VirtualLookup::Super, ""); + utils().pushCombinedFunctionEntryLabel(m_context.superFunction( + dynamic_cast(*_memberAccess.annotation().referencedDeclaration), + contractType->contractDefinition() + )); } else - _memberAccess.expression().accept(*this); + { + if (auto variable = dynamic_cast(_memberAccess.annotation().referencedDeclaration)) + appendVariable(*variable, static_cast(_memberAccess)); + else if (auto funType = dynamic_cast(_memberAccess.annotation().type)) + { + switch (funType->kind()) + { + case FunctionType::Kind::Declaration: + break; + case FunctionType::Kind::Internal: + // We do not visit the expression here on purpose, because in the case of an + // internal library function call, this would push the library address forcing + // us to link against it although we actually do not need it. + if (auto const* function = dynamic_cast(_memberAccess.annotation().referencedDeclaration)) + { + solAssert(*_memberAccess.annotation().requiredLookup == VirtualLookup::Static, ""); + utils().pushCombinedFunctionEntryLabel(*function); + } + else + solAssert(false, "Function not found in member access"); + break; + case FunctionType::Kind::Event: + if (!dynamic_cast(_memberAccess.annotation().referencedDeclaration)) + solAssert(false, "event not found"); + // no-op, because the parent node will do the job + break; + case FunctionType::Kind::DelegateCall: + _memberAccess.expression().accept(*this); + m_context << funType->externalIdentifier(); + break; + case FunctionType::Kind::External: + case FunctionType::Kind::Creation: + case FunctionType::Kind::Send: + case FunctionType::Kind::BareCall: + case FunctionType::Kind::BareCallCode: + case FunctionType::Kind::BareDelegateCall: + case FunctionType::Kind::BareStaticCall: + case FunctionType::Kind::Transfer: + case FunctionType::Kind::ECRecover: + case FunctionType::Kind::SHA256: + case FunctionType::Kind::RIPEMD160: + default: + solAssert(false, "unsupported member function"); + } + } + else if (dynamic_cast(_memberAccess.annotation().type)) + { + // no-op + } + else + _memberAccess.expression().accept(*this); + } } else if (auto enumType = dynamic_cast(type->actualType())) { @@ -1480,17 +1493,8 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) case Type::Category::Contract: { ContractType const& type = dynamic_cast(*_memberAccess.expression().annotation().type); - if (type.isSuper()) - { - solAssert(!!_memberAccess.annotation().referencedDeclaration, "Referenced declaration not resolved."); - solAssert(*_memberAccess.annotation().requiredLookup == VirtualLookup::Super, ""); - utils().pushCombinedFunctionEntryLabel(m_context.superFunction( - dynamic_cast(*_memberAccess.annotation().referencedDeclaration), - type.contractDefinition() - )); - } // ordinary contract type - else if (Declaration const* declaration = _memberAccess.annotation().referencedDeclaration) + if (Declaration const* declaration = _memberAccess.annotation().referencedDeclaration) { u256 identifier; if (auto const* variable = dynamic_cast(declaration)) @@ -1592,8 +1596,11 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) solAssert(false, "Blockhash has been removed."); else if (member == "creationCode" || member == "runtimeCode") { + // FIXME For super this needs to be fixed TypePointer arg = dynamic_cast(*_memberAccess.expression().annotation().type).typeArgument(); - ContractDefinition const& contract = dynamic_cast(*arg).contractDefinition(); + auto const& contractType = dynamic_cast(*arg); + solAssert(!contractType.isSuper(), ""); + ContractDefinition const& contract = contractType.contractDefinition(); utils().fetchFreeMemoryPointer(); m_context << Instruction::DUP1 << u256(32) << Instruction::ADD; utils().copyContractCodeToMemory(contract, member == "creationCode"); @@ -1610,7 +1617,10 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) else if (member == "name") { TypePointer arg = dynamic_cast(*_memberAccess.expression().annotation().type).typeArgument(); - ContractDefinition const& contract = dynamic_cast(*arg).contractDefinition(); + auto const& contractType = dynamic_cast(*arg); + ContractDefinition const& contract = contractType.isSuper() ? + *contractType.contractDefinition().superContract(m_context.mostDerivedContract()) : + dynamic_cast(*arg).contractDefinition(); utils().allocateMemory(((contract.name().length() + 31) / 32) * 32 + 32); // store string length m_context << u256(contract.name().length()) << Instruction::DUP2 << Instruction::MSTORE; @@ -1960,9 +1970,11 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier) switch (magicVar->type()->category()) { case Type::Category::Contract: - // "this" or "super" - if (!dynamic_cast(*magicVar->type()).isSuper()) + if (dynamic_cast(magicVar->type())) + { + solAssert(_identifier.name() == "this", ""); m_context << Instruction::ADDRESS; + } break; default: break; diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index e44723549..5b7c36ca2 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -884,17 +884,17 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) solAssert(*identifier->annotation().requiredLookup == VirtualLookup::Virtual, ""); functionDef = &functionDef->resolveVirtual(m_context.mostDerivedContract()); } - else - { - ContractType const* type = dynamic_cast(memberAccess->expression().annotation().type); - if (type && type->isSuper()) + else if (auto typeType = dynamic_cast(memberAccess->expression().annotation().type)) + if ( + auto contractType = dynamic_cast(typeType->actualType()); + contractType->isSuper() + ) { - ContractDefinition const* super = type->contractDefinition().superContract(m_context.mostDerivedContract()); + ContractDefinition const* super = contractType->contractDefinition().superContract(m_context.mostDerivedContract()); solAssert(super, "Super contract not available."); solAssert(*memberAccess->annotation().requiredLookup == VirtualLookup::Super, ""); functionDef = &functionDef->resolveVirtual(m_context.mostDerivedContract(), super); } - } solAssert(functionDef && functionDef->isImplemented(), ""); } @@ -1527,19 +1527,8 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) { ContractType const& type = dynamic_cast(*_memberAccess.expression().annotation().type); if (type.isSuper()) - { - solAssert(!!_memberAccess.annotation().referencedDeclaration, "Referenced declaration not resolved."); - ContractDefinition const* super = type.contractDefinition().superContract(m_context.mostDerivedContract()); - solAssert(super, "Super contract not available."); - FunctionDefinition const& resolvedFunctionDef = dynamic_cast( - *_memberAccess.annotation().referencedDeclaration - ).resolveVirtual(m_context.mostDerivedContract(), super); + solAssert(false, ""); - define(_memberAccess) << to_string(resolvedFunctionDef.id()) << "\n"; - solAssert(resolvedFunctionDef.functionType(true), ""); - solAssert(resolvedFunctionDef.functionType(true)->kind() == FunctionType::Kind::Internal, ""); - m_context.internalFunctionAccessed(_memberAccess, resolvedFunctionDef); - } // ordinary contract type else if (Declaration const* declaration = _memberAccess.annotation().referencedDeclaration) { @@ -1649,7 +1638,9 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) else if (member == "creationCode" || member == "runtimeCode") { TypePointer arg = dynamic_cast(*_memberAccess.expression().annotation().type).typeArgument(); - ContractDefinition const& contract = dynamic_cast(*arg).contractDefinition(); + auto const& contractType = dynamic_cast(*arg); + solAssert(!contractType.isSuper(), ""); + ContractDefinition const& contract = contractType.contractDefinition(); m_context.subObjectsCreated().insert(&contract); m_code << Whiskers(R"( let := datasize("") @@ -1669,7 +1660,9 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) else if (member == "interfaceId") { TypePointer arg = dynamic_cast(*_memberAccess.expression().annotation().type).typeArgument(); - ContractDefinition const& contract = dynamic_cast(*arg).contractDefinition(); + auto const& contractType = dynamic_cast(*arg); + solAssert(!contractType.isSuper(), ""); + ContractDefinition const& contract = contractType.contractDefinition(); define(_memberAccess) << formatNumber(u256{contract.interfaceId()} << (256 - 32)) << "\n"; } else if (member == "min" || member == "max") @@ -1790,8 +1783,24 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) if (actualType.category() == Type::Category::Contract) { - if (auto const* variable = dynamic_cast(_memberAccess.annotation().referencedDeclaration)) - handleVariableReference(*variable, _memberAccess); + ContractType const& contractType = dynamic_cast(actualType); + if (contractType.isSuper()) + { + solAssert(!!_memberAccess.annotation().referencedDeclaration, "Referenced declaration not resolved."); + ContractDefinition const* super = contractType.contractDefinition().superContract(m_context.mostDerivedContract()); + solAssert(super, "Super contract not available."); + FunctionDefinition const& resolvedFunctionDef = + dynamic_cast( + *_memberAccess.annotation().referencedDeclaration + ).resolveVirtual(m_context.mostDerivedContract(), super); + + define(_memberAccess) << to_string(resolvedFunctionDef.id()) << "\n"; + solAssert(resolvedFunctionDef.functionType(true), ""); + solAssert(resolvedFunctionDef.functionType(true)->kind() == FunctionType::Kind::Internal, ""); + m_context.internalFunctionAccessed(_memberAccess, resolvedFunctionDef); + } + else if (auto const* variable = dynamic_cast(_memberAccess.annotation().referencedDeclaration)) + handleVariableReference(*variable, _memberAccess); else if (memberFunctionType) { switch (memberFunctionType->kind()) @@ -1812,7 +1821,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) dynamic_cast(_memberAccess.annotation().referencedDeclaration), "Event not found" ); - // the call will do the resolving + // the call will do the resolving break; case FunctionType::Kind::DelegateCall: define(IRVariable(_memberAccess).part("address"), _memberAccess.expression()); @@ -1835,7 +1844,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) } else if (dynamic_cast(_memberAccess.annotation().type)) { - // no-op + // no-op } else // The old code generator had a generic "else" case here @@ -2095,18 +2104,20 @@ void IRGeneratorForStatements::endVisit(Identifier const& _identifier) switch (magicVar->type()->category()) { case Type::Category::Contract: - if (dynamic_cast(*magicVar->type()).isSuper()) - solAssert(_identifier.name() == "super", ""); - else - { - solAssert(_identifier.name() == "this", ""); - define(_identifier) << "address()\n"; - } + solAssert(_identifier.name() == "this", ""); + define(_identifier) << "address()\n"; break; case Type::Category::Integer: solAssert(_identifier.name() == "now", ""); define(_identifier) << "timestamp()\n"; break; + case Type::Category::TypeType: + { + auto typeType = dynamic_cast(magicVar->type()); + if (auto contractType = dynamic_cast(typeType->actualType())) + solAssert(!contractType->isSuper() || _identifier.name() == "super", ""); + break; + } default: break; } From 2348b721bb821b0f1d9cb754a91da281cd9503cc Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Wed, 14 Oct 2020 11:18:22 +0200 Subject: [PATCH 2/2] Tests after changing type of super to TypeType --- libsolidity/codegen/ExpressionCompiler.cpp | 1 - .../metaTypes/name_other_contract.sol | 6 ++- .../semanticTests/metaTypes/super_name.sol | 54 +++++++++++++++++++ .../complex/slither/external_function.sol | 2 + ...icit_conversion_of_super_in_comparison.sol | 12 ++--- ...licit_conversion_of_super_in_operators.sol | 44 +++++++-------- .../not_allowed_conversion_from_super.sol | 2 +- .../inheritance/super_on_external.sol | 2 +- .../metaTypes/codeAccess_super.sol | 14 +++++ .../metaTypes/interfaceid_super.sol | 17 ++++++ .../065_super_excludes_current_contract.sol | 2 +- .../state_variable_selector_super.sol | 2 +- .../unimplemented_super_function.sol | 2 +- .../unimplemented_super_function_derived.sol | 2 +- 14 files changed, 126 insertions(+), 36 deletions(-) create mode 100644 test/libsolidity/semanticTests/metaTypes/super_name.sol create mode 100644 test/libsolidity/syntaxTests/metaTypes/codeAccess_super.sol create mode 100644 test/libsolidity/syntaxTests/metaTypes/interfaceid_super.sol diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 6f7e1a66a..a0fdbd883 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1596,7 +1596,6 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) solAssert(false, "Blockhash has been removed."); else if (member == "creationCode" || member == "runtimeCode") { - // FIXME For super this needs to be fixed TypePointer arg = dynamic_cast(*_memberAccess.expression().annotation().type).typeArgument(); auto const& contractType = dynamic_cast(*arg); solAssert(!contractType.isSuper(), ""); diff --git a/test/libsolidity/semanticTests/metaTypes/name_other_contract.sol b/test/libsolidity/semanticTests/metaTypes/name_other_contract.sol index 069e46532..9eb7ee38e 100644 --- a/test/libsolidity/semanticTests/metaTypes/name_other_contract.sol +++ b/test/libsolidity/semanticTests/metaTypes/name_other_contract.sol @@ -11,7 +11,7 @@ contract C { } } -contract Test { +contract Test is C { function c() public pure returns (string memory) { return type(C).name; } @@ -21,9 +21,13 @@ contract Test { function i() public pure returns (string memory) { return type(I).name; } + function j() public pure returns (string memory) { + return type(super).name; + } } // ---- // c() -> 0x20, 1, "C" // a() -> 0x20, 1, "A" // i() -> 0x20, 1, "I" +// j() -> 0x20, 1, "C" diff --git a/test/libsolidity/semanticTests/metaTypes/super_name.sol b/test/libsolidity/semanticTests/metaTypes/super_name.sol new file mode 100644 index 000000000..ce5490bad --- /dev/null +++ b/test/libsolidity/semanticTests/metaTypes/super_name.sol @@ -0,0 +1,54 @@ +pragma experimental ABIEncoderV2; + +function compareStrings(string memory s1, string memory s2) returns (bool) { + return keccak256(abi.encodePacked(s1)) == keccak256(abi.encodePacked(s2)); +} + +contract A { + string[] r; + function f() public virtual returns (bool) { + r.push(""); + + return false; + } +} + + +contract B is A { + function f() public virtual override returns (bool) { + super.f(); + r.push(type(super).name); + + return false; + } +} + + +contract C is A { + function f() public virtual override returns (bool) { + super.f(); + r.push(type(super).name); + + return false; + } +} + + +contract D is B, C { + function f() public override(B, C) returns (bool) { + super.f(); + r.push(type(super).name); + // Order of calls: D.f, C.f, B.f, A.f + // r contains "", "A", "B", "C" + assert(r.length == 4); + assert(compareStrings(r[0], "")); + assert(compareStrings(r[1], "A")); + assert(compareStrings(r[2], "B")); + assert(compareStrings(r[3], "C")); + + return true; + } +} + +// ---- +// f() -> true diff --git a/test/libsolidity/smtCheckerTests/complex/slither/external_function.sol b/test/libsolidity/smtCheckerTests/complex/slither/external_function.sol index 69da6b331..5bed58f6c 100644 --- a/test/libsolidity/smtCheckerTests/complex/slither/external_function.sol +++ b/test/libsolidity/smtCheckerTests/complex/slither/external_function.sol @@ -84,5 +84,7 @@ contract InternalCall { // Warning 2018: (1212-1274): Function state mutability can be restricted to pure // Warning 2018: (1280-1342): Function state mutability can be restricted to pure // Warning 4588: (771-814): Assertion checker does not yet implement this type of function call. +// Warning 8364: (825-830): Assertion checker does not yet implement type type(contract super ContractWithFunctionNotCalled2) // Warning 4588: (771-814): Assertion checker does not yet implement this type of function call. +// Warning 8364: (825-830): Assertion checker does not yet implement type type(contract super ContractWithFunctionNotCalled2) // Warning 5729: (1403-1408): BMC does not yet implement this type of function call. diff --git a/test/libsolidity/syntaxTests/conversion/implicit_conversion_of_super_in_comparison.sol b/test/libsolidity/syntaxTests/conversion/implicit_conversion_of_super_in_comparison.sol index b2f5ba881..d07594b09 100644 --- a/test/libsolidity/syntaxTests/conversion/implicit_conversion_of_super_in_comparison.sol +++ b/test/libsolidity/syntaxTests/conversion/implicit_conversion_of_super_in_comparison.sol @@ -19,9 +19,9 @@ contract C { } } // ---- -// TypeError 2271: (144-157): Operator != not compatible with types contract super C and contract C -// TypeError 2271: (167-180): Operator != not compatible with types contract C and contract super C -// TypeError 2271: (254-264): Operator != not compatible with types contract super C and contract C -// TypeError 2271: (274-284): Operator != not compatible with types contract C and contract super C -// TypeError 2271: (349-359): Operator != not compatible with types contract super C and contract D -// TypeError 2271: (369-379): Operator != not compatible with types contract D and contract super C +// TypeError 2271: (144-157): Operator != not compatible with types type(contract super C) and contract C +// TypeError 2271: (167-180): Operator != not compatible with types contract C and type(contract super C) +// TypeError 2271: (254-264): Operator != not compatible with types type(contract super C) and contract C +// TypeError 2271: (274-284): Operator != not compatible with types contract C and type(contract super C) +// TypeError 2271: (349-359): Operator != not compatible with types type(contract super C) and contract D +// TypeError 2271: (369-379): Operator != not compatible with types contract D and type(contract super C) diff --git a/test/libsolidity/syntaxTests/conversion/implicit_conversion_of_super_in_operators.sol b/test/libsolidity/syntaxTests/conversion/implicit_conversion_of_super_in_operators.sol index 2cb104dbd..8a803a233 100644 --- a/test/libsolidity/syntaxTests/conversion/implicit_conversion_of_super_in_operators.sol +++ b/test/libsolidity/syntaxTests/conversion/implicit_conversion_of_super_in_operators.sol @@ -30,27 +30,27 @@ contract C { } } // ---- -// TypeError 2271: (49-62): Operator << not compatible with types contract super C and contract C -// TypeError 2271: (72-85): Operator >> not compatible with types contract super C and contract C -// TypeError 2271: (95-107): Operator ^ not compatible with types contract super C and contract C -// TypeError 2271: (117-129): Operator | not compatible with types contract super C and contract C -// TypeError 2271: (139-151): Operator & not compatible with types contract super C and contract C -// TypeError 2271: (162-174): Operator * not compatible with types contract super C and contract C -// TypeError 2271: (184-196): Operator / not compatible with types contract super C and contract C -// TypeError 2271: (206-218): Operator % not compatible with types contract super C and contract C -// TypeError 2271: (228-240): Operator - not compatible with types contract super C and contract C -// TypeError 2271: (250-262): Operator + not compatible with types contract super C and contract C -// TypeError 2271: (272-285): Operator ** not compatible with types contract super C and contract C -// TypeError 2271: (296-309): Operator == not compatible with types contract super C and contract C -// TypeError 2271: (319-332): Operator != not compatible with types contract super C and contract C -// TypeError 2271: (342-355): Operator >= not compatible with types contract super C and contract C -// TypeError 2271: (365-378): Operator <= not compatible with types contract super C and contract C -// TypeError 2271: (388-400): Operator < not compatible with types contract super C and contract C -// TypeError 2271: (410-422): Operator > not compatible with types contract super C and contract C -// TypeError 2271: (433-446): Operator || not compatible with types contract super C and contract C -// TypeError 2271: (456-469): Operator && not compatible with types contract super C and contract C +// TypeError 2271: (49-62): Operator << not compatible with types type(contract super C) and contract C +// TypeError 2271: (72-85): Operator >> not compatible with types type(contract super C) and contract C +// TypeError 2271: (95-107): Operator ^ not compatible with types type(contract super C) and contract C +// TypeError 2271: (117-129): Operator | not compatible with types type(contract super C) and contract C +// TypeError 2271: (139-151): Operator & not compatible with types type(contract super C) and contract C +// TypeError 2271: (162-174): Operator * not compatible with types type(contract super C) and contract C +// TypeError 2271: (184-196): Operator / not compatible with types type(contract super C) and contract C +// TypeError 2271: (206-218): Operator % not compatible with types type(contract super C) and contract C +// TypeError 2271: (228-240): Operator - not compatible with types type(contract super C) and contract C +// TypeError 2271: (250-262): Operator + not compatible with types type(contract super C) and contract C +// TypeError 2271: (272-285): Operator ** not compatible with types type(contract super C) and contract C +// TypeError 2271: (296-309): Operator == not compatible with types type(contract super C) and contract C +// TypeError 2271: (319-332): Operator != not compatible with types type(contract super C) and contract C +// TypeError 2271: (342-355): Operator >= not compatible with types type(contract super C) and contract C +// TypeError 2271: (365-378): Operator <= not compatible with types type(contract super C) and contract C +// TypeError 2271: (388-400): Operator < not compatible with types type(contract super C) and contract C +// TypeError 2271: (410-422): Operator > not compatible with types type(contract super C) and contract C +// TypeError 2271: (433-446): Operator || not compatible with types type(contract super C) and contract C +// TypeError 2271: (456-469): Operator && not compatible with types type(contract super C) and contract C // TypeError 4247: (480-485): Expression has to be an lvalue. -// TypeError 7366: (480-493): Operator -= not compatible with types contract super C and contract C +// TypeError 7366: (480-493): Operator -= not compatible with types type(contract super C) and contract C // TypeError 4247: (503-508): Expression has to be an lvalue. -// TypeError 7366: (503-516): Operator += not compatible with types contract super C and contract C -// TypeError 1080: (527-546): True expression's type contract super C does not match false expression's type contract C. +// TypeError 7366: (503-516): Operator += not compatible with types type(contract super C) and contract C +// TypeError 1080: (527-546): True expression's type type(contract super C) does not match false expression's type contract C. diff --git a/test/libsolidity/syntaxTests/conversion/not_allowed_conversion_from_super.sol b/test/libsolidity/syntaxTests/conversion/not_allowed_conversion_from_super.sol index e2af196ee..749a9b0d9 100644 --- a/test/libsolidity/syntaxTests/conversion/not_allowed_conversion_from_super.sol +++ b/test/libsolidity/syntaxTests/conversion/not_allowed_conversion_from_super.sol @@ -12,4 +12,4 @@ contract B is S } } // ---- -// TypeError 9640: (129-137): Explicit type conversion not allowed from "contract super B" to "contract S". +// TypeError 9640: (129-137): Explicit type conversion not allowed from "type(contract super B)" to "contract S". diff --git a/test/libsolidity/syntaxTests/inheritance/super_on_external.sol b/test/libsolidity/syntaxTests/inheritance/super_on_external.sol index 1030beab4..1fd7483c2 100644 --- a/test/libsolidity/syntaxTests/inheritance/super_on_external.sol +++ b/test/libsolidity/syntaxTests/inheritance/super_on_external.sol @@ -7,4 +7,4 @@ contract B is A { } } // ---- -// TypeError 9582: (123-130): Member "f" not found or not visible after argument-dependent lookup in contract super B. +// TypeError 9582: (123-130): Member "f" not found or not visible after argument-dependent lookup in type(contract super B). diff --git a/test/libsolidity/syntaxTests/metaTypes/codeAccess_super.sol b/test/libsolidity/syntaxTests/metaTypes/codeAccess_super.sol new file mode 100644 index 000000000..942d37824 --- /dev/null +++ b/test/libsolidity/syntaxTests/metaTypes/codeAccess_super.sol @@ -0,0 +1,14 @@ +contract Other { + function f(uint) public pure returns (uint) {} +} +contract SuperTest is Other { + function creationSuper() public pure returns (bytes memory) { + return type(super).creationCode; + } + function runtimeOther() public pure returns (bytes memory) { + return type(super).runtimeCode; + } +} +// ---- +// TypeError 3625: (172-196): "creationCode" and "runtimeCode" are not available for the "super" contract. +// TypeError 3625: (272-295): "creationCode" and "runtimeCode" are not available for the "super" contract. diff --git a/test/libsolidity/syntaxTests/metaTypes/interfaceid_super.sol b/test/libsolidity/syntaxTests/metaTypes/interfaceid_super.sol new file mode 100644 index 000000000..d96a43003 --- /dev/null +++ b/test/libsolidity/syntaxTests/metaTypes/interfaceid_super.sol @@ -0,0 +1,17 @@ +interface ERC165 { + /// @notice Query if a contract implements an interface + /// @param interfaceID The interface identifier, as specified in ERC-165 + /// @dev Interface identification is specified in ERC-165. This function + /// uses less than 30,000 gas. + /// @return `true` if the contract implements `interfaceID` and + /// `interfaceID` is not 0xffffffff, `false` otherwise + function supportsInterface(bytes4 interfaceID) external view returns (bool); +} + +abstract contract Test is ERC165 { + function hello() public pure returns (bytes4 data){ + return type(super).interfaceID; + } +} +// ---- +// TypeError 9582: (587-610): Member "interfaceID" not found or not visible after argument-dependent lookup in type(contract super Test). diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/065_super_excludes_current_contract.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/065_super_excludes_current_contract.sol index 62d4d7b34..d94f5bcc6 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/065_super_excludes_current_contract.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/065_super_excludes_current_contract.sol @@ -8,4 +8,4 @@ contract B is A { } } // ---- -// TypeError 9582: (95-102): Member "f" not found or not visible after argument-dependent lookup in contract super B. +// TypeError 9582: (95-102): Member "f" not found or not visible after argument-dependent lookup in type(contract super B). diff --git a/test/libsolidity/syntaxTests/types/function_types/selector/state_variable_selector_super.sol b/test/libsolidity/syntaxTests/types/function_types/selector/state_variable_selector_super.sol index 36d3b013a..0aab02207 100644 --- a/test/libsolidity/syntaxTests/types/function_types/selector/state_variable_selector_super.sol +++ b/test/libsolidity/syntaxTests/types/function_types/selector/state_variable_selector_super.sol @@ -6,4 +6,4 @@ contract C is B { bytes4 constant s4 = super.g.selector; } // ---- -// TypeError 9582: (93-100): Member "g" not found or not visible after argument-dependent lookup in contract super C. +// TypeError 9582: (93-100): Member "g" not found or not visible after argument-dependent lookup in type(contract super C). diff --git a/test/libsolidity/syntaxTests/unimplemented_super_function.sol b/test/libsolidity/syntaxTests/unimplemented_super_function.sol index 5da68a0ea..22b98df02 100644 --- a/test/libsolidity/syntaxTests/unimplemented_super_function.sol +++ b/test/libsolidity/syntaxTests/unimplemented_super_function.sol @@ -5,4 +5,4 @@ contract b is a { function f() public override { super.f(); } } // ---- -// TypeError 9582: (110-117): Member "f" not found or not visible after argument-dependent lookup in contract super b. +// TypeError 9582: (110-117): Member "f" not found or not visible after argument-dependent lookup in type(contract super b). diff --git a/test/libsolidity/syntaxTests/unimplemented_super_function_derived.sol b/test/libsolidity/syntaxTests/unimplemented_super_function_derived.sol index f3213e72f..6a683b461 100644 --- a/test/libsolidity/syntaxTests/unimplemented_super_function_derived.sol +++ b/test/libsolidity/syntaxTests/unimplemented_super_function_derived.sol @@ -9,4 +9,4 @@ contract c is a,b { function f() public override(a, b) { super.f(); } } // ---- -// TypeError 9582: (118-125): Member "f" not found or not visible after argument-dependent lookup in contract super b. +// TypeError 9582: (118-125): Member "f" not found or not visible after argument-dependent lookup in type(contract super b).