Yul IR generation for member access to type types.

This commit is contained in:
chriseth
2020-04-22 11:25:27 +02:00
parent d0fcd468f6
commit 4908101ad7
10 changed files with 117 additions and 35 deletions
@@ -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;
}