aboutsummaryrefslogtreecommitdiffstats
path: root/AST.cpp
diff options
context:
space:
mode:
authorLu Guanqun <guanqun.lu@gmail.com>2015-03-01 11:34:39 +0800
committerLu Guanqun <guanqun.lu@gmail.com>2015-03-08 22:50:06 +0800
commit3b9b71e0ae86cc20c6a0201b027bd45bee4257e5 (patch)
treec3b1ffc4e5d6d2e8013733401289928cfc51d086 /AST.cpp
parente008f3f808b1483e7b7a5861ea4fe46fbe74bcff (diff)
downloaddexon-solidity-3b9b71e0ae86cc20c6a0201b027bd45bee4257e5.tar.gz
dexon-solidity-3b9b71e0ae86cc20c6a0201b027bd45bee4257e5.tar.zst
dexon-solidity-3b9b71e0ae86cc20c6a0201b027bd45bee4257e5.zip
implement overload resolution
Diffstat (limited to 'AST.cpp')
-rw-r--r--AST.cpp159
1 files changed, 153 insertions, 6 deletions
diff --git a/AST.cpp b/AST.cpp
index 79b755e9..428c82f2 100644
--- a/AST.cpp
+++ b/AST.cpp
@@ -76,6 +76,15 @@ void ContractDefinition::checkTypeRequirements()
for (ASTPointer<FunctionDefinition> const& function: getDefinedFunctions())
function->checkTypeRequirements();
+ // check for duplicate declaration
+ set<string> functions;
+ for (ASTPointer<FunctionDefinition> const& function: getDefinedFunctions())
+ {
+ string signature = function->getCanonicalSignature();
+ if (functions.count(signature))
+ BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_comment("Duplicate functions are not allowed."));
+ functions.insert(signature);
+ }
for (ASTPointer<VariableDeclaration> const& variable: m_stateVariables)
variable->checkTypeRequirements();
@@ -129,6 +138,7 @@ 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;
+ set<string> functionNames;
map<string, ModifierDefinition const*> modifiers;
// We search from derived to base, so the stored item causes the error.
@@ -141,7 +151,8 @@ void ContractDefinition::checkIllegalOverrides() const
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];
+ FunctionDefinition const*& override = functions[function->getCanonicalSignature()];
+ functionNames.insert(name);
if (!override)
override = function.get();
else if (override->getVisibility() != function->getVisibility() ||
@@ -152,13 +163,13 @@ void ContractDefinition::checkIllegalOverrides() const
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."));
+ if (functionNames.count(name))
+ BOOST_THROW_EXCEPTION(override->createTypeError("Override changes modifier to function."));
}
}
}
@@ -185,16 +196,21 @@ vector<pair<FixedHash<4>, FunctionTypePointer>> const& ContractDefinition::getIn
if (!m_interfaceFunctionList)
{
set<string> functionsSeen;
+ set<string> signaturesSeen;
m_interfaceFunctionList.reset(new vector<pair<FixedHash<4>, FunctionTypePointer>>());
for (ContractDefinition const* contract: getLinearizedBaseContracts())
{
for (ASTPointer<FunctionDefinition> const& f: contract->getDefinedFunctions())
- if (f->isPublic() && !f->isConstructor() && !f->getName().empty() && functionsSeen.count(f->getName()) == 0)
+ {
+ string functionSignature = f->getCanonicalSignature();
+ if (f->isPublic() && !f->isConstructor() && !f->getName().empty() && signaturesSeen.count(functionSignature) == 0)
{
functionsSeen.insert(f->getName());
- FixedHash<4> hash(dev::sha3(f->getCanonicalSignature()));
+ signaturesSeen.insert(functionSignature);
+ FixedHash<4> hash(dev::sha3(functionSignature));
m_interfaceFunctionList->push_back(make_pair(hash, make_shared<FunctionType>(*f, false)));
}
+ }
for (ASTPointer<VariableDeclaration> const& v: contract->getStateVariables())
if (v->isPublic() && functionsSeen.count(v->getName()) == 0)
@@ -467,7 +483,43 @@ void Return::checkTypeRequirements()
void VariableDeclarationStatement::checkTypeRequirements()
{
+<<<<<<< HEAD
m_variable->checkTypeRequirements();
+=======
+ // Variables can be declared without type (with "var"), in which case the first assignment
+ // sets the type.
+ // Note that assignments before the first declaration are legal because of the special scoping
+ // rules inherited from JavaScript.
+ if (m_variable->getValue())
+ {
+ if (m_variable->getType())
+ {
+ std::cout << "getType() ok" << std::endl;
+ m_variable->getValue()->expectType(*m_variable->getType());
+ }
+ else
+ {
+ // no type declared and no previous assignment, infer the type
+ std::cout << "here's where called...." << std::endl;
+ Identifier* identifier = dynamic_cast<Identifier*>(m_variable->getValue().get());
+ if (identifier)
+ identifier->checkTypeRequirementsFromVariableDeclaration();
+ else
+ m_variable->getValue()->checkTypeRequirements();
+ TypePointer type = m_variable->getValue()->getType();
+ if (type->getCategory() == Type::Category::IntegerConstant)
+ {
+ auto intType = dynamic_pointer_cast<IntegerConstantType const>(type)->getIntegerType();
+ if (!intType)
+ BOOST_THROW_EXCEPTION(m_variable->getValue()->createTypeError("Invalid integer constant " + type->toString()));
+ type = intType;
+ }
+ else if (type->getCategory() == Type::Category::Void)
+ BOOST_THROW_EXCEPTION(m_variable->createTypeError("var cannot be void type"));
+ m_variable->setType(type);
+ }
+ }
+>>>>>>> implement overload resolution
}
void Assignment::checkTypeRequirements()
@@ -544,10 +596,16 @@ void BinaryOperation::checkTypeRequirements()
void FunctionCall::checkTypeRequirements()
{
- m_expression->checkTypeRequirements();
+ // we need to check arguments' type first as their info will be used by m_express(Identifier).
for (ASTPointer<Expression> const& argument: m_arguments)
argument->checkTypeRequirements();
+ auto identifier = dynamic_cast<Identifier*>(m_expression.get());
+ if (identifier)
+ identifier->checkTypeRequirementsWithFunctionCall(*this);
+ else
+ m_expression->checkTypeRequirements();
+
Type const* expressionType = m_expression->getType().get();
if (isTypeConversion())
{
@@ -617,6 +675,19 @@ void FunctionCall::checkTypeRequirements()
else
m_type = functionType->getReturnParameterTypes().front();
}
+ else if (OverloadedFunctionType const* overloadedTypes = dynamic_cast<OverloadedFunctionType const*>(expressionType))
+ {
+ // this only applies to "x(3)" where x is assigned by "var x = f;" where f is an overloaded functions.
+ overloadedTypes->m_identifier->overloadResolution(*this);
+ FunctionType const* functionType = dynamic_cast<FunctionType const*>(overloadedTypes->m_identifier->getType().get());
+
+ // @todo actually the return type should be an anonymous struct,
+ // but we change it to the type of the first return value until we have structs
+ if (functionType->getReturnParameterTypes().empty())
+ m_type = make_shared<VoidType>();
+ else
+ m_type = functionType->getReturnParameterTypes().front();
+ }
else
BOOST_THROW_EXCEPTION(createTypeError("Type is not callable."));
}
@@ -709,16 +780,92 @@ void IndexAccess::checkTypeRequirements()
}
}
+void Identifier::checkTypeRequirementsWithFunctionCall(FunctionCall const& _functionCall)
+{
+ solAssert(m_referencedDeclaration || !m_overloadedDeclarations.empty(), "Identifier not resolved.");
+
+ if (!m_referencedDeclaration)
+ overloadResolution(_functionCall);
+
+ checkTypeRequirements();
+}
+
+void Identifier::checkTypeRequirementsFromVariableDeclaration()
+{
+ solAssert(m_referencedDeclaration || !m_overloadedDeclarations.empty(), "Identifier not resolved.");
+
+ if (!m_referencedDeclaration)
+ m_type = make_shared<OverloadedFunctionType>(m_overloadedDeclarations, this);
+ else
+ checkTypeRequirements();
+
+ m_isLValue = true;
+}
+
void Identifier::checkTypeRequirements()
{
+ // var x = f; TODO!
solAssert(m_referencedDeclaration, "Identifier not resolved.");
m_isLValue = m_referencedDeclaration->isLValue();
+ if (m_isLValue)
+ std::cout << "Identifier: " << string(getName()) << " -> true" << std::endl;
+ else
+ std::cout << "Identifier: " << string(getName()) << " -> true" << std::endl;
m_type = m_referencedDeclaration->getType(m_currentContract);
if (!m_type)
BOOST_THROW_EXCEPTION(createTypeError("Declaration referenced before type could be determined."));
}
+void Identifier::overloadResolution(FunctionCall const& _functionCall)
+{
+ solAssert(m_overloadedDeclarations.size() > 1, "FunctionIdentifier not resolved.");
+ solAssert(!m_referencedDeclaration, "Referenced declaration should be null before overload resolution.");
+
+ bool resolved = false;
+
+ std::vector<ASTPointer<Expression const>> arguments = _functionCall.getArguments();
+ std::vector<ASTPointer<ASTString>> const& argumentNames = _functionCall.getNames();
+
+ if (argumentNames.empty())
+ {
+ // positional arguments
+ std::vector<Declaration const*> possibles;
+ for (Declaration const* declaration: m_overloadedDeclarations)
+ {
+ TypePointer const& function = declaration->getType();
+ auto const& functionType = dynamic_cast<FunctionType const&>(*function);
+ TypePointers const& parameterTypes = functionType.getParameterTypes();
+
+ if (functionType.takesArbitraryParameters() ||
+ (arguments.size() == parameterTypes.size() &&
+ std::equal(arguments.cbegin(), arguments.cend(), parameterTypes.cbegin(),
+ [](ASTPointer<Expression const> const& argument, TypePointer const& parameterType)
+ {
+ return argument->getType()->isImplicitlyConvertibleTo(*parameterType);
+ })))
+ possibles.push_back(declaration);
+ }
+ std::cout << "possibles: " << possibles.size() << std::endl;
+ if (possibles.empty())
+ BOOST_THROW_EXCEPTION(createTypeError("Can't resolve identifier"));
+ else if (std::none_of(possibles.cbegin() + 1, possibles.cend(),
+ [&possibles](Declaration const* declaration)
+ {
+ return declaration->getScope() == possibles.front()->getScope();
+ }))
+ setReferencedDeclaration(*possibles.front());
+ else
+ BOOST_THROW_EXCEPTION(createTypeError("Can't resolve identifier"));
+ }
+ else
+ {
+ // named arguments
+ // TODO: don't support right now
+ // BOOST_THROW_EXCEPTION(createTypeError("Named arguments with overloaded functions are not supported yet."));
+ }
+}
+
void ElementaryTypeNameExpression::checkTypeRequirements()
{
m_type = make_shared<TypeType>(Type::fromElementaryTypeName(m_typeToken));