diff options
author | Lu Guanqun <guanqun.lu@gmail.com> | 2015-03-01 11:34:39 +0800 |
---|---|---|
committer | Lu Guanqun <guanqun.lu@gmail.com> | 2015-03-08 22:50:06 +0800 |
commit | 3b9b71e0ae86cc20c6a0201b027bd45bee4257e5 (patch) | |
tree | c3b1ffc4e5d6d2e8013733401289928cfc51d086 /AST.cpp | |
parent | e008f3f808b1483e7b7a5861ea4fe46fbe74bcff (diff) | |
download | dexon-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.cpp | 159 |
1 files changed, 153 insertions, 6 deletions
@@ -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)); |