aboutsummaryrefslogtreecommitdiffstats
path: root/AST.cpp
diff options
context:
space:
mode:
authorChristian <c@ethdev.com>2015-01-22 08:02:38 +0800
committerChristian <c@ethdev.com>2015-01-26 17:23:39 +0800
commit941c77c8fadd6195809cd2d572feb64478c4fb20 (patch)
treea4de3710aff5f3f2d9423565fd0e9ecc8708b5bf /AST.cpp
parent19793dab093ae36b5f2b4d1cabfbf54bed3125b1 (diff)
downloaddexon-solidity-941c77c8fadd6195809cd2d572feb64478c4fb20.tar
dexon-solidity-941c77c8fadd6195809cd2d572feb64478c4fb20.tar.gz
dexon-solidity-941c77c8fadd6195809cd2d572feb64478c4fb20.tar.bz2
dexon-solidity-941c77c8fadd6195809cd2d572feb64478c4fb20.tar.lz
dexon-solidity-941c77c8fadd6195809cd2d572feb64478c4fb20.tar.xz
dexon-solidity-941c77c8fadd6195809cd2d572feb64478c4fb20.tar.zst
dexon-solidity-941c77c8fadd6195809cd2d572feb64478c4fb20.zip
Type resolution for function modifiers.
Diffstat (limited to 'AST.cpp')
-rw-r--r--AST.cpp123
1 files changed, 78 insertions, 45 deletions
diff --git a/AST.cpp b/AST.cpp
index a51bbd0c..85d7db6e 100644
--- a/AST.cpp
+++ b/AST.cpp
@@ -41,10 +41,15 @@ TypeError ASTNode::createTypeError(string const& _description) const
return TypeError() << errinfo_sourceLocation(getLocation()) << errinfo_comment(_description);
}
+TypePointer ContractDefinition::getType(ContractDefinition const* _currentContract) const
+{
+ return make_shared<TypeType>(make_shared<ContractType>(*this), _currentContract);
+}
+
void ContractDefinition::checkTypeRequirements()
{
- for (ASTPointer<InheritanceSpecifier> const& base: getBaseContracts())
- base->checkTypeRequirements();
+ for (ASTPointer<InheritanceSpecifier> const& baseSpecifier: getBaseContracts())
+ baseSpecifier->checkTypeRequirements();
checkIllegalOverrides();
@@ -53,6 +58,9 @@ void ContractDefinition::checkTypeRequirements()
BOOST_THROW_EXCEPTION(constructor->getReturnParameterList()->createTypeError(
"Non-empty \"returns\" directive for constructor."));
+ for (ASTPointer<ModifierDefinition> const& modifier: getFunctionModifiers())
+ modifier->checkTypeRequirements();
+
for (ASTPointer<FunctionDefinition> const& function: getDefinedFunctions())
function->checkTypeRequirements();
@@ -89,15 +97,22 @@ FunctionDefinition const* ContractDefinition::getConstructor() const
void ContractDefinition::checkIllegalOverrides() const
{
+ // TODO unify this at a later point. for this we need to put the constness and the access specifier
+ // into the types
map<string, FunctionDefinition const*> functions;
+ map<string, ModifierDefinition const*> modifiers;
// We search from derived to base, so the stored item causes the error.
for (ContractDefinition const* contract: getLinearizedBaseContracts())
+ {
for (ASTPointer<FunctionDefinition> const& function: contract->getDefinedFunctions())
{
if (function->isConstructor())
- continue; // constructors can neither be overriden nor override anything
- FunctionDefinition const*& override = functions[function->getName()];
+ continue; // constructors can neither be overridden nor override anything
+ string const& name = function->getName();
+ if (modifiers.count(name))
+ BOOST_THROW_EXCEPTION(modifiers[name]->createTypeError("Override changes function to modifier."));
+ FunctionDefinition const*& override = functions[name];
if (!override)
override = function.get();
else if (override->isPublic() != function->isPublic() ||
@@ -105,6 +120,18 @@ void ContractDefinition::checkIllegalOverrides() const
FunctionType(*override) != FunctionType(*function))
BOOST_THROW_EXCEPTION(override->createTypeError("Override changes extended function signature."));
}
+ for (ASTPointer<ModifierDefinition> const& modifier: contract->getFunctionModifiers())
+ {
+ string const& name = modifier->getName();
+ if (functions.count(name))
+ BOOST_THROW_EXCEPTION(functions[name]->createTypeError("Override changes modifier to function."));
+ ModifierDefinition const*& override = modifiers[name];
+ if (!override)
+ override = modifier.get();
+ else if (ModifierType(*override) != ModifierType(*modifier))
+ BOOST_THROW_EXCEPTION(override->createTypeError("Override changes modifier signature."));
+ }
+ }
}
vector<pair<FixedHash<4>, FunctionDefinition const*>> const& ContractDefinition::getInterfaceFunctionList() const
@@ -141,6 +168,11 @@ void InheritanceSpecifier::checkTypeRequirements()
BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in constructer call."));
}
+TypePointer StructDefinition::getType(ContractDefinition const*) const
+{
+ return make_shared<TypeType>(make_shared<StructType>(*this));
+}
+
void StructDefinition::checkMemberTypes() const
{
for (ASTPointer<VariableDeclaration> const& member: getMembers())
@@ -169,11 +201,18 @@ void StructDefinition::checkRecursion() const
}
}
+TypePointer FunctionDefinition::getType(ContractDefinition const*) const
+{
+ return make_shared<FunctionType>(*this);
+}
+
void FunctionDefinition::checkTypeRequirements()
{
for (ASTPointer<VariableDeclaration> const& var: getParameters() + getReturnParameters())
if (!var->getType()->canLiveOutsideStorage())
BOOST_THROW_EXCEPTION(var->createTypeError("Type is required to live outside storage."));
+ for (ASTPointer<ModifierInvocation> const& modifier: m_functionModifiers)
+ modifier->checkTypeRequirements();
m_body->checkTypeRequirements();
}
@@ -183,11 +222,40 @@ string FunctionDefinition::getCanonicalSignature() const
return getName() + FunctionType(*this).getCanonicalSignature();
}
+Declaration::LValueType VariableDeclaration::getLValueType() const
+{
+ if (dynamic_cast<FunctionDefinition const*>(getScope()))
+ return Declaration::LValueType::LOCAL;
+ else
+ return Declaration::LValueType::STORAGE;
+}
+
+TypePointer ModifierDefinition::getType(ContractDefinition const*) const
+{
+ return make_shared<ModifierType>(*this);
+}
+
void ModifierDefinition::checkTypeRequirements()
{
m_body->checkTypeRequirements();
}
+void ModifierInvocation::checkTypeRequirements()
+{
+ m_modifierName->checkTypeRequirements();
+ for (ASTPointer<Expression> const& argument: m_arguments)
+ argument->checkTypeRequirements();
+
+ ModifierDefinition const* modifier = dynamic_cast<ModifierDefinition const*>(m_modifierName->getReferencedDeclaration());
+ solAssert(modifier, "Function modifier not found.");
+ vector<ASTPointer<VariableDeclaration>> const& parameters = modifier->getParameters();
+ if (parameters.size() != m_arguments.size())
+ BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for modifier invocation."));
+ for (size_t i = 0; i < m_arguments.size(); ++i)
+ if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameters[i]->getType()))
+ BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in modifier invocation."));
+}
+
void Block::checkTypeRequirements()
{
for (shared_ptr<Statement> const& statement: m_statements)
@@ -399,7 +467,7 @@ void MemberAccess::checkTypeRequirements()
BOOST_THROW_EXCEPTION(createTypeError("Member \"" + *m_memberName + "\" not found or not "
"visible in " + type.toString()));
//@todo later, this will not always be STORAGE
- m_lvalue = type.getCategory() == Type::Category::STRUCT ? LValueType::STORAGE : LValueType::NONE;
+ m_lvalue = type.getCategory() == Type::Category::STRUCT ? Declaration::LValueType::STORAGE : Declaration::LValueType::NONE;
}
void IndexAccess::checkTypeRequirements()
@@ -411,52 +479,17 @@ void IndexAccess::checkTypeRequirements()
MappingType const& type = dynamic_cast<MappingType const&>(*m_base->getType());
m_index->expectType(*type.getKeyType());
m_type = type.getValueType();
- m_lvalue = LValueType::STORAGE;
+ m_lvalue = Declaration::LValueType::STORAGE;
}
void Identifier::checkTypeRequirements()
{
solAssert(m_referencedDeclaration, "Identifier not resolved.");
- VariableDeclaration const* variable = dynamic_cast<VariableDeclaration const*>(m_referencedDeclaration);
- if (variable)
- {
- if (!variable->getType())
- BOOST_THROW_EXCEPTION(createTypeError("Variable referenced before type could be determined."));
- m_type = variable->getType();
- m_lvalue = variable->isLocalVariable() ? LValueType::LOCAL : LValueType::STORAGE;
- return;
- }
- //@todo can we unify these with TypeName::toType()?
- StructDefinition const* structDef = dynamic_cast<StructDefinition const*>(m_referencedDeclaration);
- if (structDef)
- {
- // note that we do not have a struct type here
- m_type = make_shared<TypeType>(make_shared<StructType>(*structDef));
- return;
- }
- FunctionDefinition const* functionDef = dynamic_cast<FunctionDefinition const*>(m_referencedDeclaration);
- if (functionDef)
- {
- // a function reference is not a TypeType, because calling a TypeType converts to the type.
- // Calling a function (e.g. function(12), otherContract.function(34)) does not do a type
- // conversion.
- m_type = make_shared<FunctionType>(*functionDef);
- return;
- }
- ContractDefinition const* contractDef = dynamic_cast<ContractDefinition const*>(m_referencedDeclaration);
- if (contractDef)
- {
- m_type = make_shared<TypeType>(make_shared<ContractType>(*contractDef), m_currentContract);
- return;
- }
- MagicVariableDeclaration const* magicVariable = dynamic_cast<MagicVariableDeclaration const*>(m_referencedDeclaration);
- if (magicVariable)
- {
- m_type = magicVariable->getType();
- return;
- }
- BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Declaration reference of unknown/forbidden type."));
+ m_lvalue = m_referencedDeclaration->getLValueType();
+ m_type = m_referencedDeclaration->getType(m_currentContract);
+ if (!m_type)
+ BOOST_THROW_EXCEPTION(createTypeError("Declaration referenced before type could be determined."));
}
void ElementaryTypeNameExpression::checkTypeRequirements()