aboutsummaryrefslogtreecommitdiffstats
path: root/AST.cpp
diff options
context:
space:
mode:
authorchriseth <c@ethdev.com>2015-04-07 23:08:49 +0800
committerchriseth <c@ethdev.com>2015-04-07 23:08:49 +0800
commit158795e48f4285d713b11f78cdd04de8c6d1f667 (patch)
treea4194b4dfbac5bcbed9dbd6290e156c945fff56b /AST.cpp
parentff4d2cc7dc035a248de4698c2c59a8df14db2e82 (diff)
parent8e19eea7d5d6cd4bffa03f8617023a74268de608 (diff)
downloaddexon-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.cpp81
1 files changed, 69 insertions, 12 deletions
diff --git a/AST.cpp b/AST.cpp
index 09c03ef6..ada4a01d 100644
--- a/AST.cpp
+++ b/AST.cpp
@@ -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;