diff options
author | chriseth <c@ethdev.com> | 2015-04-07 23:08:49 +0800 |
---|---|---|
committer | chriseth <c@ethdev.com> | 2015-04-07 23:08:49 +0800 |
commit | 158795e48f4285d713b11f78cdd04de8c6d1f667 (patch) | |
tree | a4194b4dfbac5bcbed9dbd6290e156c945fff56b /AST.cpp | |
parent | ff4d2cc7dc035a248de4698c2c59a8df14db2e82 (diff) | |
parent | 8e19eea7d5d6cd4bffa03f8617023a74268de608 (diff) | |
download | dexon-solidity-158795e48f4285d713b11f78cdd04de8c6d1f667.tar.gz dexon-solidity-158795e48f4285d713b11f78cdd04de8c6d1f667.tar.zst dexon-solidity-158795e48f4285d713b11f78cdd04de8c6d1f667.zip |
Merge remote-tracking branch 'ethereum/develop' into sol_overloadingFunctions
Diffstat (limited to 'AST.cpp')
-rw-r--r-- | AST.cpp | 81 |
1 files changed, 69 insertions, 12 deletions
@@ -21,6 +21,7 @@ */ #include <algorithm> +#include <boost/range/adaptor/reversed.hpp> #include <libsolidity/Utils.h> #include <libsolidity/AST.h> #include <libsolidity/ASTVisitor.h> @@ -52,6 +53,7 @@ void ContractDefinition::checkTypeRequirements() baseSpecifier->checkTypeRequirements(); checkIllegalOverrides(); + checkAbstractFunctions(); FunctionDefinition const* constructor = getConstructor(); if (constructor && !constructor->getReturnParameters().empty()) @@ -60,6 +62,7 @@ void ContractDefinition::checkTypeRequirements() FunctionDefinition const* fallbackFunction = nullptr; for (ASTPointer<FunctionDefinition> const& function: getDefinedFunctions()) + { if (function->getName().empty()) { if (fallbackFunction) @@ -71,6 +74,9 @@ void ContractDefinition::checkTypeRequirements() BOOST_THROW_EXCEPTION(fallbackFunction->getParameterList().createTypeError("Fallback function cannot take parameters.")); } } + if (!function->isFullyImplemented()) + setFullyImplemented(false); + } for (ASTPointer<ModifierDefinition> const& modifier: getFunctionModifiers()) modifier->checkTypeRequirements(); @@ -98,7 +104,7 @@ void ContractDefinition::checkTypeRequirements() if (hashes.count(hash)) BOOST_THROW_EXCEPTION(createTypeError( std::string("Function signature hash collision for ") + - it.second->getCanonicalSignature())); + it.second->externalSignature())); hashes.insert(hash); } } @@ -134,6 +140,28 @@ FunctionDefinition const* ContractDefinition::getFallbackFunction() const return nullptr; } +void ContractDefinition::checkAbstractFunctions() +{ + map<string, bool> functions; + + // Search from base to derived + for (ContractDefinition const* contract: boost::adaptors::reverse(getLinearizedBaseContracts())) + for (ASTPointer<FunctionDefinition> const& function: contract->getDefinedFunctions()) + { + string const& name = function->getName(); + if (!function->isFullyImplemented() && functions.count(name) && functions[name]) + BOOST_THROW_EXCEPTION(function->createTypeError("Redeclaring an already implemented function as abstract")); + functions[name] = function->isFullyImplemented(); + } + + for (auto const& it: functions) + if (!it.second) + { + setFullyImplemented(false); + break; + } +} + void ContractDefinition::checkIllegalOverrides() const { // TODO unify this at a later point. for this we need to put the constness and the access specifier @@ -203,8 +231,8 @@ vector<pair<FixedHash<4>, FunctionTypePointer>> const& ContractDefinition::getIn { for (ASTPointer<FunctionDefinition> const& f: contract->getDefinedFunctions()) { - string functionSignature = f->getCanonicalSignature(); - if (f->isPublic() && !f->isConstructor() && !f->getName().empty() && signaturesSeen.count(functionSignature) == 0) + string functionSignature = f->externalSignature(); + if (f->isPartOfExternalInterface() && signaturesSeen.count(functionSignature) == 0) { functionsSeen.insert(f->getName()); signaturesSeen.insert(functionSignature); @@ -214,11 +242,12 @@ vector<pair<FixedHash<4>, FunctionTypePointer>> const& ContractDefinition::getIn } for (ASTPointer<VariableDeclaration> const& v: contract->getStateVariables()) - if (v->isPublic() && functionsSeen.count(v->getName()) == 0) + if (functionsSeen.count(v->getName()) == 0 && v->isPartOfExternalInterface()) { FunctionType ftype(*v); + solAssert(v->getType().get(), ""); functionsSeen.insert(v->getName()); - FixedHash<4> hash(dev::sha3(ftype.getCanonicalSignature(v->getName()))); + FixedHash<4> hash(dev::sha3(ftype.externalSignature(v->getName()))); m_interfaceFunctionList->push_back(make_pair(hash, make_shared<FunctionType>(*v))); } } @@ -322,25 +351,35 @@ TypePointer FunctionDefinition::getType(ContractDefinition const*) const 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.")); + if (getVisibility() >= Visibility::Public && !(var->getType()->externalType())) + { + // todo delete when will be implemented arrays as parameter type in internal functions + if (getVisibility() == Visibility::Public && var->getType()->getCategory() == Type::Category::Array) + BOOST_THROW_EXCEPTION(var->createTypeError("Arrays only implemented for external functions.")); + else + BOOST_THROW_EXCEPTION(var->createTypeError("Internal type is not allowed for public and external functions.")); + } + } for (ASTPointer<ModifierInvocation> const& modifier: m_functionModifiers) modifier->checkTypeRequirements(isConstructor() ? dynamic_cast<ContractDefinition const&>(*getScope()).getBaseContracts() : vector<ASTPointer<InheritanceSpecifier>>()); - - m_body->checkTypeRequirements(); + if (m_body) + m_body->checkTypeRequirements(); } -string FunctionDefinition::getCanonicalSignature() const +string FunctionDefinition::externalSignature() const { - return FunctionType(*this).getCanonicalSignature(getName()); + return FunctionType(*this).externalSignature(getName()); } bool VariableDeclaration::isLValue() const { - // External function parameters are Read-Only - return !isExternalFunctionParameter(); + // External function parameters and constant declared variables are Read-Only + return !isExternalFunctionParameter() && !m_isConstant; } void VariableDeclaration::checkTypeRequirements() @@ -349,10 +388,24 @@ void VariableDeclaration::checkTypeRequirements() // sets the type. // Note that assignments before the first declaration are legal because of the special scoping // rules inherited from JavaScript. + if (m_isConstant) + { + if (!dynamic_cast<ContractDefinition const*>(getScope())) + BOOST_THROW_EXCEPTION(createTypeError("Illegal use of \"constant\" specifier.")); + if ((m_type && !m_type->isValueType()) || !m_value) + BOOST_THROW_EXCEPTION(createTypeError("Unitialized \"constant\" variable.")); + } if (!m_value) return; if (m_type) + { m_value->expectType(*m_type); + if (m_isStateVariable && !m_type->externalType() && getVisibility() >= Visibility::Public) + BOOST_THROW_EXCEPTION(createTypeError("Internal type is not allowed for state variables.")); + + if (!FunctionType(*this).externalType()) + BOOST_THROW_EXCEPTION(createTypeError("Internal type is not allowed for public state variables.")); + } else { // no type declared and no previous assignment, infer the type @@ -437,6 +490,8 @@ void EventDefinition::checkTypeRequirements() numIndexed++; if (!var->getType()->canLiveOutsideStorage()) BOOST_THROW_EXCEPTION(var->createTypeError("Type is required to live outside storage.")); + if (!var->getType()->externalType()) + BOOST_THROW_EXCEPTION(var->createTypeError("Internal type is not allowed as event parameter type.")); } if (numIndexed > 3) BOOST_THROW_EXCEPTION(createTypeError("More than 3 indexed arguments for event.")); @@ -681,6 +736,8 @@ void NewExpression::checkTypeRequirements() m_contract = dynamic_cast<ContractDefinition const*>(m_contractName->getReferencedDeclaration()); if (!m_contract) BOOST_THROW_EXCEPTION(createTypeError("Identifier is not a contract.")); + if (!m_contract->isFullyImplemented()) + BOOST_THROW_EXCEPTION(m_contract->createTypeError("Trying to create an instance of an abstract contract.")); shared_ptr<ContractType const> contractType = make_shared<ContractType>(*m_contract); TypePointers const& parameterTypes = contractType->getConstructorType()->getParameterTypes(); m_type = make_shared<FunctionType>(parameterTypes, TypePointers{contractType}, @@ -720,7 +777,7 @@ void IndexAccess::checkTypeRequirements() BOOST_THROW_EXCEPTION(createTypeError("Index expression cannot be omitted.")); m_index->expectType(IntegerType(256)); if (type.isByteArray()) - m_type = make_shared<IntegerType>(8, IntegerType::Modifier::Hash); + m_type = make_shared<FixedBytesType>(1); else m_type = type.getBaseType(); m_isLValue = type.getLocation() != ArrayType::Location::CallData; |