Merge pull request #8685 from ethereum/yulForTypeType

Yul codegen for member access to type type
This commit is contained in:
chriseth 2020-04-22 14:27:19 +02:00 committed by GitHub
commit 14fc9e740c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 117 additions and 35 deletions

View File

@ -985,12 +985,74 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
}
case Type::Category::TypeType:
{
TypeType const& type = dynamic_cast<TypeType const&>(*_memberAccess.expression().annotation().type);
solUnimplementedAssert(type.actualType()->category() == Type::Category::Contract, "");
FunctionType const* funType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type);
solUnimplementedAssert(funType, "");
solUnimplementedAssert(funType->kind() == FunctionType::Kind::Declaration, "");
// Nothing to do for declaration.
Type const& actualType = *dynamic_cast<TypeType const&>(
*_memberAccess.expression().annotation().type
).actualType();
if (actualType.category() == Type::Category::Contract)
{
if (auto const* variable = dynamic_cast<VariableDeclaration const*>(_memberAccess.annotation().referencedDeclaration))
handleVariableReference(*variable, _memberAccess);
else if (auto const* funType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type))
{
switch (funType->kind())
{
case FunctionType::Kind::Declaration:
break;
case FunctionType::Kind::Internal:
if (auto const* function = dynamic_cast<FunctionDefinition const*>(_memberAccess.annotation().referencedDeclaration))
define(_memberAccess) << to_string(function->id()) << "\n";
else
solAssert(false, "Function not found in member access");
break;
case FunctionType::Kind::Event:
solAssert(
dynamic_cast<EventDefinition const*>(_memberAccess.annotation().referencedDeclaration),
"Event not found"
);
// the call will do the resolving
break;
case FunctionType::Kind::DelegateCall:
define(IRVariable(_memberAccess).part("address"), _memberAccess.expression());
define(IRVariable(_memberAccess).part("functionIdentifier")) << formatNumber(funType->externalIdentifier()) << "\n";
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::Log0:
case FunctionType::Kind::Log1:
case FunctionType::Kind::Log2:
case FunctionType::Kind::Log3:
case FunctionType::Kind::Log4:
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
// The old code generator had a generic "else" case here
// without any specific code being generated,
// but it would still be better to have an exhaustive list.
solAssert(false, "");
}
else if (EnumType const* enumType = dynamic_cast<EnumType const*>(&actualType))
define(_memberAccess) << to_string(enumType->memberValue(_memberAccess.memberName())) << "\n";
else
// The old code generator had a generic "else" case here
// without any specific code being generated,
// but it would still be better to have an exhaustive list.
solAssert(false, "");
break;
}
default:
@ -1208,28 +1270,7 @@ void IRGeneratorForStatements::endVisit(Identifier const& _identifier)
else if (FunctionDefinition const* functionDef = dynamic_cast<FunctionDefinition const*>(declaration))
define(_identifier) << to_string(functionDef->resolveVirtual(m_context.mostDerivedContract()).id()) << "\n";
else if (VariableDeclaration const* varDecl = dynamic_cast<VariableDeclaration const*>(declaration))
{
// TODO for the constant case, we have to be careful:
// If the value is visited twice, `defineExpression` is called twice on
// the same expression.
solUnimplementedAssert(!varDecl->isConstant(), "");
solUnimplementedAssert(!varDecl->immutable(), "");
if (m_context.isLocalVariable(*varDecl))
setLValue(_identifier, IRLValue{
*varDecl->annotation().type,
IRLValue::Stack{m_context.localVariable(*varDecl)}
});
else if (m_context.isStateVariable(*varDecl))
setLValue(_identifier, IRLValue{
*varDecl->annotation().type,
IRLValue::Storage{
toCompactHexWithPrefix(m_context.storageLocationOfVariable(*varDecl).first),
m_context.storageLocationOfVariable(*varDecl).second
}
});
else
solAssert(false, "Invalid variable kind.");
}
handleVariableReference(*varDecl, _identifier);
else if (auto contract = dynamic_cast<ContractDefinition const*>(declaration))
{
solUnimplementedAssert(!contract->isLibrary(), "Libraries not yet supported.");
@ -1271,6 +1312,33 @@ bool IRGeneratorForStatements::visit(Literal const& _literal)
return false;
}
void IRGeneratorForStatements::handleVariableReference(
VariableDeclaration const& _variable,
Expression const& _referencingExpression
)
{
// TODO for the constant case, we have to be careful:
// If the value is visited twice, `defineExpression` is called twice on
// the same expression.
solUnimplementedAssert(!_variable.isConstant(), "");
solUnimplementedAssert(!_variable.immutable(), "");
if (m_context.isLocalVariable(_variable))
setLValue(_referencingExpression, IRLValue{
*_variable.annotation().type,
IRLValue::Stack{m_context.localVariable(_variable)}
});
else if (m_context.isStateVariable(_variable))
setLValue(_referencingExpression, IRLValue{
*_variable.annotation().type,
IRLValue::Storage{
toCompactHexWithPrefix(m_context.storageLocationOfVariable(_variable).first),
m_context.storageLocationOfVariable(_variable).second
}
});
else
solAssert(false, "Invalid variable kind.");
}
void IRGeneratorForStatements::appendExternalFunctionCall(
FunctionCall const& _functionCall,
vector<ASTPointer<Expression const>> const& _arguments
@ -1890,4 +1958,3 @@ bool IRGeneratorForStatements::visit(TryCatchClause const& _clause)
_clause.block().accept(*this);
return false;
}

View File

@ -87,6 +87,11 @@ private:
/// Generates code to rethrow an exception.
void rethrow();
void handleVariableReference(
VariableDeclaration const& _variable,
Expression const& _referencingExpression
);
/// Appends code to call an external function with the given arguments.
/// All involved expressions have already been visited.
void appendExternalFunctionCall(

View File

@ -6,5 +6,7 @@ contract test {
}
}
// ====
// compileViaYul: also
// ----
// answer() -> 1

View File

@ -12,5 +12,7 @@ contract test {
ActionChoices choices;
}
// ====
// compileViaYul: also
// ----
// getChoice() -> 2

View File

@ -8,6 +8,7 @@ contract test is base {
_ret = Choice.B;
}
}
// ====
// compileViaYul: also
// ----
// answer() -> 1

View File

@ -8,6 +8,7 @@ contract test is base {
_ret = base.Choice.B;
}
}
// ====
// compileViaYul: also
// ----
// answer() -> 1

View File

@ -21,7 +21,8 @@ contract Derived is Base {
return 3;
}
}
// ====
// compileViaYul: also
// ----
// g() -> 3
// f() -> 1

View File

@ -14,6 +14,7 @@ contract B is A {
return A.f();
}
}
// ====
// compileViaYul: also
// ----
// g() -> 1

View File

@ -6,6 +6,7 @@ contract A {
x = A.y;
}
}
// ====
// compileViaYul: also
// ----
// a() -> 2

View File

@ -5,6 +5,7 @@ contract Scope {
stateVar = Scope.stateVar;
}
}
// ====
// compileViaYul: also
// ----
// getStateVar() -> 42