Merge pull request #10029 from ethereum/super-typetype

[BREAKING] Change type of Super to TypeType
This commit is contained in:
chriseth 2020-11-10 16:13:16 +01:00 committed by GitHub
commit d5f59d2914
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 315 additions and 186 deletions

View File

@ -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<MagicVariableDeclaration>(magicVariableToID("super"), "super", type);
}

View File

@ -2760,9 +2760,12 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
);
if (!funType->bound())
if (auto contractType = dynamic_cast<ContractType const*>(exprType))
if (contractType->isSuper())
if (auto typeType = dynamic_cast<TypeType const*>(exprType))
{
auto contractType = dynamic_cast<ContractType const*>(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

View File

@ -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<ContractType const&>(*magicVar->type()).isSuper())
solAssert(_identifier.name() == "this", "");
if (dynamic_cast<ContractType const*>(magicVar->type()))
// reads the address
mutability = StateMutability::View;
break;
@ -440,4 +440,3 @@ void ViewPureChecker::endVisit(ModifierInvocation const& _modifier)
else
solAssert(dynamic_cast<ContractDefinition const*>(_modifier.name().annotation().referencedDeclaration), "");
}

View File

@ -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<FunctionType const*>(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<tuple<string, TypePointer>> TypeType::makeStackItems() const
{
if (auto contractType = dynamic_cast<ContractType const*>(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<ContractDefinition const*>(_currentScope);
ContractDefinition const& contract = dynamic_cast<ContractType const&>(*m_actualType).contractDefinition();
bool inDerivingScope = contractScope && contractScope->derivesFrom(contract);
for (auto const* declaration: contract.declarations())
auto contractType = dynamic_cast<ContractType const*>(m_actualType);
ContractDefinition const& contract = contractType->contractDefinition();
if (contractType->isSuper())
{
if (dynamic_cast<ModifierDefinition const*>(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<FunctionType const*>(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<ContractDefinition const*>(_currentScope);
bool inDerivingScope = contractScope && contractScope->derivesFrom(contract);
for (auto const* declaration: contract.declarations())
{
if (
auto const* functionDefinition = dynamic_cast<FunctionDefinition const*>(declaration);
functionDefinition && !functionDefinition->isImplemented()
if (dynamic_cast<ModifierDefinition const*>(declaration))
continue;
if (declaration->name().empty())
continue;
if (!contract.isLibrary() && inDerivingScope && declaration->isVisibleInDerivedContracts())
{
if (
auto const* functionDefinition = dynamic_cast<FunctionDefinition const*>(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)

View File

@ -1355,59 +1355,72 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
// for internal functions, or enum/struct definitions.
if (TypeType const* type = dynamic_cast<TypeType const*>(_memberAccess.expression().annotation().type))
{
if (dynamic_cast<ContractType const*>(type->actualType()))
if (auto contractType = dynamic_cast<ContractType const*>(type->actualType()))
{
solAssert(_memberAccess.annotation().type, "_memberAccess has no type");
if (auto variable = dynamic_cast<VariableDeclaration const*>(_memberAccess.annotation().referencedDeclaration))
appendVariable(*variable, static_cast<Expression const&>(_memberAccess));
else if (auto funType = dynamic_cast<FunctionType const*>(_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<FunctionDefinition const*>(_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<EventDefinition const*>(_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<TypeType const*>(_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<FunctionDefinition const&>(*_memberAccess.annotation().referencedDeclaration),
contractType->contractDefinition()
));
}
else
_memberAccess.expression().accept(*this);
{
if (auto variable = dynamic_cast<VariableDeclaration const*>(_memberAccess.annotation().referencedDeclaration))
appendVariable(*variable, static_cast<Expression const&>(_memberAccess));
else if (auto funType = dynamic_cast<FunctionType const*>(_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<FunctionDefinition const*>(_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<EventDefinition const*>(_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<TypeType const*>(_memberAccess.annotation().type))
{
// no-op
}
else
_memberAccess.expression().accept(*this);
}
}
else if (auto enumType = dynamic_cast<EnumType const*>(type->actualType()))
{
@ -1480,17 +1493,8 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
case Type::Category::Contract:
{
ContractType const& type = dynamic_cast<ContractType const&>(*_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<FunctionDefinition const&>(*_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<VariableDeclaration const*>(declaration))
@ -1593,7 +1597,9 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
else if (member == "creationCode" || member == "runtimeCode")
{
TypePointer arg = dynamic_cast<MagicType const&>(*_memberAccess.expression().annotation().type).typeArgument();
ContractDefinition const& contract = dynamic_cast<ContractType const&>(*arg).contractDefinition();
auto const& contractType = dynamic_cast<ContractType const&>(*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 +1616,10 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
else if (member == "name")
{
TypePointer arg = dynamic_cast<MagicType const&>(*_memberAccess.expression().annotation().type).typeArgument();
ContractDefinition const& contract = dynamic_cast<ContractType const&>(*arg).contractDefinition();
auto const& contractType = dynamic_cast<ContractType const&>(*arg);
ContractDefinition const& contract = contractType.isSuper() ?
*contractType.contractDefinition().superContract(m_context.mostDerivedContract()) :
dynamic_cast<ContractType const&>(*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 +1969,11 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier)
switch (magicVar->type()->category())
{
case Type::Category::Contract:
// "this" or "super"
if (!dynamic_cast<ContractType const&>(*magicVar->type()).isSuper())
if (dynamic_cast<ContractType const*>(magicVar->type()))
{
solAssert(_identifier.name() == "this", "");
m_context << Instruction::ADDRESS;
}
break;
default:
break;

View File

@ -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<ContractType const*>(memberAccess->expression().annotation().type);
if (type && type->isSuper())
else if (auto typeType = dynamic_cast<TypeType const*>(memberAccess->expression().annotation().type))
if (
auto contractType = dynamic_cast<ContractType const*>(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<ContractType const&>(*_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<FunctionDefinition const&>(
*_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<MagicType const&>(*_memberAccess.expression().annotation().type).typeArgument();
ContractDefinition const& contract = dynamic_cast<ContractType const&>(*arg).contractDefinition();
auto const& contractType = dynamic_cast<ContractType const&>(*arg);
solAssert(!contractType.isSuper(), "");
ContractDefinition const& contract = contractType.contractDefinition();
m_context.subObjectsCreated().insert(&contract);
m_code << Whiskers(R"(
let <size> := datasize("<objectName>")
@ -1669,7 +1660,9 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
else if (member == "interfaceId")
{
TypePointer arg = dynamic_cast<MagicType const&>(*_memberAccess.expression().annotation().type).typeArgument();
ContractDefinition const& contract = dynamic_cast<ContractType const&>(*arg).contractDefinition();
auto const& contractType = dynamic_cast<ContractType const&>(*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<VariableDeclaration const*>(_memberAccess.annotation().referencedDeclaration))
handleVariableReference(*variable, _memberAccess);
ContractType const& contractType = dynamic_cast<ContractType const&>(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<FunctionDefinition const&>(
*_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<VariableDeclaration const*>(_memberAccess.annotation().referencedDeclaration))
handleVariableReference(*variable, _memberAccess);
else if (memberFunctionType)
{
switch (memberFunctionType->kind())
@ -1812,7 +1821,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
dynamic_cast<EventDefinition const*>(_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<TypeType const*>(_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<ContractType const&>(*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<TypeType const*>(magicVar->type());
if (auto contractType = dynamic_cast<ContractType const*>(typeType->actualType()))
solAssert(!contractType->isSuper() || _identifier.name() == "super", "");
break;
}
default:
break;
}

View File

@ -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"

View File

@ -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

View File

@ -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.

View File

@ -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)

View File

@ -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.

View File

@ -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".

View File

@ -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).

View File

@ -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.

View File

@ -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).

View File

@ -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).

View File

@ -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).

View File

@ -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).

View File

@ -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).