aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libsolidity/AST.cpp1049
-rw-r--r--libsolidity/AST.h305
-rw-r--r--libsolidity/ASTAnnotations.cpp28
-rw-r--r--libsolidity/ASTAnnotations.h123
-rw-r--r--libsolidity/ASTJsonConverter.cpp18
-rw-r--r--libsolidity/ASTJsonConverter.h3
-rw-r--r--libsolidity/ASTPrinter.cpp6
-rw-r--r--libsolidity/AST_accept.h6
-rw-r--r--libsolidity/Compiler.cpp37
-rw-r--r--libsolidity/Compiler.h7
-rw-r--r--libsolidity/CompilerContext.h1
-rw-r--r--libsolidity/CompilerStack.cpp39
-rw-r--r--libsolidity/CompilerStack.h27
-rw-r--r--libsolidity/CompilerUtils.cpp2
-rw-r--r--libsolidity/CompilerUtils.h2
-rw-r--r--libsolidity/ConstantEvaluator.cpp59
-rw-r--r--libsolidity/ConstantEvaluator.h50
-rw-r--r--libsolidity/Exceptions.h12
-rw-r--r--libsolidity/ExpressionCompiler.cpp147
-rw-r--r--libsolidity/ExpressionCompiler.h2
-rw-r--r--libsolidity/InterfaceHandler.cpp2
-rw-r--r--libsolidity/LValue.cpp8
-rw-r--r--libsolidity/LValue.h5
-rw-r--r--libsolidity/NameAndTypeResolver.cpp162
-rw-r--r--libsolidity/NameAndTypeResolver.h38
-rw-r--r--libsolidity/ReferencesResolver.cpp225
-rw-r--r--libsolidity/ReferencesResolver.h69
-rw-r--r--libsolidity/TypeChecker.cpp1143
-rw-r--r--libsolidity/TypeChecker.h114
-rw-r--r--libsolidity/Types.cpp73
-rw-r--r--solc/CommandLineInterface.cpp7
-rw-r--r--solc/jsonCompiler.cpp34
-rw-r--r--test/libsolidity/Assembly.cpp4
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp2
-rw-r--r--test/libsolidity/SolidityExpressionCompiler.cpp4
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp461
36 files changed, 2460 insertions, 1814 deletions
diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp
index daa84016..00b51c42 100644
--- a/libsolidity/AST.cpp
+++ b/libsolidity/AST.cpp
@@ -22,7 +22,6 @@
#include <algorithm>
#include <functional>
-#include <boost/range/adaptor/reversed.hpp>
#include <libsolidity/Utils.h>
#include <libsolidity/AST.h>
#include <libsolidity/ASTVisitor.h>
@@ -32,83 +31,29 @@
#include <libdevcore/SHA3.h>
using namespace std;
+using namespace dev;
+using namespace dev::solidity;
-namespace dev
-{
-namespace solidity
+ASTNode::ASTNode(SourceLocation const& _location):
+ m_location(_location)
{
+}
-TypeError ASTNode::createTypeError(string const& _description) const
+ASTNode::~ASTNode()
{
- return TypeError() << errinfo_sourceLocation(location()) << errinfo_comment(_description);
+ delete m_annotation;
}
-TypePointer ContractDefinition::type(ContractDefinition const* _currentContract) const
+ASTAnnotation& ASTNode::annotation() const
{
- return make_shared<TypeType>(make_shared<ContractType>(*this), _currentContract);
+ if (!m_annotation)
+ m_annotation = new ASTAnnotation();
+ return *m_annotation;
}
-void ContractDefinition::checkTypeRequirements()
+TypeError ASTNode::createTypeError(string const& _description) const
{
- for (ASTPointer<InheritanceSpecifier> const& baseSpecifier: baseContracts())
- baseSpecifier->checkTypeRequirements();
-
- checkDuplicateFunctions();
- checkIllegalOverrides();
- checkAbstractFunctions();
- checkAbstractConstructors();
-
- FunctionDefinition const* functionDefinition = constructor();
- if (functionDefinition && !functionDefinition->returnParameters().empty())
- BOOST_THROW_EXCEPTION(functionDefinition->returnParameterList()->createTypeError(
- "Non-empty \"returns\" directive for constructor."
- ));
-
- FunctionDefinition const* fallbackFunction = nullptr;
- for (ASTPointer<FunctionDefinition> const& function: definedFunctions())
- {
- if (function->name().empty())
- {
- if (fallbackFunction)
- BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_comment("Only one fallback function is allowed."));
- else
- {
- fallbackFunction = function.get();
- if (!fallbackFunction->parameters().empty())
- BOOST_THROW_EXCEPTION(fallbackFunction->parameterList().createTypeError("Fallback function cannot take parameters."));
- }
- }
- if (!function->isFullyImplemented())
- setFullyImplemented(false);
- }
-
- for (ASTPointer<VariableDeclaration> const& variable: m_stateVariables)
- variable->checkTypeRequirements();
-
- for (ASTPointer<EventDefinition> const& event: events())
- event->checkTypeRequirements();
-
- for (ASTPointer<ModifierDefinition> const& modifier: functionModifiers())
- modifier->checkTypeRequirements();
-
- for (ASTPointer<FunctionDefinition> const& function: definedFunctions())
- function->checkTypeRequirements();
-
- checkExternalTypeClashes();
- // check for hash collisions in function signatures
- set<FixedHash<4>> hashes;
- for (auto const& it: interfaceFunctionList())
- {
- FixedHash<4> const& hash = it.first;
- if (hashes.count(hash))
- BOOST_THROW_EXCEPTION(createTypeError(
- string("Function signature hash collision for ") + it.second->externalSignature()
- ));
- hashes.insert(hash);
- }
-
- if (isLibrary())
- checkLibraryRequirements();
+ return TypeError() << errinfo_sourceLocation(location()) << errinfo_comment(_description);
}
map<FixedHash<4>, FunctionTypePointer> ContractDefinition::interfaceFunctions() const
@@ -137,227 +82,20 @@ FunctionDefinition const* ContractDefinition::constructor() const
FunctionDefinition const* ContractDefinition::fallbackFunction() const
{
- for (ContractDefinition const* contract: linearizedBaseContracts())
+ for (ContractDefinition const* contract: annotation().linearizedBaseContracts)
for (ASTPointer<FunctionDefinition> const& f: contract->definedFunctions())
if (f->name().empty())
return f.get();
return nullptr;
}
-void ContractDefinition::checkDuplicateFunctions() const
-{
- /// Checks that two functions with the same name defined in this contract have different
- /// argument types and that there is at most one constructor.
- map<string, vector<FunctionDefinition const*>> functions;
- for (ASTPointer<FunctionDefinition> const& function: definedFunctions())
- functions[function->name()].push_back(function.get());
-
- if (functions[name()].size() > 1)
- {
- SecondarySourceLocation ssl;
- auto it = functions[name()].begin();
- ++it;
- for (; it != functions[name()].end(); ++it)
- ssl.append("Another declaration is here:", (*it)->location());
-
- BOOST_THROW_EXCEPTION(
- DeclarationError() <<
- errinfo_sourceLocation(functions[name()].front()->location()) <<
- errinfo_comment("More than one constructor defined.") <<
- errinfo_secondarySourceLocation(ssl)
- );
- }
- for (auto const& it: functions)
- {
- vector<FunctionDefinition const*> const& overloads = it.second;
- for (size_t i = 0; i < overloads.size(); ++i)
- for (size_t j = i + 1; j < overloads.size(); ++j)
- if (FunctionType(*overloads[i]).hasEqualArgumentTypes(FunctionType(*overloads[j])))
- BOOST_THROW_EXCEPTION(
- DeclarationError() <<
- errinfo_sourceLocation(overloads[j]->location()) <<
- errinfo_comment("Function with same name and arguments defined twice.") <<
- errinfo_secondarySourceLocation(SecondarySourceLocation().append(
- "Other declaration is here:", overloads[i]->location())
- )
-
- );
- }
-}
-
-void ContractDefinition::checkAbstractFunctions()
-{
- // Mapping from name to function definition (exactly one per argument type equality class) and
- // flag to indicate whether it is fully implemented.
- using FunTypeAndFlag = std::pair<FunctionTypePointer, bool>;
- map<string, vector<FunTypeAndFlag>> functions;
-
- // Search from base to derived
- for (ContractDefinition const* contract: boost::adaptors::reverse(linearizedBaseContracts()))
- for (ASTPointer<FunctionDefinition> const& function: contract->definedFunctions())
- {
- auto& overloads = functions[function->name()];
- FunctionTypePointer funType = make_shared<FunctionType>(*function);
- auto it = find_if(overloads.begin(), overloads.end(), [&](FunTypeAndFlag const& _funAndFlag)
- {
- return funType->hasEqualArgumentTypes(*_funAndFlag.first);
- });
- if (it == overloads.end())
- overloads.push_back(make_pair(funType, function->isFullyImplemented()));
- else if (it->second)
- {
- if (!function->isFullyImplemented())
- BOOST_THROW_EXCEPTION(function->createTypeError("Redeclaring an already implemented function as abstract"));
- }
- else if (function->isFullyImplemented())
- it->second = true;
- }
-
- // Set to not fully implemented if at least one flag is false.
- for (auto const& it: functions)
- for (auto const& funAndFlag: it.second)
- if (!funAndFlag.second)
- {
- setFullyImplemented(false);
- return;
- }
-}
-
-void ContractDefinition::checkAbstractConstructors()
-{
- set<ContractDefinition const*> argumentsNeeded;
- // check that we get arguments for all base constructors that need it.
- // If not mark the contract as abstract (not fully implemented)
-
- vector<ContractDefinition const*> const& bases = linearizedBaseContracts();
- for (ContractDefinition const* contract: bases)
- if (FunctionDefinition const* constructor = contract->constructor())
- if (contract != this && !constructor->parameters().empty())
- argumentsNeeded.insert(contract);
-
- for (ContractDefinition const* contract: bases)
- {
- if (FunctionDefinition const* constructor = contract->constructor())
- for (auto const& modifier: constructor->modifiers())
- {
- auto baseContract = dynamic_cast<ContractDefinition const*>(
- &modifier->name()->referencedDeclaration()
- );
- if (baseContract)
- argumentsNeeded.erase(baseContract);
- }
-
-
- for (ASTPointer<InheritanceSpecifier> const& base: contract->baseContracts())
- {
- auto baseContract = dynamic_cast<ContractDefinition const*>(
- &base->name()->referencedDeclaration()
- );
- solAssert(baseContract, "");
- if (!base->arguments().empty())
- argumentsNeeded.erase(baseContract);
- }
- }
- if (!argumentsNeeded.empty())
- setFullyImplemented(false);
-}
-
-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, vector<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: linearizedBaseContracts())
- {
- for (ASTPointer<FunctionDefinition> const& function: contract->definedFunctions())
- {
- if (function->isConstructor())
- continue; // constructors can neither be overridden nor override anything
- string const& name = function->name();
- if (modifiers.count(name))
- BOOST_THROW_EXCEPTION(modifiers[name]->createTypeError("Override changes function to modifier."));
- FunctionType functionType(*function);
- // function should not change the return type
- for (FunctionDefinition const* overriding: functions[name])
- {
- FunctionType overridingType(*overriding);
- if (!overridingType.hasEqualArgumentTypes(functionType))
- continue;
- if (
- overriding->visibility() != function->visibility() ||
- overriding->isDeclaredConst() != function->isDeclaredConst() ||
- overridingType != functionType
- )
- BOOST_THROW_EXCEPTION(overriding->createTypeError("Override changes extended function signature."));
- }
- functions[name].push_back(function.get());
- }
- for (ASTPointer<ModifierDefinition> const& modifier: contract->functionModifiers())
- {
- string const& name = modifier->name();
- 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 (!functions[name].empty())
- BOOST_THROW_EXCEPTION(override->createTypeError("Override changes modifier to function."));
- }
- }
-}
-
-void ContractDefinition::checkExternalTypeClashes() const
-{
- map<string, vector<pair<Declaration const*, shared_ptr<FunctionType>>>> externalDeclarations;
- for (ContractDefinition const* contract: linearizedBaseContracts())
- {
- for (ASTPointer<FunctionDefinition> const& f: contract->definedFunctions())
- if (f->isPartOfExternalInterface())
- {
- auto functionType = make_shared<FunctionType>(*f);
- externalDeclarations[functionType->externalSignature(f->name())].push_back(
- make_pair(f.get(), functionType)
- );
- }
- for (ASTPointer<VariableDeclaration> const& v: contract->stateVariables())
- if (v->isPartOfExternalInterface())
- {
- auto functionType = make_shared<FunctionType>(*v);
- externalDeclarations[functionType->externalSignature(v->name())].push_back(
- make_pair(v.get(), functionType)
- );
- }
- }
- for (auto const& it: externalDeclarations)
- for (size_t i = 0; i < it.second.size(); ++i)
- for (size_t j = i + 1; j < it.second.size(); ++j)
- if (!it.second[i].second->hasEqualArgumentTypes(*it.second[j].second))
- BOOST_THROW_EXCEPTION(it.second[j].first->createTypeError(
- "Function overload clash during conversion to external types for arguments."
- ));
-}
-
-void ContractDefinition::checkLibraryRequirements() const
-{
- solAssert(m_isLibrary, "");
- if (!m_baseContracts.empty())
- BOOST_THROW_EXCEPTION(createTypeError("Library is not allowed to inherit."));
-
- for (auto const& var: m_stateVariables)
- if (!var->isConstant())
- BOOST_THROW_EXCEPTION(var->createTypeError("Library cannot have non-constant state variables"));
-}
-
vector<ASTPointer<EventDefinition>> const& ContractDefinition::interfaceEvents() const
{
if (!m_interfaceEvents)
{
set<string> eventsSeen;
m_interfaceEvents.reset(new vector<ASTPointer<EventDefinition>>());
- for (ContractDefinition const* contract: linearizedBaseContracts())
+ for (ContractDefinition const* contract: annotation().linearizedBaseContracts)
for (ASTPointer<EventDefinition> const& e: contract->events())
if (eventsSeen.count(e->name()) == 0)
{
@@ -375,7 +113,7 @@ vector<pair<FixedHash<4>, FunctionTypePointer>> const& ContractDefinition::inter
set<string> functionsSeen;
set<string> signaturesSeen;
m_interfaceFunctionList.reset(new vector<pair<FixedHash<4>, FunctionTypePointer>>());
- for (ContractDefinition const* contract: linearizedBaseContracts())
+ for (ContractDefinition const* contract: annotation().linearizedBaseContracts)
{
for (ASTPointer<FunctionDefinition> const& f: contract->definedFunctions())
{
@@ -395,7 +133,7 @@ vector<pair<FixedHash<4>, FunctionTypePointer>> const& ContractDefinition::inter
if (functionsSeen.count(v->name()) == 0 && v->isPartOfExternalInterface())
{
FunctionType ftype(*v);
- solAssert(v->type().get(), "");
+ solAssert(!!v->annotation().type.get(), "");
functionsSeen.insert(v->name());
FixedHash<4> hash(dev::sha3(ftype.externalSignature(v->name())));
m_interfaceFunctionList->push_back(make_pair(hash, make_shared<FunctionType>(*v)));
@@ -453,84 +191,35 @@ vector<Declaration const*> const& ContractDefinition::inheritableMembers() const
return *m_inheritableMembers;
}
-TypePointer EnumValue::type(ContractDefinition const*) const
+TypePointer ContractDefinition::type(ContractDefinition const* m_currentContract) const
{
- EnumDefinition const* parentDef = dynamic_cast<EnumDefinition const*>(scope());
- solAssert(parentDef, "Enclosing Scope of EnumValue was not set");
- return make_shared<EnumType>(*parentDef);
+ return make_shared<TypeType>(make_shared<ContractType>(*this), m_currentContract);
}
-void InheritanceSpecifier::checkTypeRequirements()
+ContractDefinitionAnnotation& ContractDefinition::annotation() const
{
- m_baseName->checkTypeRequirements(nullptr);
- for (ASTPointer<Expression> const& argument: m_arguments)
- argument->checkTypeRequirements(nullptr);
-
- ContractDefinition const* base = dynamic_cast<ContractDefinition const*>(&m_baseName->referencedDeclaration());
- solAssert(base, "Base contract not available.");
-
- if (base->isLibrary())
- BOOST_THROW_EXCEPTION(createTypeError("Libraries cannot be inherited from."));
-
- TypePointers parameterTypes = ContractType(*base).constructorType()->parameterTypes();
- if (!m_arguments.empty() && parameterTypes.size() != m_arguments.size())
- BOOST_THROW_EXCEPTION(createTypeError(
- "Wrong argument count for constructor call: " +
- toString(m_arguments.size()) +
- " arguments given but expected " +
- toString(parameterTypes.size()) +
- "."
- ));
-
- for (size_t i = 0; i < m_arguments.size(); ++i)
- if (!m_arguments[i]->type()->isImplicitlyConvertibleTo(*parameterTypes[i]))
- BOOST_THROW_EXCEPTION(m_arguments[i]->createTypeError(
- "Invalid type for argument in constructor call. "
- "Invalid implicit conversion from " +
- m_arguments[i]->type()->toString() +
- " to " +
- parameterTypes[i]->toString() +
- " requested."
- ));
+ if (!m_annotation)
+ m_annotation = new ContractDefinitionAnnotation();
+ return static_cast<ContractDefinitionAnnotation&>(*m_annotation);
}
-TypePointer StructDefinition::type(ContractDefinition const*) const
+TypeNameAnnotation& TypeName::annotation() const
{
- return make_shared<TypeType>(make_shared<StructType>(*this));
+ if (!m_annotation)
+ m_annotation = new TypeNameAnnotation();
+ return static_cast<TypeNameAnnotation&>(*m_annotation);
}
-void StructDefinition::checkMemberTypes() const
+TypePointer StructDefinition::type(ContractDefinition const*) const
{
- for (ASTPointer<VariableDeclaration> const& member: members())
- if (!member->type()->canBeStored())
- BOOST_THROW_EXCEPTION(member->createTypeError("Type cannot be used in struct."));
+ return make_shared<TypeType>(make_shared<StructType>(*this));
}
-void StructDefinition::checkRecursion() const
+TypePointer EnumValue::type(ContractDefinition const*) const
{
- using StructPointer = StructDefinition const*;
- using StructPointersSet = set<StructPointer>;
- function<void(StructPointer,StructPointersSet const&)> check = [&](StructPointer _struct, StructPointersSet const& _parents)
- {
- if (_parents.count(_struct))
- BOOST_THROW_EXCEPTION(
- ParserError() <<
- errinfo_sourceLocation(_struct->location()) <<
- errinfo_comment("Recursive struct definition.")
- );
- set<StructDefinition const*> parents = _parents;
- parents.insert(_struct);
- for (ASTPointer<VariableDeclaration> const& member: _struct->members())
- if (member->type()->category() == Type::Category::Struct)
- {
- auto const& typeName = dynamic_cast<UserDefinedTypeName const&>(*member->typeName());
- check(
- &dynamic_cast<StructDefinition const&>(*typeName.referencedDeclaration()),
- parents
- );
- }
- };
- check(this, StructPointersSet{});
+ auto parentDef = dynamic_cast<EnumDefinition const*>(scope());
+ solAssert(parentDef, "Enclosing Scope of EnumValue was not set");
+ return make_shared<EnumType>(*parentDef);
}
TypePointer EnumDefinition::type(ContractDefinition const*) const
@@ -543,92 +232,32 @@ TypePointer FunctionDefinition::type(ContractDefinition const*) const
return make_shared<FunctionType>(*this);
}
-void FunctionDefinition::checkTypeRequirements()
+string FunctionDefinition::externalSignature() const
{
- for (ASTPointer<VariableDeclaration> const& var: parameters() + returnParameters())
- {
- if (!var->type()->canLiveOutsideStorage())
- BOOST_THROW_EXCEPTION(var->createTypeError("Type is required to live outside storage."));
- if (visibility() >= Visibility::Public && !(var->type()->externalType()))
- 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&>(*scope()).linearizedBaseContracts() :
- vector<ContractDefinition const*>());
- if (m_body)
- m_body->checkTypeRequirements();
+ return FunctionType(*this).externalSignature(name());
}
-string FunctionDefinition::externalSignature() const
+TypePointer ModifierDefinition::type(ContractDefinition const*) const
{
- return FunctionType(*this).externalSignature(name());
+ return make_shared<ModifierType>(*this);
}
-bool VariableDeclaration::isLValue() const
+TypePointer EventDefinition::type(ContractDefinition const*) const
{
- // External function parameters and constant declared variables are Read-Only
- return !isExternalCallableParameter() && !m_isConstant;
+ return make_shared<FunctionType>(*this);
}
-void VariableDeclaration::checkTypeRequirements()
+UserDefinedTypeNameAnnotation& UserDefinedTypeName::annotation() const
{
- // 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_isConstant)
- {
- if (!dynamic_cast<ContractDefinition const*>(scope()))
- BOOST_THROW_EXCEPTION(createTypeError("Illegal use of \"constant\" specifier."));
- if (!m_value)
- BOOST_THROW_EXCEPTION(createTypeError("Uninitialized \"constant\" variable."));
- if (m_type && !m_type->isValueType())
- {
- // TODO: const is implemented only for uint, bytesXX, string and enums types.
- bool constImplemented = false;
- if (auto arrayType = dynamic_cast<ArrayType const*>(m_type.get()))
- constImplemented = arrayType->isByteArray();
- if (!constImplemented)
- BOOST_THROW_EXCEPTION(createTypeError(
- "Illegal use of \"constant\" specifier. \"constant\" "
- "is not yet implemented for this type."
- ));
- }
- }
- if (m_type)
- {
- if (m_value)
- m_value->expectType(*m_type);
- }
- else
- {
- if (!m_value)
- // This feature might be extended in the future.
- BOOST_THROW_EXCEPTION(createTypeError("Assignment necessary for type detection."));
- m_value->checkTypeRequirements(nullptr);
+ if (!m_annotation)
+ m_annotation = new UserDefinedTypeNameAnnotation();
+ return static_cast<UserDefinedTypeNameAnnotation&>(*m_annotation);
+}
- TypePointer const& type = m_value->type();
- if (
- type->category() == Type::Category::IntegerConstant &&
- !dynamic_pointer_cast<IntegerConstantType const>(type)->integerType()
- )
- BOOST_THROW_EXCEPTION(m_value->createTypeError("Invalid integer constant " + type->toString() + "."));
- else if (type->category() == Type::Category::Void)
- BOOST_THROW_EXCEPTION(createTypeError("Variable cannot have void type."));
- m_type = type->mobileType();
- }
- solAssert(!!m_type, "");
- if (!m_isStateVariable)
- {
- if (m_type->dataStoredIn(DataLocation::Memory) || m_type->dataStoredIn(DataLocation::CallData))
- if (!m_type->canLiveOutsideStorage())
- BOOST_THROW_EXCEPTION(createTypeError(
- "Type " + m_type->toString() + " is only valid in storage."
- ));
- }
- else if (visibility() >= Visibility::Public && !FunctionType(*this).externalType())
- BOOST_THROW_EXCEPTION(createTypeError("Internal type is not allowed for public state variables."));
+bool VariableDeclaration::isLValue() const
+{
+ // External function parameters and constant declared variables are Read-Only
+ return !isExternalCallableParameter() && !m_isConstant;
}
bool VariableDeclaration::isCallableParameter() const
@@ -657,578 +286,62 @@ bool VariableDeclaration::isExternalCallableParameter() const
return false;
}
-TypePointer ModifierDefinition::type(ContractDefinition const*) const
-{
- return make_shared<ModifierType>(*this);
-}
-
-void ModifierDefinition::checkTypeRequirements()
-{
- m_body->checkTypeRequirements();
-}
-
-void ModifierInvocation::checkTypeRequirements(vector<ContractDefinition const*> const& _bases)
-{
- TypePointers argumentTypes;
- for (ASTPointer<Expression> const& argument: m_arguments)
- {
- argument->checkTypeRequirements(nullptr);
- argumentTypes.push_back(argument->type());
- }
- m_modifierName->checkTypeRequirements(&argumentTypes);
-
- auto const* declaration = &m_modifierName->referencedDeclaration();
- vector<ASTPointer<VariableDeclaration>> emptyParameterList;
- vector<ASTPointer<VariableDeclaration>> const* parameters = nullptr;
- if (auto modifier = dynamic_cast<ModifierDefinition const*>(declaration))
- parameters = &modifier->parameters();
- else
- // check parameters for Base constructors
- for (ContractDefinition const* base: _bases)
- if (declaration == base)
- {
- if (auto referencedConstructor = base->constructor())
- parameters = &referencedConstructor->parameters();
- else
- parameters = &emptyParameterList;
- break;
- }
- if (!parameters)
- BOOST_THROW_EXCEPTION(createTypeError("Referenced declaration is neither modifier nor base class."));
- if (parameters->size() != m_arguments.size())
- BOOST_THROW_EXCEPTION(createTypeError(
- "Wrong argument count for modifier invocation: " +
- toString(m_arguments.size()) +
- " arguments given but expected " +
- toString(parameters->size()) +
- "."
- ));
- for (size_t i = 0; i < m_arguments.size(); ++i)
- if (!m_arguments[i]->type()->isImplicitlyConvertibleTo(*(*parameters)[i]->type()))
- BOOST_THROW_EXCEPTION(m_arguments[i]->createTypeError(
- "Invalid type for argument in modifier invocation. "
- "Invalid implicit conversion from " +
- m_arguments[i]->type()->toString() +
- " to " +
- (*parameters)[i]->type()->toString() +
- " requested."
- ));
-}
-
-void EventDefinition::checkTypeRequirements()
-{
- int numIndexed = 0;
- for (ASTPointer<VariableDeclaration> const& var: parameters())
- {
- if (var->isIndexed())
- numIndexed++;
- if (numIndexed > 3)
- BOOST_THROW_EXCEPTION(createTypeError("More than 3 indexed arguments for event."));
- if (!var->type()->canLiveOutsideStorage())
- BOOST_THROW_EXCEPTION(var->createTypeError("Type is required to live outside storage."));
- if (!var->type()->externalType())
- BOOST_THROW_EXCEPTION(var->createTypeError("Internal type is not allowed as event parameter type."));
- }
-}
-
-void Block::checkTypeRequirements()
-{
- for (shared_ptr<Statement> const& statement: m_statements)
- statement->checkTypeRequirements();
-}
-
-void IfStatement::checkTypeRequirements()
-{
- m_condition->expectType(BoolType());
- m_trueBody->checkTypeRequirements();
- if (m_falseBody)
- m_falseBody->checkTypeRequirements();
-}
-
-void WhileStatement::checkTypeRequirements()
-{
- m_condition->expectType(BoolType());
- m_body->checkTypeRequirements();
-}
-
-void ForStatement::checkTypeRequirements()
-{
- if (m_initExpression)
- m_initExpression->checkTypeRequirements();
- if (m_condExpression)
- m_condExpression->expectType(BoolType());
- if (m_loopExpression)
- m_loopExpression->checkTypeRequirements();
- m_body->checkTypeRequirements();
-}
-
-void Return::checkTypeRequirements()
+bool VariableDeclaration::canHaveAutoType() const
{
- if (!m_expression)
- return;
- if (!m_returnParameters)
- BOOST_THROW_EXCEPTION(createTypeError("Return arguments not allowed."));
- if (m_returnParameters->parameters().size() != 1)
- BOOST_THROW_EXCEPTION(createTypeError(
- "Different number of arguments in return statement "
- "than in returns declaration."
- ));
- // this could later be changed such that the paramaters type is an anonymous struct type,
- // but for now, we only allow one return parameter
- m_expression->expectType(*m_returnParameters->parameters().front()->type());
-}
-
-void VariableDeclarationStatement::checkTypeRequirements()
-{
- m_variable->checkTypeRequirements();
-}
-
-void Assignment::checkTypeRequirements(TypePointers const*)
-{
- m_leftHandSide->checkTypeRequirements(nullptr);
- m_leftHandSide->requireLValue();
- if (m_leftHandSide->type()->category() == Type::Category::Mapping)
- BOOST_THROW_EXCEPTION(createTypeError("Mappings cannot be assigned to."));
- m_type = m_leftHandSide->type();
- if (m_assigmentOperator == Token::Assign)
- m_rightHandSide->expectType(*m_type);
- else
- {
- // compound assignment
- m_rightHandSide->checkTypeRequirements(nullptr);
- TypePointer resultType = m_type->binaryOperatorResult(Token::AssignmentToBinaryOp(m_assigmentOperator),
- m_rightHandSide->type());
- if (!resultType || *resultType != *m_type)
- BOOST_THROW_EXCEPTION(createTypeError(
- "Operator " +
- string(Token::toString(m_assigmentOperator)) +
- " not compatible with types " +
- m_type->toString() +
- " and " +
- m_rightHandSide->type()->toString()
- ));
- }
-}
-
-void ExpressionStatement::checkTypeRequirements()
-{
- m_expression->checkTypeRequirements(nullptr);
- if (m_expression->type()->category() == Type::Category::IntegerConstant)
- if (!dynamic_pointer_cast<IntegerConstantType const>(m_expression->type())->integerType())
- BOOST_THROW_EXCEPTION(m_expression->createTypeError("Invalid integer constant."));
-}
-
-void Expression::expectType(Type const& _expectedType)
-{
- checkTypeRequirements(nullptr);
- Type const& currentType = *type();
- if (!currentType.isImplicitlyConvertibleTo(_expectedType))
- BOOST_THROW_EXCEPTION(
- createTypeError(
- "Type " +
- currentType.toString() +
- " is not implicitly convertible to expected type " +
- _expectedType.toString() +
- "."
- )
- );
-}
-
-void Expression::requireLValue()
-{
- if (!isLValue())
- BOOST_THROW_EXCEPTION(createTypeError("Expression has to be an lvalue."));
- m_lvalueRequested = true;
-}
-
-void UnaryOperation::checkTypeRequirements(TypePointers const*)
-{
- // Inc, Dec, Add, Sub, Not, BitNot, Delete
- m_subExpression->checkTypeRequirements(nullptr);
- if (m_operator == Token::Value::Inc || m_operator == Token::Value::Dec || m_operator == Token::Value::Delete)
- m_subExpression->requireLValue();
- m_type = m_subExpression->type()->unaryOperatorResult(m_operator);
- if (!m_type)
- BOOST_THROW_EXCEPTION(createTypeError("Unary operator not compatible with type."));
-}
-
-void BinaryOperation::checkTypeRequirements(TypePointers const*)
-{
- m_left->checkTypeRequirements(nullptr);
- m_right->checkTypeRequirements(nullptr);
- m_commonType = m_left->type()->binaryOperatorResult(m_operator, m_right->type());
- if (!m_commonType)
- BOOST_THROW_EXCEPTION(createTypeError(
- "Operator " + string(Token::toString(m_operator)) +
- " not compatible with types " +
- m_left->type()->toString() +
- " and " +
- m_right->type()->toString()
- ));
- m_type = Token::isCompareOp(m_operator) ? make_shared<BoolType>() : m_commonType;
-}
-
-void FunctionCall::checkTypeRequirements(TypePointers const*)
-{
- bool isPositionalCall = m_names.empty();
-
- // we need to check arguments' type first as they will be forwarded to
- // m_expression->checkTypeRequirements
- TypePointers argumentTypes;
- for (ASTPointer<Expression> const& argument: m_arguments)
- {
- argument->checkTypeRequirements(nullptr);
- // only store them for positional calls
- if (isPositionalCall)
- argumentTypes.push_back(argument->type());
- }
-
- m_expression->checkTypeRequirements(isPositionalCall ? &argumentTypes : nullptr);
-
- TypePointer const& expressionType = m_expression->type();
- FunctionTypePointer functionType;
- if (isTypeConversion())
- {
- TypeType const& type = dynamic_cast<TypeType const&>(*expressionType);
- if (m_arguments.size() != 1)
- BOOST_THROW_EXCEPTION(createTypeError("Exactly one argument expected for explicit type conversion."));
- if (!isPositionalCall)
- BOOST_THROW_EXCEPTION(createTypeError("Type conversion cannot allow named arguments."));
- m_type = type.actualType();
- auto argType = m_arguments.front()->type();
- if (auto argRefType = dynamic_cast<ReferenceType const*>(argType.get()))
- // do not change the data location when converting
- // (data location cannot yet be specified for type conversions)
- m_type = ReferenceType::copyForLocationIfReference(argRefType->location(), m_type);
- if (!argType->isExplicitlyConvertibleTo(*m_type))
- BOOST_THROW_EXCEPTION(createTypeError("Explicit type conversion not allowed."));
-
- return;
- }
-
- /// For error message: Struct members that were removed during conversion to memory.
- set<string> membersRemovedForStructConstructor;
- if (isStructConstructorCall())
- {
- TypeType const& type = dynamic_cast<TypeType const&>(*expressionType);
- auto const& structType = dynamic_cast<StructType const&>(*type.actualType());
- functionType = structType.constructorType();
- membersRemovedForStructConstructor = structType.membersMissingInMemory();
- }
- else
- functionType = dynamic_pointer_cast<FunctionType const>(expressionType);
-
- if (!functionType)
- BOOST_THROW_EXCEPTION(createTypeError("Type is not callable."));
-
- //@todo would be nice to create a struct type from the arguments
- // and then ask if that is implicitly convertible to the struct represented by the
- // function parameters
- TypePointers const& parameterTypes = functionType->parameterTypes();
- if (!functionType->takesArbitraryParameters() && parameterTypes.size() != m_arguments.size())
- {
- string msg =
- "Wrong argument count for function call: " +
- toString(m_arguments.size()) +
- " arguments given but expected " +
- toString(parameterTypes.size()) +
- ".";
- // Extend error message in case we try to construct a struct with mapping member.
- if (isStructConstructorCall() && !membersRemovedForStructConstructor.empty())
- {
- msg += " Members that have to be skipped in memory:";
- for (auto const& member: membersRemovedForStructConstructor)
- msg += " " + member;
- }
- BOOST_THROW_EXCEPTION(createTypeError(msg));
- }
-
- if (isPositionalCall)
- {
- // call by positional arguments
- for (size_t i = 0; i < m_arguments.size(); ++i)
- if (
- !functionType->takesArbitraryParameters() &&
- !m_arguments[i]->type()->isImplicitlyConvertibleTo(*parameterTypes[i])
- )
- BOOST_THROW_EXCEPTION(m_arguments[i]->createTypeError(
- "Invalid type for argument in function call. "
- "Invalid implicit conversion from " +
- m_arguments[i]->type()->toString() +
- " to " +
- parameterTypes[i]->toString() +
- " requested."
- ));
- }
- else
- {
- // call by named arguments
- if (functionType->takesArbitraryParameters())
- BOOST_THROW_EXCEPTION(createTypeError(
- "Named arguments cannnot be used for functions that take arbitrary parameters."
- ));
- auto const& parameterNames = functionType->parameterNames();
- if (parameterNames.size() != m_names.size())
- BOOST_THROW_EXCEPTION(createTypeError("Some argument names are missing."));
-
- // check duplicate names
- for (size_t i = 0; i < m_names.size(); i++)
- for (size_t j = i + 1; j < m_names.size(); j++)
- if (*m_names[i] == *m_names[j])
- BOOST_THROW_EXCEPTION(m_arguments[i]->createTypeError("Duplicate named argument."));
-
- for (size_t i = 0; i < m_names.size(); i++) {
- bool found = false;
- for (size_t j = 0; j < parameterNames.size(); j++) {
- if (parameterNames[j] == *m_names[i]) {
- // check type convertible
- if (!m_arguments[i]->type()->isImplicitlyConvertibleTo(*parameterTypes[j]))
- BOOST_THROW_EXCEPTION(m_arguments[i]->createTypeError(
- "Invalid type for argument in function call. "
- "Invalid implicit conversion from " +
- m_arguments[i]->type()->toString() +
- " to " +
- parameterTypes[i]->toString() +
- " requested."
- ));
-
- found = true;
- break;
- }
- }
- if (!found)
- BOOST_THROW_EXCEPTION(createTypeError("Named argument does not match function declaration."));
- }
- }
-
- // @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 anonymous
- // structs and tuples
- if (functionType->returnParameterTypes().empty())
- m_type = make_shared<VoidType>();
- else
- m_type = functionType->returnParameterTypes().front();
-}
-
-bool FunctionCall::isTypeConversion() const
-{
- return m_expression->type()->category() == Type::Category::TypeType && !isStructConstructorCall();
-}
-
-bool FunctionCall::isStructConstructorCall() const
-{
- if (auto const* type = dynamic_cast<TypeType const*>(m_expression->type().get()))
- return type->actualType()->category() == Type::Category::Struct;
- else
- return false;
+ auto const* callable = dynamic_cast<CallableDeclaration const*>(scope());
+ return (!!callable && !isCallableParameter());
}
-void NewExpression::checkTypeRequirements(TypePointers const*)
+TypePointer VariableDeclaration::type(ContractDefinition const*) const
{
- m_contractName->checkTypeRequirements(nullptr);
- m_contract = dynamic_cast<ContractDefinition const*>(&m_contractName->referencedDeclaration());
-
- if (!m_contract)
- BOOST_THROW_EXCEPTION(createTypeError("Identifier is not a contract."));
- if (!m_contract->isFullyImplemented())
- BOOST_THROW_EXCEPTION(createTypeError("Trying to create an instance of an abstract contract."));
-
- auto scopeContract = m_contractName->contractScope();
- auto bases = m_contract->linearizedBaseContracts();
- if (find(bases.begin(), bases.end(), scopeContract) != bases.end())
- BOOST_THROW_EXCEPTION(createTypeError("Circular reference for contract creation: cannot create instance of derived or same contract."));
-
- shared_ptr<ContractType const> contractType = make_shared<ContractType>(*m_contract);
- TypePointers const& parameterTypes = contractType->constructorType()->parameterTypes();
- m_type = make_shared<FunctionType>(
- parameterTypes,
- TypePointers{contractType},
- strings(),
- strings(),
- FunctionType::Location::Creation
- );
+ return annotation().type;
}
-void MemberAccess::checkTypeRequirements(TypePointers const* _argumentTypes)
+VariableDeclarationAnnotation& VariableDeclaration::annotation() const
{
- m_expression->checkTypeRequirements(nullptr);
- Type const& type = *m_expression->type();
-
- MemberList::MemberMap possibleMembers = type.members().membersByName(*m_memberName);
- if (possibleMembers.size() > 1 && _argumentTypes)
- {
- // do override resolution
- for (auto it = possibleMembers.begin(); it != possibleMembers.end();)
- if (
- it->type->category() == Type::Category::Function &&
- !dynamic_cast<FunctionType const&>(*it->type).canTakeArguments(*_argumentTypes)
- )
- it = possibleMembers.erase(it);
- else
- ++it;
- }
- if (possibleMembers.size() == 0)
- {
- auto storageType = ReferenceType::copyForLocationIfReference(
- DataLocation::Storage,
- m_expression->type()
- );
- if (!storageType->members().membersByName(*m_memberName).empty())
- BOOST_THROW_EXCEPTION(createTypeError(
- "Member \"" +
- *m_memberName +
- "\" is not available in " +
- type.toString() +
- " outside of storage."
- ));
- BOOST_THROW_EXCEPTION(createTypeError(
- "Member \"" +
- *m_memberName +
- "\" not found or not visible after argument-dependent lookup in " +
- type.toString()
- ));
- }
- else if (possibleMembers.size() > 1)
- BOOST_THROW_EXCEPTION(createTypeError(
- "Member \"" +
- *m_memberName +
- "\" not unique after argument-dependent lookup in " +
- type.toString()
- ));
-
- m_referencedDeclaration = possibleMembers.front().declaration;
- m_type = possibleMembers.front().type;
- if (type.category() == Type::Category::Struct)
- m_isLValue = true;
- else if (type.category() == Type::Category::Array)
- {
- auto const& arrayType(dynamic_cast<ArrayType const&>(type));
- m_isLValue = (
- *m_memberName == "length" &&
- arrayType.location() == DataLocation::Storage &&
- arrayType.isDynamicallySized()
- );
- }
- else
- m_isLValue = false;
+ if (!m_annotation)
+ m_annotation = new VariableDeclarationAnnotation();
+ return static_cast<VariableDeclarationAnnotation&>(*m_annotation);
}
-void IndexAccess::checkTypeRequirements(TypePointers const*)
+ReturnAnnotation& Return::annotation() const
{
- m_base->checkTypeRequirements(nullptr);
- switch (m_base->type()->category())
- {
- case Type::Category::Array:
- {
- ArrayType const& type = dynamic_cast<ArrayType const&>(*m_base->type());
- if (!m_index)
- BOOST_THROW_EXCEPTION(createTypeError("Index expression cannot be omitted."));
- if (type.isString())
- BOOST_THROW_EXCEPTION(createTypeError("Index access for string is not possible."));
- m_index->expectType(IntegerType(256));
-
- m_type = type.baseType();
- if (auto integerType = dynamic_cast<IntegerConstantType const*>(m_index->type().get()))
- if (!type.isDynamicallySized() && type.length() <= integerType->literalValue(nullptr))
- BOOST_THROW_EXCEPTION(createTypeError("Out of bounds access."));
-
- m_isLValue = type.location() != DataLocation::CallData;
- break;
- }
- case Type::Category::Mapping:
- {
- MappingType const& type = dynamic_cast<MappingType const&>(*m_base->type());
- if (!m_index)
- BOOST_THROW_EXCEPTION(createTypeError("Index expression cannot be omitted."));
- m_index->expectType(*type.keyType());
- m_type = type.valueType();
- m_isLValue = true;
- break;
- }
- case Type::Category::TypeType:
- {
- TypeType const& type = dynamic_cast<TypeType const&>(*m_base->type());
- if (!m_index)
- m_type = make_shared<TypeType>(make_shared<ArrayType>(DataLocation::Memory, type.actualType()));
- else
- {
- m_index->checkTypeRequirements(nullptr);
- auto length = dynamic_cast<IntegerConstantType const*>(m_index->type().get());
- if (!length)
- BOOST_THROW_EXCEPTION(m_index->createTypeError("Integer constant expected."));
- m_type = make_shared<TypeType>(make_shared<ArrayType>(
- DataLocation::Memory,
- type.actualType(),
- length->literalValue(nullptr)
- ));
- }
- break;
- }
- default:
- BOOST_THROW_EXCEPTION(m_base->createTypeError(
- "Indexed expression has to be a type, mapping or array (is " +
- m_base->type()->toString() +
- ")"
- ));
- }
+ if (!m_annotation)
+ m_annotation = new ReturnAnnotation();
+ return static_cast<ReturnAnnotation&>(*m_annotation);
}
-void Identifier::checkTypeRequirements(TypePointers const* _argumentTypes)
+ExpressionAnnotation& Expression::annotation() const
{
- if (!m_referencedDeclaration)
- {
- if (!_argumentTypes)
- BOOST_THROW_EXCEPTION(createTypeError("Unable to determine overloaded type."));
- overloadResolution(*_argumentTypes);
- }
- solAssert(!!m_referencedDeclaration, "Referenced declaration is null after overload resolution.");
- m_isLValue = m_referencedDeclaration->isLValue();
- m_type = m_referencedDeclaration->type(m_contractScope);
- if (!m_type)
- BOOST_THROW_EXCEPTION(createTypeError("Declaration referenced before type could be determined."));
+ if (!m_annotation)
+ m_annotation = new ExpressionAnnotation();
+ return static_cast<ExpressionAnnotation&>(*m_annotation);
}
-Declaration const& Identifier::referencedDeclaration() const
+MemberAccessAnnotation& MemberAccess::annotation() const
{
- solAssert(!!m_referencedDeclaration, "Identifier not resolved.");
- return *m_referencedDeclaration;
+ if (!m_annotation)
+ m_annotation = new MemberAccessAnnotation();
+ return static_cast<MemberAccessAnnotation&>(*m_annotation);
}
-void Identifier::overloadResolution(TypePointers const& _argumentTypes)
+BinaryOperationAnnotation& BinaryOperation::annotation() const
{
- solAssert(!m_referencedDeclaration, "Referenced declaration should be null before overload resolution.");
- solAssert(!m_overloadedDeclarations.empty(), "No candidates for overload resolution found.");
-
- vector<Declaration const*> possibles;
- if (m_overloadedDeclarations.size() == 1)
- m_referencedDeclaration = *m_overloadedDeclarations.begin();
-
- for (Declaration const* declaration: m_overloadedDeclarations)
- {
- TypePointer const& function = declaration->type();
- auto const* functionType = dynamic_cast<FunctionType const*>(function.get());
- if (functionType && functionType->canTakeArguments(_argumentTypes))
- possibles.push_back(declaration);
- }
- if (possibles.size() == 1)
- m_referencedDeclaration = possibles.front();
- else if (possibles.empty())
- BOOST_THROW_EXCEPTION(createTypeError("No matching declaration found after argument-dependent lookup."));
- else
- BOOST_THROW_EXCEPTION(createTypeError("No unique declaration found after argument-dependent lookup."));
+ if (!m_annotation)
+ m_annotation = new BinaryOperationAnnotation();
+ return static_cast<BinaryOperationAnnotation&>(*m_annotation);
}
-void ElementaryTypeNameExpression::checkTypeRequirements(TypePointers const*)
+FunctionCallAnnotation& FunctionCall::annotation() const
{
- m_type = make_shared<TypeType>(Type::fromElementaryTypeName(m_typeToken));
+ if (!m_annotation)
+ m_annotation = new FunctionCallAnnotation();
+ return static_cast<FunctionCallAnnotation&>(*m_annotation);
}
-void Literal::checkTypeRequirements(TypePointers const*)
+IdentifierAnnotation& Identifier::annotation() const
{
- m_type = Type::forLiteral(*this);
- if (!m_type)
- BOOST_THROW_EXCEPTION(createTypeError("Invalid literal value."));
-}
-
-}
+ if (!m_annotation)
+ m_annotation = new IdentifierAnnotation();
+ return static_cast<IdentifierAnnotation&>(*m_annotation);
}
diff --git a/libsolidity/AST.h b/libsolidity/AST.h
index ba529a8a..134ca148 100644
--- a/libsolidity/AST.h
+++ b/libsolidity/AST.h
@@ -33,6 +33,7 @@
#include <libsolidity/Token.h>
#include <libsolidity/Types.h>
#include <libsolidity/Exceptions.h>
+#include <libsolidity/ASTAnnotations.h>
namespace dev
{
@@ -51,9 +52,8 @@ class ASTConstVisitor;
class ASTNode: private boost::noncopyable
{
public:
- explicit ASTNode(SourceLocation const& _location): m_location(_location) {}
-
- virtual ~ASTNode() {}
+ explicit ASTNode(SourceLocation const& _location);
+ virtual ~ASTNode();
virtual void accept(ASTVisitor& _visitor) = 0;
virtual void accept(ASTConstVisitor& _visitor) const = 0;
@@ -77,6 +77,9 @@ public:
/// the given description
TypeError createTypeError(std::string const& _description) const;
+ ///@todo make this const-safe by providing a different way to access the annotation
+ virtual ASTAnnotation& annotation() const;
+
///@{
///@name equality operators
/// Equality relies on the fact that nodes cannot be copied.
@@ -84,6 +87,10 @@ public:
bool operator!=(ASTNode const& _other) const { return !operator==(_other); }
///@}
+protected:
+ /// Annotation - is specialised in derived classes, is created upon request (because of polymorphism).
+ mutable ASTAnnotation* m_annotation = nullptr;
+
private:
SourceLocation m_location;
};
@@ -151,12 +158,14 @@ public:
Declaration const* scope() const { return m_scope; }
void setScope(Declaration const* _scope) { m_scope = _scope; }
+ virtual bool isLValue() const { return false; }
+ virtual bool isPartOfExternalInterface() const { return false; }
+
/// @returns the type of expressions referencing this declaration.
/// The current contract has to be given since this context can change the type, especially of
/// contract types.
+ /// This can only be called once types of variable declarations have already been resolved.
virtual TypePointer type(ContractDefinition const* m_currentContract = nullptr) const = 0;
- virtual bool isLValue() const { return false; }
- virtual bool isPartOfExternalInterface() const { return false; }
protected:
virtual Visibility defaultVisibility() const { return Visibility::Public; }
@@ -205,8 +214,7 @@ public:
explicit ImplementationOptional(bool _implemented): m_implemented(_implemented) {}
/// @return whether this node is fully implemented or not
- bool isFullyImplemented() const { return m_implemented; }
- void setFullyImplemented(bool _implemented) { m_implemented = _implemented; }
+ bool isImplemented() const { return m_implemented; }
protected:
bool m_implemented;
@@ -219,7 +227,7 @@ protected:
* document order. It first visits all struct declarations, then all variable declarations and
* finally all function declarations.
*/
-class ContractDefinition: public Declaration, public Documented, public ImplementationOptional
+class ContractDefinition: public Declaration, public Documented
{
public:
ContractDefinition(
@@ -237,7 +245,6 @@ public:
):
Declaration(_location, _name),
Documented(_documentation),
- ImplementationOptional(true),
m_baseContracts(_baseContracts),
m_definedStructs(_definedStructs),
m_definedEnums(_definedEnums),
@@ -261,24 +268,14 @@ public:
std::vector<ASTPointer<EventDefinition>> const& interfaceEvents() const;
bool isLibrary() const { return m_isLibrary; }
- virtual TypePointer type(ContractDefinition const* m_currentContract) const override;
-
- /// Checks that there are no illegal overrides, that the constructor does not have a "returns"
- /// and calls checkTypeRequirements on all its functions.
- void checkTypeRequirements();
-
/// @returns a map of canonical function signatures to FunctionDefinitions
/// as intended for use by the ABI.
std::map<FixedHash<4>, FunctionTypePointer> interfaceFunctions() const;
+ std::vector<std::pair<FixedHash<4>, FunctionTypePointer>> const& interfaceFunctionList() const;
/// @returns a list of the inheritable members of this contract
std::vector<Declaration const*> const& inheritableMembers() const;
- /// List of all (direct and indirect) base contracts in order from derived to base, including
- /// the contract itself. Available after name resolution
- std::vector<ContractDefinition const*> const& linearizedBaseContracts() const { return m_linearizedBaseContracts; }
- void setLinearizedBaseContracts(std::vector<ContractDefinition const*> const& _bases) { m_linearizedBaseContracts = _bases; }
-
/// Returns the constructor or nullptr if no constructor was specified.
FunctionDefinition const* constructor() const;
/// Returns the fallback function or nullptr if no fallback function was specified.
@@ -290,21 +287,11 @@ public:
std::string const& devDocumentation() const;
void setDevDocumentation(std::string const& _devDocumentation);
-private:
- /// Checks that two functions defined in this contract with the same name have different
- /// arguments and that there is at most one constructor.
- void checkDuplicateFunctions() const;
- void checkIllegalOverrides() const;
- void checkAbstractFunctions();
- void checkAbstractConstructors();
- /// Checks that different functions with external visibility end up having different
- /// external argument types (i.e. different signature).
- void checkExternalTypeClashes() const;
- /// Checks that all requirements for a library are fulfilled if this is a library.
- void checkLibraryRequirements() const;
+ virtual TypePointer type(ContractDefinition const* m_currentContract) const override;
- std::vector<std::pair<FixedHash<4>, FunctionTypePointer>> const& interfaceFunctionList() const;
+ virtual ContractDefinitionAnnotation& annotation() const override;
+private:
std::vector<ASTPointer<InheritanceSpecifier>> m_baseContracts;
std::vector<ASTPointer<StructDefinition>> m_definedStructs;
std::vector<ASTPointer<EnumDefinition>> m_definedEnums;
@@ -327,18 +314,19 @@ private:
class InheritanceSpecifier: public ASTNode
{
public:
- InheritanceSpecifier(SourceLocation const& _location, ASTPointer<Identifier> const& _baseName,
- std::vector<ASTPointer<Expression>> _arguments):
+ InheritanceSpecifier(
+ SourceLocation const& _location,
+ ASTPointer<Identifier> const& _baseName,
+ std::vector<ASTPointer<Expression>> _arguments
+ ):
ASTNode(_location), m_baseName(_baseName), m_arguments(_arguments) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
- ASTPointer<Identifier> const& name() const { return m_baseName; }
+ Identifier const& name() const { return *m_baseName; }
std::vector<ASTPointer<Expression>> const& arguments() const { return m_arguments; }
- void checkTypeRequirements();
-
private:
ASTPointer<Identifier> m_baseName;
std::vector<ASTPointer<Expression>> m_arguments;
@@ -359,32 +347,27 @@ public:
std::vector<ASTPointer<VariableDeclaration>> const& members() const { return m_members; }
- virtual TypePointer type(ContractDefinition const*) const override;
-
- /// Checks that the members do not include any recursive structs and have valid types
- /// (e.g. no functions).
- void checkValidityOfMembers() const;
+ virtual TypePointer type(ContractDefinition const* m_currentContract) const override;
private:
- void checkMemberTypes() const;
- void checkRecursion() const;
-
std::vector<ASTPointer<VariableDeclaration>> m_members;
};
class EnumDefinition: public Declaration
{
public:
- EnumDefinition(SourceLocation const& _location,
- ASTPointer<ASTString> const& _name,
- std::vector<ASTPointer<EnumValue>> const& _members):
+ EnumDefinition(
+ SourceLocation const& _location,
+ ASTPointer<ASTString> const& _name,
+ std::vector<ASTPointer<EnumValue>> const& _members
+ ):
Declaration(_location, _name), m_members(_members) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
std::vector<ASTPointer<EnumValue>> const& members() const { return m_members; }
- virtual TypePointer type(ContractDefinition const*) const override;
+ virtual TypePointer type(ContractDefinition const* m_currentContract) const override;
private:
std::vector<ASTPointer<EnumValue>> m_members;
@@ -395,14 +378,14 @@ private:
*/
class EnumValue: public Declaration
{
- public:
- EnumValue(SourceLocation const& _location,
- ASTPointer<ASTString> const& _name):
+public:
+ EnumValue(SourceLocation const& _location, ASTPointer<ASTString> const& _name):
Declaration(_location, _name) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
- virtual TypePointer type(ContractDefinition const* = nullptr) const override;
+
+ virtual TypePointer type(ContractDefinition const* m_currentContract) const override;
};
/**
@@ -491,17 +474,15 @@ public:
{
return Declaration::isVisibleInContract() && !isConstructor() && !name().empty();
}
- virtual TypePointer type(ContractDefinition const*) const override;
virtual bool isPartOfExternalInterface() const override { return isPublic() && !m_isConstructor && !name().empty(); }
- /// Checks that all parameters have allowed types and calls checkTypeRequirements on the body.
- void checkTypeRequirements();
-
/// @returns the external signature of the function
/// That consists of the name of the function followed by the types of the
/// arguments separated by commas all enclosed in parentheses without any spaces.
std::string externalSignature() const;
+ virtual TypePointer type(ContractDefinition const* m_currentContract) const override;
+
private:
bool m_isConstructor;
bool m_isDeclaredConst;
@@ -540,28 +521,29 @@ public:
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
- TypeName* typeName() { return m_typeName.get(); }
+ TypeName* typeName() const { return m_typeName.get(); }
ASTPointer<Expression> const& value() const { return m_value; }
- /// Returns the declared or inferred type. Can be an empty pointer if no type was explicitly
- /// declared and there is no assignment to the variable that fixes the type.
- TypePointer type(ContractDefinition const* = nullptr) const override { return m_type; }
- void setType(std::shared_ptr<Type const> const& _type) { m_type = _type; }
-
virtual bool isLValue() const override;
virtual bool isPartOfExternalInterface() const override { return isPublic(); }
- void checkTypeRequirements();
bool isLocalVariable() const { return !!dynamic_cast<FunctionDefinition const*>(scope()); }
/// @returns true if this variable is a parameter or return parameter of a function.
bool isCallableParameter() const;
/// @returns true if this variable is a parameter (not return parameter) of an external function.
bool isExternalCallableParameter() const;
+ /// @returns true if the type of the variable does not need to be specified, i.e. it is declared
+ /// in the body of a function or modifier.
+ bool canHaveAutoType() const;
bool isStateVariable() const { return m_isStateVariable; }
bool isIndexed() const { return m_isIndexed; }
bool isConstant() const { return m_isConstant; }
Location referenceLocation() const { return m_location; }
+ virtual TypePointer type(ContractDefinition const* m_currentContract) const override;
+
+ virtual VariableDeclarationAnnotation& annotation() const override;
+
protected:
Visibility defaultVisibility() const override { return Visibility::Internal; }
@@ -572,8 +554,6 @@ private:
bool m_isIndexed; ///< Whether this is an indexed variable (used by events).
bool m_isConstant; ///< Whether the variable is a compile-time constant.
Location m_location; ///< Location of the variable if it is of reference type.
-
- std::shared_ptr<Type const> m_type; ///< derived type, initially empty
};
/**
@@ -600,9 +580,7 @@ public:
Block const& body() const { return *m_body; }
- virtual TypePointer type(ContractDefinition const* = nullptr) const override;
-
- void checkTypeRequirements();
+ virtual TypePointer type(ContractDefinition const* m_currentContract) const override;
private:
ASTPointer<Block> m_body;
@@ -614,8 +592,11 @@ private:
class ModifierInvocation: public ASTNode
{
public:
- ModifierInvocation(SourceLocation const& _location, ASTPointer<Identifier> const& _name,
- std::vector<ASTPointer<Expression>> _arguments):
+ ModifierInvocation(
+ SourceLocation const& _location,
+ ASTPointer<Identifier> const& _name,
+ std::vector<ASTPointer<Expression>> _arguments
+ ):
ASTNode(_location), m_modifierName(_name), m_arguments(_arguments) {}
virtual void accept(ASTVisitor& _visitor) override;
@@ -624,9 +605,6 @@ public:
ASTPointer<Identifier> const& name() const { return m_modifierName; }
std::vector<ASTPointer<Expression>> const& arguments() const { return m_arguments; }
- /// @param _bases is the list of base contracts for base constructor calls. For modifiers an empty vector should be passed.
- void checkTypeRequirements(std::vector<ContractDefinition const*> const& _bases);
-
private:
ASTPointer<Identifier> m_modifierName;
std::vector<ASTPointer<Expression>> m_arguments;
@@ -656,12 +634,7 @@ public:
bool isAnonymous() const { return m_anonymous; }
- virtual TypePointer type(ContractDefinition const* = nullptr) const override
- {
- return std::make_shared<FunctionType>(*this);
- }
-
- void checkTypeRequirements();
+ virtual TypePointer type(ContractDefinition const* m_currentContract) const override;
private:
bool m_anonymous = false;
@@ -681,7 +654,7 @@ public:
virtual void accept(ASTConstVisitor&) const override { BOOST_THROW_EXCEPTION(InternalCompilerError()
<< errinfo_comment("MagicVariableDeclaration used inside real AST.")); }
- virtual TypePointer type(ContractDefinition const* = nullptr) const override { return m_type; }
+ virtual TypePointer type(ContractDefinition const*) const override { return m_type; }
private:
std::shared_ptr<Type const> m_type;
@@ -700,10 +673,7 @@ public:
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
- /// Retrieve the element of the type hierarchy this node refers to. Can return an empty shared
- /// pointer until the types have been resolved using the @ref NameAndTypeResolver.
- /// If it returns an empty shared pointer after that, this indicates that the type was not found.
- virtual std::shared_ptr<Type const> toType() = 0;
+ virtual TypeNameAnnotation& annotation() const override;
};
/**
@@ -720,7 +690,6 @@ public:
}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
- virtual std::shared_ptr<Type const> toType() override { return Type::fromElementaryTypeName(m_type); }
Token::Value typeName() const { return m_type; }
@@ -735,19 +704,16 @@ class UserDefinedTypeName: public TypeName
{
public:
UserDefinedTypeName(SourceLocation const& _location, ASTPointer<ASTString> const& _name):
- TypeName(_location), m_name(_name), m_referencedDeclaration(nullptr) {}
+ TypeName(_location), m_name(_name) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
- virtual std::shared_ptr<Type const> toType() override { return Type::fromUserDefinedTypeName(*this); }
ASTString const& name() const { return *m_name; }
- void setReferencedDeclaration(Declaration const& _referencedDeclaration) { m_referencedDeclaration = &_referencedDeclaration; }
- Declaration const* referencedDeclaration() const { return m_referencedDeclaration; }
+
+ virtual UserDefinedTypeNameAnnotation& annotation() const override;
private:
ASTPointer<ASTString> m_name;
-
- Declaration const* m_referencedDeclaration;
};
/**
@@ -761,7 +727,6 @@ public:
TypeName(_location), m_keyType(_keyType), m_valueType(_valueType) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
- virtual TypePointer toType() override { return Type::fromMapping(*m_keyType, *m_valueType); }
ElementaryTypeName const& keyType() const { return *m_keyType; }
TypeName const& valueType() const { return *m_valueType; }
@@ -782,7 +747,6 @@ public:
TypeName(_location), m_baseType(_baseType), m_length(_length) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
- virtual std::shared_ptr<Type const> toType() override { return Type::fromArrayTypeName(*m_baseType, m_length.get()); }
TypeName const& baseType() const { return *m_baseType; }
Expression const* length() const { return m_length.get(); }
@@ -805,11 +769,6 @@ class Statement: public ASTNode
{
public:
explicit Statement(SourceLocation const& _location): ASTNode(_location) {}
-
- /// Check all type requirements, throws exception if some requirement is not met.
- /// This includes checking that operators are applicable to their arguments but also that
- /// the number of function call arguments matches the number of formal parameters and so forth.
- virtual void checkTypeRequirements() = 0;
};
/**
@@ -823,8 +782,6 @@ public:
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
- virtual void checkTypeRequirements() override;
-
private:
std::vector<ASTPointer<Statement>> m_statements;
};
@@ -840,8 +797,6 @@ public:
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
-
- virtual void checkTypeRequirements() override { }
};
/**
@@ -857,7 +812,6 @@ public:
m_condition(_condition), m_trueBody(_trueBody), m_falseBody(_falseBody) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
- virtual void checkTypeRequirements() override;
Expression const& condition() const { return *m_condition; }
Statement const& trueStatement() const { return *m_trueBody; }
@@ -887,7 +841,6 @@ public:
BreakableStatement(_location), m_condition(_condition), m_body(_body) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
- virtual void checkTypeRequirements() override;
Expression const& condition() const { return *m_condition; }
Statement const& body() const { return *m_body; }
@@ -903,19 +856,21 @@ private:
class ForStatement: public BreakableStatement
{
public:
- ForStatement(SourceLocation const& _location,
- ASTPointer<Statement> const& _initExpression,
- ASTPointer<Expression> const& _conditionExpression,
- ASTPointer<ExpressionStatement> const& _loopExpression,
- ASTPointer<Statement> const& _body):
+ ForStatement(
+ SourceLocation const& _location,
+ ASTPointer<Statement> const& _initExpression,
+ ASTPointer<Expression> const& _conditionExpression,
+ ASTPointer<ExpressionStatement> const& _loopExpression,
+ ASTPointer<Statement> const& _body
+ ):
BreakableStatement(_location),
m_initExpression(_initExpression),
m_condExpression(_conditionExpression),
m_loopExpression(_loopExpression),
- m_body(_body) {}
+ m_body(_body)
+ {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
- virtual void checkTypeRequirements() override;
Statement const* initializationExpression() const { return m_initExpression.get(); }
Expression const* condition() const { return m_condExpression.get(); }
@@ -939,7 +894,6 @@ public:
Continue(SourceLocation const& _location): Statement(_location) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
- virtual void checkTypeRequirements() override {}
};
class Break: public Statement
@@ -948,27 +902,22 @@ public:
Break(SourceLocation const& _location): Statement(_location) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
- virtual void checkTypeRequirements() override {}
};
class Return: public Statement
{
public:
Return(SourceLocation const& _location, ASTPointer<Expression> _expression):
- Statement(_location), m_expression(_expression), m_returnParameters(nullptr) {}
+ Statement(_location), m_expression(_expression) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
- virtual void checkTypeRequirements() override;
- void setFunctionReturnParameters(ParameterList const* _parameters) { m_returnParameters = _parameters; }
- ParameterList const* functionReturnParameters() const { return m_returnParameters; }
Expression const* expression() const { return m_expression.get(); }
+ virtual ReturnAnnotation& annotation() const override;
+
private:
ASTPointer<Expression> m_expression; ///< value to return, optional
-
- /// Pointer to the parameter list of the function, filled by the @ref NameAndTypeResolver.
- ParameterList const* m_returnParameters;
};
/**
@@ -980,7 +929,6 @@ public:
Throw(SourceLocation const& _location): Statement(_location) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
- virtual void checkTypeRequirements() override {};
};
/**
@@ -995,7 +943,6 @@ public:
Statement(_location), m_variable(_variable) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
- virtual void checkTypeRequirements() override;
VariableDeclaration const& declaration() const { return *m_variable; }
Expression const* expression() const { return m_variable->value().get(); }
@@ -1014,7 +961,6 @@ public:
Statement(_location), m_expression(_expression) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
- virtual void checkTypeRequirements() override;
Expression const& expression() const { return *m_expression; }
@@ -1036,32 +982,8 @@ class Expression: public ASTNode
{
public:
Expression(SourceLocation const& _location): ASTNode(_location) {}
- /// Performs type checking after which m_type should be set.
- /// @arg _argumentTypes if set, provides the argument types for the case that this expression
- /// is used in the context of a call, used for function overload resolution.
- virtual void checkTypeRequirements(TypePointers const* _argumentTypes) = 0;
-
- std::shared_ptr<Type const> const& type() const { return m_type; }
- bool isLValue() const { return m_isLValue; }
-
- /// Helper function, infer the type via @ref checkTypeRequirements and then check that it
- /// is implicitly convertible to @a _expectedType. If not, throw exception.
- void expectType(Type const& _expectedType);
- /// Checks that this expression is an lvalue and also registers that an address and
- /// not a value is generated during compilation. Can be called after checkTypeRequirements()
- /// by an enclosing expression.
- void requireLValue();
- /// Returns true if @a requireLValue was previously called on this expression.
- bool lvalueRequested() const { return m_lvalueRequested; }
-protected:
- //! Inferred type of the expression, only filled after a call to checkTypeRequirements().
- std::shared_ptr<Type const> m_type;
- //! If this expression is an lvalue (i.e. something that can be assigned to).
- //! This is set during calls to @a checkTypeRequirements()
- bool m_isLValue = false;
- //! Whether the outer expression requested the address (true) or the value (false) of this expression.
- bool m_lvalueRequested = false;
+ ExpressionAnnotation& annotation() const override;
};
/// Assignment, can also be a compound assignment.
@@ -1069,16 +991,21 @@ protected:
class Assignment: public Expression
{
public:
- Assignment(SourceLocation const& _location, ASTPointer<Expression> const& _leftHandSide,
- Token::Value _assignmentOperator, ASTPointer<Expression> const& _rightHandSide):
- Expression(_location), m_leftHandSide(_leftHandSide),
- m_assigmentOperator(_assignmentOperator), m_rightHandSide(_rightHandSide)
+ Assignment(
+ SourceLocation const& _location,
+ ASTPointer<Expression> const& _leftHandSide,
+ Token::Value _assignmentOperator,
+ ASTPointer<Expression> const& _rightHandSide
+ ):
+ Expression(_location),
+ m_leftHandSide(_leftHandSide),
+ m_assigmentOperator(_assignmentOperator),
+ m_rightHandSide(_rightHandSide)
{
solAssert(Token::isAssignmentOp(_assignmentOperator), "");
}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
- virtual void checkTypeRequirements(TypePointers const* _argumentTypes) override;
Expression const& leftHandSide() const { return *m_leftHandSide; }
Token::Value assignmentOperator() const { return m_assigmentOperator; }
@@ -1106,7 +1033,6 @@ public:
}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
- virtual void checkTypeRequirements(TypePointers const* _argumentTypes) override;
Token::Value getOperator() const { return m_operator; }
bool isPrefixOperation() const { return m_isPrefix; }
@@ -1133,21 +1059,17 @@ public:
}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
- virtual void checkTypeRequirements(TypePointers const* _argumentTypes) override;
Expression const& leftExpression() const { return *m_left; }
Expression const& rightExpression() const { return *m_right; }
Token::Value getOperator() const { return m_operator; }
- Type const& commonType() const { return *m_commonType; }
+
+ BinaryOperationAnnotation& annotation() const override;
private:
ASTPointer<Expression> m_left;
Token::Value m_operator;
ASTPointer<Expression> m_right;
-
- /// The common type that is used for the operation, not necessarily the result type (e.g. for
- /// comparisons, this is always bool).
- std::shared_ptr<Type const> m_commonType;
};
/**
@@ -1161,17 +1083,12 @@ public:
Expression(_location), m_expression(_expression), m_arguments(_arguments), m_names(_names) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
- virtual void checkTypeRequirements(TypePointers const* _argumentTypes) override;
Expression const& expression() const { return *m_expression; }
std::vector<ASTPointer<Expression const>> arguments() const { return {m_arguments.begin(), m_arguments.end()}; }
std::vector<ASTPointer<ASTString>> const& names() const { return m_names; }
- /// @returns true if this is not an actual function call, but an explicit type conversion.
- /// Returns false for struct constructor calls.
- bool isTypeConversion() const;
- /// @return true if this is a constructor call for a struct, i.e. StructName(...).
- bool isStructConstructorCall() const;
+ virtual FunctionCallAnnotation& annotation() const override;
private:
ASTPointer<Expression> m_expression;
@@ -1189,15 +1106,11 @@ public:
Expression(_location), m_contractName(_contractName) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
- virtual void checkTypeRequirements(TypePointers const* _argumentTypes) override;
- /// Returns the referenced contract. Can only be called after type checking.
- ContractDefinition const* contract() const { solAssert(m_contract, ""); return m_contract; }
+ Identifier const& contractName() const { return *m_contractName; }
private:
ASTPointer<Identifier> m_contractName;
-
- ContractDefinition const* m_contract = nullptr;
};
/**
@@ -1213,18 +1126,12 @@ public:
virtual void accept(ASTConstVisitor& _visitor) const override;
Expression const& expression() const { return *m_expression; }
ASTString const& memberName() const { return *m_memberName; }
- /// @returns the declaration referenced by this expression. Might return nullptr even if the
- /// expression is valid, e.g. if the member does not correspond to an AST node.
- Declaration const* referencedDeclaration() const { return m_referencedDeclaration; }
- virtual void checkTypeRequirements(TypePointers const* _argumentTypes) override;
+
+ virtual MemberAccessAnnotation& annotation() const override;
private:
ASTPointer<Expression> m_expression;
ASTPointer<ASTString> m_memberName;
-
- /// Pointer to the referenced declaration, this is sometimes needed to resolve function over
- /// loads in the type-checking phase.
- Declaration const* m_referencedDeclaration = nullptr;
};
/**
@@ -1238,7 +1145,6 @@ public:
Expression(_location), m_base(_base), m_index(_index) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
- virtual void checkTypeRequirements(TypePointers const* _argumentTypes) override;
Expression const& baseExpression() const { return *m_base; }
Expression const* indexExpression() const { return m_index.get(); }
@@ -1268,44 +1174,13 @@ public:
PrimaryExpression(_location), m_name(_name) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
- virtual void checkTypeRequirements(TypePointers const* _argumentTypes) override;
ASTString const& name() const { return *m_name; }
- void setReferencedDeclaration(
- Declaration const& _referencedDeclaration,
- ContractDefinition const* _currentContract = nullptr
- )
- {
- m_referencedDeclaration = &_referencedDeclaration;
- m_contractScope = _currentContract;
- }
- Declaration const& referencedDeclaration() const;
-
- /// Stores a set of possible declarations referenced by this identifier. Has to be resolved
- /// providing argument types using overloadResolution before the referenced declaration
- /// is accessed.
- void setOverloadedDeclarations(std::vector<Declaration const*> const& _declarations)
- {
- m_overloadedDeclarations = _declarations;
- }
-
- /// Tries to find exactly one of the possible referenced declarations provided the given
- /// argument types in a call context.
- void overloadResolution(TypePointers const& _argumentTypes);
-
- ContractDefinition const* contractScope() const { return m_contractScope; }
+ virtual IdentifierAnnotation& annotation() const override;
private:
ASTPointer<ASTString> m_name;
-
- /// Declaration the name refers to.
- Declaration const* m_referencedDeclaration = nullptr;
- /// Stores a reference to the current contract. This is needed because types of base contracts
- /// change depending on the context.
- ContractDefinition const* m_contractScope = nullptr;
- /// A vector of overloaded declarations, right now only FunctionDefinition has overloaded declarations.
- std::vector<Declaration const*> m_overloadedDeclarations;
};
/**
@@ -1323,7 +1198,6 @@ public:
}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
- virtual void checkTypeRequirements(TypePointers const* _argumentTypes) override;
Token::Value typeToken() const { return m_typeToken; }
@@ -1357,7 +1231,6 @@ public:
PrimaryExpression(_location), m_token(_token), m_value(_value), m_subDenomination(_sub) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
- virtual void checkTypeRequirements(TypePointers const* _argumentTypes) override;
Token::Value token() const { return m_token; }
/// @returns the non-parsed value of the literal
diff --git a/libsolidity/ASTAnnotations.cpp b/libsolidity/ASTAnnotations.cpp
new file mode 100644
index 00000000..4253e16d
--- /dev/null
+++ b/libsolidity/ASTAnnotations.cpp
@@ -0,0 +1,28 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ cpp-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @author Christian <c@ethdev.com>
+ * @date 2015
+ * Object containing the type and other annotations for the AST nodes.
+ */
+
+#include <libsolidity/ASTAnnotations.h>
+
+using namespace std;
+using namespace dev;
+using namespace dev::solidity;
+
diff --git a/libsolidity/ASTAnnotations.h b/libsolidity/ASTAnnotations.h
new file mode 100644
index 00000000..195f11c8
--- /dev/null
+++ b/libsolidity/ASTAnnotations.h
@@ -0,0 +1,123 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ cpp-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @author Christian <c@ethdev.com>
+ * @date 2015
+ * Object containing the type and other annotations for the AST nodes.
+ */
+
+#pragma once
+
+#include <map>
+#include <memory>
+#include <vector>
+#include <libsolidity/ASTForward.h>
+
+namespace dev
+{
+namespace solidity
+{
+
+class Type;
+using TypePointer = std::shared_ptr<Type const>;
+
+struct ASTAnnotation
+{
+ virtual ~ASTAnnotation() {}
+};
+
+struct ContractDefinitionAnnotation: ASTAnnotation
+{
+ /// Whether all functions are implemented.
+ bool isFullyImplemented = true;
+ /// List of all (direct and indirect) base contracts in order from derived to
+ /// base, including the contract itself.
+ std::vector<ContractDefinition const*> linearizedBaseContracts;
+};
+
+struct VariableDeclarationAnnotation: ASTAnnotation
+{
+ /// Type of variable (type of identifier referencing this variable).
+ TypePointer type;
+};
+
+struct ReturnAnnotation: ASTAnnotation
+{
+ /// Reference to the return parameters of the function.
+ ParameterList const* functionReturnParameters = nullptr;
+};
+
+struct TypeNameAnnotation: ASTAnnotation
+{
+ /// Type declared by this type name, i.e. type of a variable where this type name is used.
+ /// Set during reference resolution stage.
+ TypePointer type;
+};
+
+struct UserDefinedTypeNameAnnotation: TypeNameAnnotation
+{
+ /// Referenced declaration, set during reference resolution stage.
+ Declaration const* referencedDeclaration = nullptr;
+};
+
+struct ExpressionAnnotation: ASTAnnotation
+{
+ /// Inferred type of the expression.
+ TypePointer type;
+ /// Whether it is an LValue (i.e. something that can be assigned to).
+ bool isLValue = false;
+ /// Whether the expression is used in a context where the LValue is actually required.
+ bool lValueRequested = false;
+ /// Types of arguments if the expression is a function that is called - used
+ /// for overload resolution.
+ std::shared_ptr<std::vector<TypePointer>> argumentTypes;
+};
+
+struct IdentifierAnnotation: ExpressionAnnotation
+{
+ /// Stores a reference to the current contract.
+ /// This is needed because types of base contracts change depending on the context.
+ ContractDefinition const* contractScope = nullptr;
+ /// Referenced declaration, set at latest during overload resolution stage.
+ Declaration const* referencedDeclaration = nullptr;
+ /// List of possible declarations it could refer to.
+ std::vector<Declaration const*> overloadedDeclarations;
+};
+
+struct MemberAccessAnnotation: ExpressionAnnotation
+{
+ /// Referenced declaration, set at latest during overload resolution stage.
+ Declaration const* referencedDeclaration = nullptr;
+};
+
+struct BinaryOperationAnnotation: ExpressionAnnotation
+{
+ /// The common type that is used for the operation, not necessarily the result type (which
+ /// e.g. for comparisons is bool).
+ TypePointer commonType;
+};
+
+struct FunctionCallAnnotation: ExpressionAnnotation
+{
+ /// Whether this is an explicit type conversion.
+ bool isTypeConversion = false;
+ /// Whether this is a struct constructor call.
+ bool isStructConstructorCall = false;
+};
+
+}
+}
diff --git a/libsolidity/ASTJsonConverter.cpp b/libsolidity/ASTJsonConverter.cpp
index 96e5cf2a..3edcb77e 100644
--- a/libsolidity/ASTJsonConverter.cpp
+++ b/libsolidity/ASTJsonConverter.cpp
@@ -232,19 +232,19 @@ bool ASTJsonConverter::visit(UnaryOperation const& _node)
bool ASTJsonConverter::visit(BinaryOperation const& _node)
{
- addJsonNode("BinaryOperation",
- { make_pair("operator", Token::toString(_node.getOperator())),
- make_pair("type", type(_node))},
- true);
+ addJsonNode("BinaryOperation", {
+ make_pair("operator", Token::toString(_node.getOperator())),
+ make_pair("type", type(_node))
+ }, true);
return true;
}
bool ASTJsonConverter::visit(FunctionCall const& _node)
{
- addJsonNode("FunctionCall",
- { make_pair("type_conversion", boost::lexical_cast<std::string>(_node.isTypeConversion())),
- make_pair("type", type(_node)) },
- true);
+ addJsonNode("FunctionCall", {
+ make_pair("type_conversion", boost::lexical_cast<std::string>(_node.annotation().isTypeConversion)),
+ make_pair("type", type(_node))
+ }, true);
return true;
}
@@ -441,7 +441,7 @@ void ASTJsonConverter::process()
string ASTJsonConverter::type(Expression const& _expression)
{
- return (_expression.type()) ? _expression.type()->toString() : "Unknown";
+ return _expression.annotation().type ? _expression.annotation().type->toString() : "Unknown";
}
}
diff --git a/libsolidity/ASTJsonConverter.h b/libsolidity/ASTJsonConverter.h
index 77230d92..a44df876 100644
--- a/libsolidity/ASTJsonConverter.h
+++ b/libsolidity/ASTJsonConverter.h
@@ -27,6 +27,7 @@
#include <libsolidity/ASTVisitor.h>
#include <libsolidity/Exceptions.h>
#include <libsolidity/Utils.h>
+#include <libsolidity/ASTAnnotations.h>
#include <json/json.h>
namespace dev
@@ -41,7 +42,7 @@ class ASTJsonConverter: public ASTConstVisitor
{
public:
/// Create a converter to JSON for the given abstract syntax tree.
- ASTJsonConverter(ASTNode const& _ast);
+ explicit ASTJsonConverter(ASTNode const& _ast);
/// Output the json representation of the AST to _stream.
void print(std::ostream& _stream);
Json::Value const& json();
diff --git a/libsolidity/ASTPrinter.cpp b/libsolidity/ASTPrinter.cpp
index 8ed45d87..5762051d 100644
--- a/libsolidity/ASTPrinter.cpp
+++ b/libsolidity/ASTPrinter.cpp
@@ -62,7 +62,7 @@ bool ASTPrinter::visit(ContractDefinition const& _node)
bool ASTPrinter::visit(InheritanceSpecifier const& _node)
{
- writeLine("InheritanceSpecifier \"" + _node.name()->name() + "\"");
+ writeLine("InheritanceSpecifier \"" + _node.name().name() + "\"");
printSourcePart(_node);
return goDeeper();
}
@@ -530,8 +530,8 @@ void ASTPrinter::printSourcePart(ASTNode const& _node)
void ASTPrinter::printType(Expression const& _expression)
{
- if (_expression.type())
- *m_ostream << indentation() << " Type: " << _expression.type()->toString() << "\n";
+ if (_expression.annotation().type)
+ *m_ostream << indentation() << " Type: " << _expression.annotation().type->toString() << "\n";
else
*m_ostream << indentation() << " Type unknown.\n";
}
diff --git a/libsolidity/AST_accept.h b/libsolidity/AST_accept.h
index 1388466c..dfa9c425 100644
--- a/libsolidity/AST_accept.h
+++ b/libsolidity/AST_accept.h
@@ -147,12 +147,6 @@ void StructDefinition::accept(ASTConstVisitor& _visitor) const
_visitor.endVisit(*this);
}
-void StructDefinition::checkValidityOfMembers() const
-{
- checkMemberTypes();
- checkRecursion();
-}
-
void ParameterList::accept(ASTVisitor& _visitor)
{
if (_visitor.visit(*this))
diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp
index d6582653..cb74072d 100644
--- a/libsolidity/Compiler.cpp
+++ b/libsolidity/Compiler.cpp
@@ -53,7 +53,7 @@ void Compiler::compileContract(
std::map<const ContractDefinition*, eth::Assembly const*> const& _contracts
)
{
- m_context = CompilerContext(); // clear it just in case
+ m_context = CompilerContext();
{
CompilerContext::LocationSetter locationSetterRunTime(m_context, _contract);
initializeContext(_contract, _contracts);
@@ -105,9 +105,9 @@ void Compiler::initializeContext(
map<ContractDefinition const*, eth::Assembly const*> const& _compiledContracts
)
{
- CompilerUtils(m_context).initialiseFreeMemoryPointer();
m_context.setCompiledContracts(_compiledContracts);
- m_context.setInheritanceHierarchy(_contract.linearizedBaseContracts());
+ m_context.setInheritanceHierarchy(_contract.annotation().linearizedBaseContracts);
+ CompilerUtils(m_context).initialiseFreeMemoryPointer();
registerStateVariables(_contract);
m_context.resetVisitedNodes(&_contract);
}
@@ -115,14 +115,14 @@ void Compiler::initializeContext(
void Compiler::appendInitAndConstructorCode(ContractDefinition const& _contract)
{
// Determine the arguments that are used for the base constructors.
- std::vector<ContractDefinition const*> const& bases = _contract.linearizedBaseContracts();
+ std::vector<ContractDefinition const*> const& bases = _contract.annotation().linearizedBaseContracts;
for (ContractDefinition const* contract: bases)
{
if (FunctionDefinition const* constructor = contract->constructor())
for (auto const& modifier: constructor->modifiers())
{
auto baseContract = dynamic_cast<ContractDefinition const*>(
- &modifier->name()->referencedDeclaration());
+ modifier->name()->annotation().referencedDeclaration);
if (baseContract)
if (m_baseArguments.count(baseContract->constructor()) == 0)
m_baseArguments[baseContract->constructor()] = &modifier->arguments();
@@ -131,7 +131,8 @@ void Compiler::appendInitAndConstructorCode(ContractDefinition const& _contract)
for (ASTPointer<InheritanceSpecifier> const& base: contract->baseContracts())
{
ContractDefinition const* baseContract = dynamic_cast<ContractDefinition const*>(
- &base->name()->referencedDeclaration());
+ base->name().annotation().referencedDeclaration
+ );
solAssert(baseContract, "");
if (m_baseArguments.count(baseContract->constructor()) == 0)
@@ -187,13 +188,13 @@ void Compiler::appendConstructor(FunctionDefinition const& _constructor)
{
unsigned argumentSize = 0;
for (ASTPointer<VariableDeclaration> const& var: _constructor.parameters())
- if (var->type()->isDynamicallySized())
+ if (var->annotation().type->isDynamicallySized())
{
argumentSize = 0;
break;
}
else
- argumentSize += var->type()->calldataEncodedSize();
+ argumentSize += var->annotation().type->calldataEncodedSize();
CompilerUtils(m_context).fetchFreeMemoryPointer();
if (argumentSize == 0)
@@ -418,7 +419,7 @@ bool Compiler::visit(FunctionDefinition const& _function)
for (ASTPointer<VariableDeclaration const> const& variable: _function.parameters())
{
m_context.addVariable(*variable, parametersSize);
- parametersSize -= variable->type()->sizeOnStack();
+ parametersSize -= variable->annotation().type->sizeOnStack();
}
for (ASTPointer<VariableDeclaration const> const& variable: _function.returnParameters())
@@ -594,9 +595,9 @@ bool Compiler::visit(Return const& _return)
//@todo modifications are needed to make this work with functions returning multiple values
if (Expression const* expression = _return.expression())
{
- solAssert(_return.functionReturnParameters(), "Invalid return parameters pointer.");
- VariableDeclaration const& firstVariable = *_return.functionReturnParameters()->parameters().front();
- compileExpression(*expression, firstVariable.type());
+ solAssert(_return.annotation().functionReturnParameters, "Invalid return parameters pointer.");
+ VariableDeclaration const& firstVariable = *_return.annotation().functionReturnParameters->parameters().front();
+ compileExpression(*expression, firstVariable.annotation().type);
CompilerUtils(m_context).moveToStackVariable(firstVariable);
}
for (unsigned i = 0; i < m_stackCleanupForReturn; ++i)
@@ -619,7 +620,7 @@ bool Compiler::visit(VariableDeclarationStatement const& _variableDeclarationSta
CompilerContext::LocationSetter locationSetter(m_context, _variableDeclarationStatement);
if (Expression const* expression = _variableDeclarationStatement.expression())
{
- compileExpression(*expression, _variableDeclarationStatement.declaration().type());
+ compileExpression(*expression, _variableDeclarationStatement.declaration().annotation().type);
CompilerUtils(m_context).moveToStackVariable(_variableDeclarationStatement.declaration());
}
checker.check();
@@ -632,7 +633,7 @@ bool Compiler::visit(ExpressionStatement const& _expressionStatement)
CompilerContext::LocationSetter locationSetter(m_context, _expressionStatement);
Expression const& expression = _expressionStatement.expression();
compileExpression(expression);
- CompilerUtils(m_context).popStackElement(*expression.type());
+ CompilerUtils(m_context).popStackElement(*expression.annotation().type);
checker.check();
return false;
}
@@ -672,7 +673,7 @@ void Compiler::appendModifierOrFunctionCode()
ASTPointer<ModifierInvocation> const& modifierInvocation = m_currentFunction->modifiers()[m_modifierDepth];
// constructor call should be excluded
- if (dynamic_cast<ContractDefinition const*>(&modifierInvocation->name()->referencedDeclaration()))
+ if (dynamic_cast<ContractDefinition const*>(modifierInvocation->name()->annotation().referencedDeclaration))
{
++m_modifierDepth;
appendModifierOrFunctionCode();
@@ -688,7 +689,7 @@ void Compiler::appendModifierOrFunctionCode()
m_context.addVariable(*modifier.parameters()[i]);
compileExpression(
*modifierInvocation->arguments()[i],
- modifier.parameters()[i]->type()
+ modifier.parameters()[i]->annotation().type
);
}
for (VariableDeclaration const* localVariable: modifier.localVariables())
@@ -710,7 +711,7 @@ void Compiler::appendStackVariableInitialisation(VariableDeclaration const& _var
{
CompilerContext::LocationSetter location(m_context, _variable);
m_context.addVariable(_variable);
- CompilerUtils(m_context).pushZeroValue(*_variable.type());
+ CompilerUtils(m_context).pushZeroValue(*_variable.annotation().type);
}
void Compiler::compileExpression(Expression const& _expression, TypePointer const& _targetType)
@@ -718,7 +719,7 @@ void Compiler::compileExpression(Expression const& _expression, TypePointer cons
ExpressionCompiler expressionCompiler(m_context, m_optimize);
expressionCompiler.compile(_expression);
if (_targetType)
- CompilerUtils(m_context).convertType(*_expression.type(), *_targetType);
+ CompilerUtils(m_context).convertType(*_expression.annotation().type, *_targetType);
}
eth::Assembly Compiler::cloneRuntime()
diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h
index c7dd7d90..7b7cffcf 100644
--- a/libsolidity/Compiler.h
+++ b/libsolidity/Compiler.h
@@ -37,10 +37,8 @@ public:
explicit Compiler(bool _optimize = false, unsigned _runs = 200):
m_optimize(_optimize),
m_optimizeRuns(_runs),
- m_context(),
m_returnTag(m_context.newTag())
- {
- }
+ { }
void compileContract(
ContractDefinition const& _contract,
@@ -71,7 +69,8 @@ public:
eth::AssemblyItem functionEntryLabel(FunctionDefinition const& _function) const;
private:
- /// Registers the non-function objects inside the contract with the context.
+ /// Registers the non-function objects inside the contract with the context and stores the basic
+ /// information about the contract like the AST annotations.
void initializeContext(
ContractDefinition const& _contract,
std::map<ContractDefinition const*, eth::Assembly const*> const& _compiledContracts
diff --git a/libsolidity/CompilerContext.h b/libsolidity/CompilerContext.h
index 39f4e75f..46ebfcf8 100644
--- a/libsolidity/CompilerContext.h
+++ b/libsolidity/CompilerContext.h
@@ -29,6 +29,7 @@
#include <libevmasm/Assembly.h>
#include <libsolidity/ASTForward.h>
#include <libsolidity/Types.h>
+#include <libsolidity/ASTAnnotations.h>
#include <libdevcore/Common.h>
namespace dev {
diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp
index 70bb1b4c..e6b87264 100644
--- a/libsolidity/CompilerStack.cpp
+++ b/libsolidity/CompilerStack.cpp
@@ -27,6 +27,7 @@
#include <libsolidity/Parser.h>
#include <libsolidity/GlobalContext.h>
#include <libsolidity/NameAndTypeResolver.h>
+#include <libsolidity/TypeChecker.h>
#include <libsolidity/Compiler.h>
#include <libsolidity/CompilerStack.h>
#include <libsolidity/InterfaceHandler.h>
@@ -76,6 +77,7 @@ void CompilerStack::reset(bool _keepSources, bool _addStandardSources)
m_globalContext.reset();
m_sourceOrder.clear();
m_contracts.clear();
+ m_errors.clear();
}
bool CompilerStack::addSource(string const& _name, string const& _content, bool _isLibrary)
@@ -93,8 +95,10 @@ void CompilerStack::setSource(string const& _sourceCode)
addSource("", _sourceCode);
}
-void CompilerStack::parse()
+bool CompilerStack::parse()
{
+ m_errors.clear();
+
for (auto& sourcePair: m_sources)
{
sourcePair.second.scanner->reset();
@@ -116,6 +120,7 @@ void CompilerStack::parse()
resolver.resolveNamesAndTypes(*contract);
m_contracts[contract->name()].contract = contract;
}
+
InterfaceHandler interfaceHandler;
for (Source const* source: m_sourceOrder)
for (ASTPointer<ASTNode> const& node: source->ast->nodes())
@@ -123,18 +128,22 @@ void CompilerStack::parse()
{
m_globalContext->setCurrentContract(*contract);
resolver.updateDeclaration(*m_globalContext->currentThis());
- resolver.checkTypeRequirements(*contract);
+ TypeChecker typeChecker;
+ bool typesFine = typeChecker.checkTypeRequirements(*contract);
+ if (!typesFine)
+ m_errors += typeChecker.errors();
contract->setDevDocumentation(interfaceHandler.devDocumentation(*contract));
contract->setUserDocumentation(interfaceHandler.userDocumentation(*contract));
m_contracts[contract->name()].contract = contract;
}
- m_parseSuccessful = true;
+ m_parseSuccessful = m_errors.empty();
+ return m_parseSuccessful;
}
-void CompilerStack::parse(string const& _sourceCode)
+bool CompilerStack::parse(string const& _sourceCode)
{
setSource(_sourceCode);
- parse();
+ return parse();
}
vector<string> CompilerStack::contractNames() const
@@ -148,17 +157,18 @@ vector<string> CompilerStack::contractNames() const
}
-void CompilerStack::compile(bool _optimize, unsigned _runs)
+bool CompilerStack::compile(bool _optimize, unsigned _runs)
{
if (!m_parseSuccessful)
- parse();
+ if (!parse())
+ return false;
map<ContractDefinition const*, eth::Assembly const*> compiledContracts;
for (Source const* source: m_sourceOrder)
for (ASTPointer<ASTNode> const& node: source->ast->nodes())
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
{
- if (!contract->isFullyImplemented())
+ if (!contract->annotation().isFullyImplemented)
continue;
shared_ptr<Compiler> compiler = make_shared<Compiler>(_optimize, _runs);
compiler->compileContract(*contract, compiledContracts);
@@ -172,13 +182,12 @@ void CompilerStack::compile(bool _optimize, unsigned _runs)
cloneCompiler.compileClone(*contract, compiledContracts);
compiledContract.cloneObject = cloneCompiler.assembledObject();
}
+ return true;
}
-eth::LinkerObject const& CompilerStack::compile(string const& _sourceCode, bool _optimize)
+bool CompilerStack::compile(string const& _sourceCode, bool _optimize)
{
- parse(_sourceCode);
- compile(_optimize);
- return object();
+ return parse(_sourceCode) && compile(_optimize);
}
void CompilerStack::link(const std::map<string, h160>& _libraries)
@@ -317,12 +326,6 @@ size_t CompilerStack::functionEntryPoint(
return 0;
}
-eth::LinkerObject CompilerStack::staticCompile(std::string const& _sourceCode, bool _optimize)
-{
- CompilerStack stack;
- return stack.compile(_sourceCode, _optimize);
-}
-
tuple<int, int, int, int> CompilerStack::positionFromSourceLocation(SourceLocation const& _sourceLocation) const
{
int startLine;
diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h
index 99e8af1a..e541ea47 100644
--- a/libsolidity/CompilerStack.h
+++ b/libsolidity/CompilerStack.h
@@ -54,6 +54,7 @@ class SourceUnit;
class Compiler;
class GlobalContext;
class InterfaceHandler;
+struct Error;
enum class DocumentationType: uint8_t
{
@@ -79,22 +80,28 @@ public:
/// Adds a source object (e.g. file) to the parser. After this, parse has to be called again.
/// @returns true if a source object by the name already existed and was replaced.
- void addSources(StringMap const& _nameContents, bool _isLibrary = false) { for (auto const& i: _nameContents) addSource(i.first, i.second, _isLibrary); }
+ void addSources(StringMap const& _nameContents, bool _isLibrary = false)
+ {
+ for (auto const& i: _nameContents) addSource(i.first, i.second, _isLibrary);
+ }
bool addSource(std::string const& _name, std::string const& _content, bool _isLibrary = false);
void setSource(std::string const& _sourceCode);
/// Parses all source units that were added
- void parse();
+ /// @returns false on error.
+ bool parse();
/// Sets the given source code as the only source unit apart from standard sources and parses it.
- void parse(std::string const& _sourceCode);
+ /// @returns false on error.
+ bool parse(std::string const& _sourceCode);
/// Returns a list of the contract names in the sources.
std::vector<std::string> contractNames() const;
std::string defaultContractName() const;
/// Compiles the source units that were previously added and parsed.
- void compile(bool _optimize = false, unsigned _runs = 200);
+ /// @returns false on error.
+ bool compile(bool _optimize = false, unsigned _runs = 200);
/// Parses and compiles the given source code.
- /// @returns the compiled linker object
- eth::LinkerObject const& compile(std::string const& _sourceCode, bool _optimize = false);
+ /// @returns false on error.
+ bool compile(std::string const& _sourceCode, bool _optimize = false);
/// Inserts the given addresses into the linker objects of all compiled contracts.
void link(std::map<std::string, h160> const& _libraries);
@@ -150,15 +157,14 @@ public:
FunctionDefinition const& _function
) const;
- /// Compile the given @a _sourceCode to bytecode. If a scanner is provided, it is used for
- /// scanning the source code - this is useful for printing exception information.
- static eth::LinkerObject staticCompile(std::string const& _sourceCode, bool _optimize = false);
-
/// Helper function for logs printing. Do only use in error cases, it's quite expensive.
/// line and columns are numbered starting from 1 with following order:
/// start line, start column, end line, end column
std::tuple<int, int, int, int> positionFromSourceLocation(SourceLocation const& _sourceLocation) const;
+ /// @returns the list of errors that occured during parsing and type checking.
+ std::vector<std::shared_ptr<Error const>> const& errors() const { return m_errors; }
+
private:
/**
* Information pertaining to one source unit, filled gradually during parsing and compilation.
@@ -198,6 +204,7 @@ private:
std::shared_ptr<GlobalContext> m_globalContext;
std::vector<Source const*> m_sourceOrder;
std::map<std::string const, Contract> m_contracts;
+ std::vector<std::shared_ptr<Error const>> m_errors;
};
}
diff --git a/libsolidity/CompilerUtils.cpp b/libsolidity/CompilerUtils.cpp
index e370c6be..b9b554e8 100644
--- a/libsolidity/CompilerUtils.cpp
+++ b/libsolidity/CompilerUtils.cpp
@@ -600,7 +600,7 @@ void CompilerUtils::pushZeroValue(const Type& _type)
void CompilerUtils::moveToStackVariable(VariableDeclaration const& _variable)
{
unsigned const stackPosition = m_context.baseToCurrentStackOffset(m_context.baseStackOffsetOfVariable(_variable));
- unsigned const size = _variable.type()->sizeOnStack();
+ unsigned const size = _variable.annotation().type->sizeOnStack();
solAssert(stackPosition >= size, "Variable size and position mismatch.");
// move variable starting from its top end in the stack
if (stackPosition - size + 1 > 16)
diff --git a/libsolidity/CompilerUtils.h b/libsolidity/CompilerUtils.h
index 0875ddd2..568a6307 100644
--- a/libsolidity/CompilerUtils.h
+++ b/libsolidity/CompilerUtils.h
@@ -170,7 +170,7 @@ unsigned CompilerUtils::sizeOnStack(std::vector<T> const& _variables)
{
unsigned size = 0;
for (T const& variable: _variables)
- size += variable->type()->sizeOnStack();
+ size += variable->annotation().type->sizeOnStack();
return size;
}
diff --git a/libsolidity/ConstantEvaluator.cpp b/libsolidity/ConstantEvaluator.cpp
new file mode 100644
index 00000000..5936b3d4
--- /dev/null
+++ b/libsolidity/ConstantEvaluator.cpp
@@ -0,0 +1,59 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ cpp-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @author Christian <c@ethdev.com>
+ * @date 2015
+ * Evaluator for types of constant expressions.
+ */
+
+#include <libsolidity/ConstantEvaluator.h>
+#include <libsolidity/AST.h>
+
+using namespace std;
+using namespace dev;
+using namespace dev::solidity;
+
+
+void ConstantEvaluator::endVisit(UnaryOperation const& _operation)
+{
+ TypePointer const& subType = _operation.subExpression().annotation().type;
+ if (!dynamic_cast<IntegerConstantType const*>(subType.get()))
+ BOOST_THROW_EXCEPTION(_operation.subExpression().createTypeError("Invalid constant expression."));
+ TypePointer t = subType->unaryOperatorResult(_operation.getOperator());
+ _operation.annotation().type = t;
+}
+
+void ConstantEvaluator::endVisit(BinaryOperation const& _operation)
+{
+ TypePointer const& leftType = _operation.leftExpression().annotation().type;
+ TypePointer const& rightType = _operation.rightExpression().annotation().type;
+ if (!dynamic_cast<IntegerConstantType const*>(leftType.get()))
+ BOOST_THROW_EXCEPTION(_operation.leftExpression().createTypeError("Invalid constant expression."));
+ if (!dynamic_cast<IntegerConstantType const*>(rightType.get()))
+ BOOST_THROW_EXCEPTION(_operation.rightExpression().createTypeError("Invalid constant expression."));
+ TypePointer commonType = leftType->binaryOperatorResult(_operation.getOperator(), rightType);
+ if (Token::isCompareOp(_operation.getOperator()))
+ commonType = make_shared<BoolType>();
+ _operation.annotation().type = commonType;
+}
+
+void ConstantEvaluator::endVisit(Literal const& _literal)
+{
+ _literal.annotation().type = Type::forLiteral(_literal);
+ if (!_literal.annotation().type)
+ BOOST_THROW_EXCEPTION(_literal.createTypeError("Invalid literal value."));
+}
diff --git a/libsolidity/ConstantEvaluator.h b/libsolidity/ConstantEvaluator.h
new file mode 100644
index 00000000..cf3d2094
--- /dev/null
+++ b/libsolidity/ConstantEvaluator.h
@@ -0,0 +1,50 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ cpp-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @author Christian <c@ethdev.com>
+ * @date 2015
+ * Evaluator for types of constant expressions.
+ */
+
+#pragma once
+
+#include <libsolidity/ASTVisitor.h>
+
+namespace dev
+{
+namespace solidity
+{
+
+class TypeChecker;
+
+/**
+ * Small drop-in replacement for TypeChecker to evaluate simple expressions of integer constants.
+ */
+class ConstantEvaluator: private ASTConstVisitor
+{
+public:
+ ConstantEvaluator(Expression const& _expr) { _expr.accept(*this); }
+
+private:
+ virtual void endVisit(BinaryOperation const& _operation);
+ virtual void endVisit(UnaryOperation const& _operation);
+ virtual void endVisit(Literal const& _literal);
+
+};
+
+}
+}
diff --git a/libsolidity/Exceptions.h b/libsolidity/Exceptions.h
index 4bb6644b..645b368f 100644
--- a/libsolidity/Exceptions.h
+++ b/libsolidity/Exceptions.h
@@ -32,12 +32,16 @@ namespace dev
namespace solidity
{
-struct ParserError: virtual Exception {};
-struct TypeError: virtual Exception {};
-struct DeclarationError: virtual Exception {};
+struct Error: virtual Exception {};
+
+struct ParserError: virtual Error {};
+struct TypeError: virtual Error {};
+struct DeclarationError: virtual Error {};
+struct DocstringParsingError: virtual Error {};
+
struct CompilerError: virtual Exception {};
struct InternalCompilerError: virtual Exception {};
-struct DocstringParsingError: virtual Exception {};
+struct FatalError: virtual Exception {};
using errorSourceLocationInfo = std::pair<std::string, SourceLocation>;
diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp
index 7db0dde9..65706602 100644
--- a/libsolidity/ExpressionCompiler.cpp
+++ b/libsolidity/ExpressionCompiler.cpp
@@ -48,12 +48,12 @@ void ExpressionCompiler::appendStateVariableInitialization(VariableDeclaration c
{
if (!_varDecl.value())
return;
- TypePointer type = _varDecl.value()->type();
+ TypePointer type = _varDecl.value()->annotation().type;
solAssert(!!type, "Type information not available.");
CompilerContext::LocationSetter locationSetter(m_context, _varDecl);
_varDecl.value()->accept(*this);
- if (_varDecl.type()->dataStoredIn(DataLocation::Storage))
+ if (_varDecl.annotation().type->dataStoredIn(DataLocation::Storage))
{
// reference type, only convert value to mobile type and do final conversion in storeValue.
utils().convertType(*type, *type->mobileType());
@@ -61,8 +61,8 @@ void ExpressionCompiler::appendStateVariableInitialization(VariableDeclaration c
}
else
{
- utils().convertType(*type, *_varDecl.type());
- type = _varDecl.type();
+ utils().convertType(*type, *_varDecl.annotation().type);
+ type = _varDecl.annotation().type;
}
StorageItem(m_context, _varDecl).storeValue(*type, _varDecl.location(), true);
}
@@ -71,10 +71,10 @@ void ExpressionCompiler::appendConstStateVariableAccessor(VariableDeclaration co
{
solAssert(_varDecl.isConstant(), "");
_varDecl.value()->accept(*this);
- utils().convertType(*_varDecl.value()->type(), *_varDecl.type());
+ utils().convertType(*_varDecl.value()->annotation().type, *_varDecl.annotation().type);
// append return
- m_context << eth::dupInstruction(_varDecl.type()->sizeOnStack() + 1);
+ m_context << eth::dupInstruction(_varDecl.annotation().type->sizeOnStack() + 1);
m_context.appendJump(eth::AssemblyItem::JumpType::OutOfFunction);
}
@@ -90,7 +90,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
auto const& location = m_context.storageLocationOfVariable(_varDecl);
m_context << location.first << u256(location.second);
- TypePointer returnType = _varDecl.type();
+ TypePointer returnType = _varDecl.annotation().type;
for (size_t i = 0; i < paramTypes.size(); ++i)
{
@@ -179,11 +179,11 @@ bool ExpressionCompiler::visit(Assignment const& _assignment)
{
CompilerContext::LocationSetter locationSetter(m_context, _assignment);
_assignment.rightHandSide().accept(*this);
- TypePointer type = _assignment.rightHandSide().type();
- if (!_assignment.type()->dataStoredIn(DataLocation::Storage))
+ TypePointer type = _assignment.rightHandSide().annotation().type;
+ if (!_assignment.annotation().type->dataStoredIn(DataLocation::Storage))
{
- utils().convertType(*type, *_assignment.type());
- type = _assignment.type();
+ utils().convertType(*type, *_assignment.annotation().type);
+ type = _assignment.annotation().type;
}
else
{
@@ -197,9 +197,9 @@ bool ExpressionCompiler::visit(Assignment const& _assignment)
Token::Value op = _assignment.assignmentOperator();
if (op != Token::Assign) // compound assignment
{
- solAssert(_assignment.type()->isValueType(), "Compound operators not implemented for non-value types.");
+ solAssert(_assignment.annotation().type->isValueType(), "Compound operators not implemented for non-value types.");
unsigned lvalueSize = m_currentLValue->sizeOnStack();
- unsigned itemSize = _assignment.type()->sizeOnStack();
+ unsigned itemSize = _assignment.annotation().type->sizeOnStack();
if (lvalueSize > 0)
{
utils().copyToStackTop(lvalueSize + itemSize, itemSize);
@@ -207,7 +207,7 @@ bool ExpressionCompiler::visit(Assignment const& _assignment)
// value lvalue_ref value lvalue_ref
}
m_currentLValue->retrieveValue(_assignment.location(), true);
- appendOrdinaryBinaryOperatorCode(Token::AssignmentToBinaryOp(op), *_assignment.type());
+ appendOrdinaryBinaryOperatorCode(Token::AssignmentToBinaryOp(op), *_assignment.annotation().type);
if (lvalueSize > 0)
{
solAssert(itemSize + lvalueSize <= 16, "Stack too deep, try removing local variables.");
@@ -228,9 +228,9 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation)
// the operator should know how to convert itself and to which types it applies, so
// put this code together with "Type::acceptsBinary/UnaryOperator" into a class that
// represents the operator
- if (_unaryOperation.type()->category() == Type::Category::IntegerConstant)
+ if (_unaryOperation.annotation().type->category() == Type::Category::IntegerConstant)
{
- m_context << _unaryOperation.type()->literalValue(nullptr);
+ m_context << _unaryOperation.annotation().type->literalValue(nullptr);
return false;
}
@@ -259,7 +259,7 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation)
if (!_unaryOperation.isPrefixOperation())
{
// store value for later
- solAssert(_unaryOperation.type()->sizeOnStack() == 1, "Stack size != 1 not implemented.");
+ solAssert(_unaryOperation.annotation().type->sizeOnStack() == 1, "Stack size != 1 not implemented.");
m_context << eth::Instruction::DUP1;
if (m_currentLValue->sizeOnStack() > 0)
for (unsigned i = 1 + m_currentLValue->sizeOnStack(); i > 0; --i)
@@ -275,7 +275,7 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation)
for (unsigned i = m_currentLValue->sizeOnStack(); i > 0; --i)
m_context << eth::swapInstruction(i);
m_currentLValue->storeValue(
- *_unaryOperation.type(), _unaryOperation.location(),
+ *_unaryOperation.annotation().type, _unaryOperation.location(),
!_unaryOperation.isPrefixOperation());
m_currentLValue.reset();
break;
@@ -297,7 +297,8 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation)
CompilerContext::LocationSetter locationSetter(m_context, _binaryOperation);
Expression const& leftExpression = _binaryOperation.leftExpression();
Expression const& rightExpression = _binaryOperation.rightExpression();
- Type const& commonType = _binaryOperation.commonType();
+ solAssert(!!_binaryOperation.annotation().commonType, "");
+ Type const& commonType = *_binaryOperation.annotation().commonType;
Token::Value const c_op = _binaryOperation.getOperator();
if (c_op == Token::And || c_op == Token::Or) // special case: short-circuiting
@@ -312,22 +313,22 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation)
// for commutative operators, push the literal as late as possible to allow improved optimization
auto isLiteral = [](Expression const& _e)
{
- return dynamic_cast<Literal const*>(&_e) || _e.type()->category() == Type::Category::IntegerConstant;
+ return dynamic_cast<Literal const*>(&_e) || _e.annotation().type->category() == Type::Category::IntegerConstant;
};
bool swap = m_optimize && Token::isCommutativeOp(c_op) && isLiteral(rightExpression) && !isLiteral(leftExpression);
if (swap)
{
leftExpression.accept(*this);
- utils().convertType(*leftExpression.type(), commonType, cleanupNeeded);
+ utils().convertType(*leftExpression.annotation().type, commonType, cleanupNeeded);
rightExpression.accept(*this);
- utils().convertType(*rightExpression.type(), commonType, cleanupNeeded);
+ utils().convertType(*rightExpression.annotation().type, commonType, cleanupNeeded);
}
else
{
rightExpression.accept(*this);
- utils().convertType(*rightExpression.type(), commonType, cleanupNeeded);
+ utils().convertType(*rightExpression.annotation().type, commonType, cleanupNeeded);
leftExpression.accept(*this);
- utils().convertType(*leftExpression.type(), commonType, cleanupNeeded);
+ utils().convertType(*leftExpression.annotation().type, commonType, cleanupNeeded);
}
if (Token::isCompareOp(c_op))
appendCompareOperatorCode(c_op, commonType);
@@ -343,25 +344,25 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
{
CompilerContext::LocationSetter locationSetter(m_context, _functionCall);
using Location = FunctionType::Location;
- if (_functionCall.isTypeConversion())
+ if (_functionCall.annotation().isTypeConversion)
{
solAssert(_functionCall.arguments().size() == 1, "");
solAssert(_functionCall.names().empty(), "");
Expression const& firstArgument = *_functionCall.arguments().front();
firstArgument.accept(*this);
- utils().convertType(*firstArgument.type(), *_functionCall.type());
+ utils().convertType(*firstArgument.annotation().type, *_functionCall.annotation().type);
return false;
}
FunctionTypePointer functionType;
- if (_functionCall.isStructConstructorCall())
+ if (_functionCall.annotation().isStructConstructorCall)
{
- auto const& type = dynamic_cast<TypeType const&>(*_functionCall.expression().type());
+ auto const& type = dynamic_cast<TypeType const&>(*_functionCall.expression().annotation().type);
auto const& structType = dynamic_cast<StructType const&>(*type.actualType());
functionType = structType.constructorType();
}
else
- functionType = dynamic_pointer_cast<FunctionType const>(_functionCall.expression().type());
+ functionType = dynamic_pointer_cast<FunctionType const>(_functionCall.expression().annotation().type);
TypePointers const& parameterTypes = functionType->parameterTypes();
vector<ASTPointer<Expression const>> const& callArguments = _functionCall.arguments();
@@ -385,9 +386,9 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
solAssert(found, "");
}
- if (_functionCall.isStructConstructorCall())
+ if (_functionCall.annotation().isStructConstructorCall)
{
- TypeType const& type = dynamic_cast<TypeType const&>(*_functionCall.expression().type());
+ TypeType const& type = dynamic_cast<TypeType const&>(*_functionCall.expression().annotation().type);
auto const& structType = dynamic_cast<StructType const&>(*type.actualType());
m_context << max(u256(32u), structType.memorySize());
@@ -397,7 +398,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
for (unsigned i = 0; i < arguments.size(); ++i)
{
arguments[i]->accept(*this);
- utils().convertType(*arguments[i]->type(), *functionType->parameterTypes()[i]);
+ utils().convertType(*arguments[i]->annotation().type, *functionType->parameterTypes()[i]);
utils().storeInMemoryDynamic(*functionType->parameterTypes()[i]);
}
m_context << eth::Instruction::POP;
@@ -416,7 +417,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
for (unsigned i = 0; i < arguments.size(); ++i)
{
arguments[i]->accept(*this);
- utils().convertType(*arguments[i]->type(), *function.parameterTypes()[i]);
+ utils().convertType(*arguments[i]->annotation().type, *function.parameterTypes()[i]);
}
_functionCall.expression().accept(*this);
@@ -449,7 +450,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
for (auto const& arg: arguments)
{
arg->accept(*this);
- argumentTypes.push_back(arg->type());
+ argumentTypes.push_back(arg->annotation().type);
}
ContractDefinition const& contract =
dynamic_cast<ContractType const&>(*function.returnParameterTypes().front()).contractDefinition();
@@ -481,7 +482,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
_functionCall.expression().accept(*this);
arguments.front()->accept(*this);
- utils().convertType(*arguments.front()->type(), IntegerType(256), true);
+ utils().convertType(*arguments.front()->annotation().type, IntegerType(256), true);
// Note that function is not the original function, but the ".gas" function.
// Its values of gasSet and valueSet is equal to the original function's though.
unsigned stackDepth = (function.gasSet() ? 1 : 0) + (function.valueSet() ? 1 : 0);
@@ -505,7 +506,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
m_context << u256(0); // do not send gas (there still is the stipend)
arguments.front()->accept(*this);
utils().convertType(
- *arguments.front()->type(),
+ *arguments.front()->annotation().type,
*function.parameterTypes().front(), true
);
appendExternalFunctionCall(
@@ -525,7 +526,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
break;
case Location::Suicide:
arguments.front()->accept(*this);
- utils().convertType(*arguments.front()->type(), *function.parameterTypes().front(), true);
+ utils().convertType(*arguments.front()->annotation().type, *function.parameterTypes().front(), true);
m_context << eth::Instruction::SUICIDE;
break;
case Location::SHA3:
@@ -534,7 +535,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
for (auto const& arg: arguments)
{
arg->accept(*this);
- argumentTypes.push_back(arg->type());
+ argumentTypes.push_back(arg->annotation().type);
}
utils().fetchFreeMemoryPointer();
utils().encodeToMemory(argumentTypes, TypePointers(), function.padArguments(), true);
@@ -552,12 +553,12 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
for (unsigned arg = logNumber; arg > 0; --arg)
{
arguments[arg]->accept(*this);
- utils().convertType(*arguments[arg]->type(), *function.parameterTypes()[arg], true);
+ utils().convertType(*arguments[arg]->annotation().type, *function.parameterTypes()[arg], true);
}
arguments.front()->accept(*this);
utils().fetchFreeMemoryPointer();
utils().encodeToMemory(
- {arguments.front()->type()},
+ {arguments.front()->annotation().type},
{function.parameterTypes().front()},
false,
true);
@@ -577,7 +578,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
++numIndexed;
arguments[arg - 1]->accept(*this);
utils().convertType(
- *arguments[arg - 1]->type(),
+ *arguments[arg - 1]->annotation().type,
*function.parameterTypes()[arg - 1],
true
);
@@ -596,7 +597,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
if (!event.parameters()[arg]->isIndexed())
{
arguments[arg]->accept(*this);
- nonIndexedArgTypes.push_back(arguments[arg]->type());
+ nonIndexedArgTypes.push_back(arguments[arg]->annotation().type);
nonIndexedParamTypes.push_back(function.parameterTypes()[arg]);
}
utils().fetchFreeMemoryPointer();
@@ -609,7 +610,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
case Location::BlockHash:
{
arguments[0]->accept(*this);
- utils().convertType(*arguments[0]->type(), *function.parameterTypes()[0], true);
+ utils().convertType(*arguments[0]->annotation().type, *function.parameterTypes()[0], true);
m_context << eth::Instruction::BLOCKHASH;
break;
}
@@ -644,24 +645,24 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
{
CompilerContext::LocationSetter locationSetter(m_context, _memberAccess);
ASTString const& member = _memberAccess.memberName();
- switch (_memberAccess.expression().type()->category())
+ switch (_memberAccess.expression().annotation().type->category())
{
case Type::Category::Contract:
{
bool alsoSearchInteger = false;
- ContractType const& type = dynamic_cast<ContractType const&>(*_memberAccess.expression().type());
+ ContractType const& type = dynamic_cast<ContractType const&>(*_memberAccess.expression().annotation().type);
if (type.isSuper())
{
- solAssert(!!_memberAccess.referencedDeclaration(), "Referenced declaration not resolved.");
+ solAssert(!!_memberAccess.annotation().referencedDeclaration, "Referenced declaration not resolved.");
m_context << m_context.superFunctionEntryLabel(
- dynamic_cast<FunctionDefinition const&>(*_memberAccess.referencedDeclaration()),
+ dynamic_cast<FunctionDefinition const&>(*_memberAccess.annotation().referencedDeclaration),
type.contractDefinition()
).pushTag();
}
else
{
// ordinary contract type
- if (Declaration const* declaration = _memberAccess.referencedDeclaration())
+ if (Declaration const* declaration = _memberAccess.annotation().referencedDeclaration)
{
u256 identifier;
if (auto const* variable = dynamic_cast<VariableDeclaration const*>(declaration))
@@ -684,7 +685,7 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
if (member == "balance")
{
utils().convertType(
- *_memberAccess.expression().type(),
+ *_memberAccess.expression().annotation().type,
IntegerType(0, IntegerType::Modifier::Address),
true
);
@@ -692,7 +693,7 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
}
else if ((set<string>{"send", "call", "callcode"}).count(member))
utils().convertType(
- *_memberAccess.expression().type(),
+ *_memberAccess.expression().annotation().type,
IntegerType(0, IntegerType::Modifier::Address),
true
);
@@ -700,7 +701,7 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid member access to integer."));
break;
case Type::Category::Function:
- solAssert(!!_memberAccess.expression().type()->memberType(member),
+ solAssert(!!_memberAccess.expression().annotation().type->memberType(member),
"Invalid member access to function.");
break;
case Type::Category::Magic:
@@ -735,7 +736,7 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
break;
case Type::Category::Struct:
{
- StructType const& type = dynamic_cast<StructType const&>(*_memberAccess.expression().type());
+ StructType const& type = dynamic_cast<StructType const&>(*_memberAccess.expression().annotation().type);
switch (type.location())
{
case DataLocation::Storage:
@@ -748,7 +749,7 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
case DataLocation::Memory:
{
m_context << type.memoryOffsetOfMember(member) << eth::Instruction::ADD;
- setLValue<MemoryItem>(_memberAccess, *_memberAccess.type());
+ setLValue<MemoryItem>(_memberAccess, *_memberAccess.annotation().type);
break;
}
default:
@@ -758,13 +759,13 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
}
case Type::Category::Enum:
{
- EnumType const& type = dynamic_cast<EnumType const&>(*_memberAccess.expression().type());
+ EnumType const& type = dynamic_cast<EnumType const&>(*_memberAccess.expression().annotation().type);
m_context << type.memberValue(_memberAccess.memberName());
break;
}
case Type::Category::TypeType:
{
- TypeType const& type = dynamic_cast<TypeType const&>(*_memberAccess.expression().type());
+ TypeType const& type = dynamic_cast<TypeType const&>(*_memberAccess.expression().annotation().type);
solAssert(
!type.members().membersByName(_memberAccess.memberName()).empty(),
"Invalid member access to " + type.toString(false)
@@ -772,12 +773,12 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
if (dynamic_cast<ContractType const*>(type.actualType().get()))
{
- auto const& funType = dynamic_cast<FunctionType const&>(*_memberAccess.type());
+ auto const& funType = dynamic_cast<FunctionType const&>(*_memberAccess.annotation().type);
if (funType.location() != FunctionType::Location::Internal)
m_context << funType.externalIdentifier();
else
{
- auto const* function = dynamic_cast<FunctionDefinition const*>(_memberAccess.referencedDeclaration());
+ auto const* function = dynamic_cast<FunctionDefinition const*>(_memberAccess.annotation().referencedDeclaration);
solAssert(!!function, "Function not found in member access");
m_context << m_context.functionEntryLabel(*function).pushTag();
}
@@ -789,7 +790,7 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
case Type::Category::Array:
{
solAssert(member == "length", "Illegal array member.");
- auto const& type = dynamic_cast<ArrayType const&>(*_memberAccess.expression().type());
+ auto const& type = dynamic_cast<ArrayType const&>(*_memberAccess.expression().annotation().type);
if (!type.isDynamicallySized())
{
utils().popStackElement(type);
@@ -820,7 +821,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
CompilerContext::LocationSetter locationSetter(m_context, _indexAccess);
_indexAccess.baseExpression().accept(*this);
- Type const& baseType = *_indexAccess.baseExpression().type();
+ Type const& baseType = *_indexAccess.baseExpression().annotation().type;
if (baseType.category() == Type::Category::Mapping)
{
@@ -834,7 +835,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
// stack: base index mem
// note: the following operations must not allocate memory!
utils().encodeToMemory(
- TypePointers{_indexAccess.indexExpression()->type()},
+ TypePointers{_indexAccess.indexExpression()->annotation().type},
TypePointers{keyType},
false,
true
@@ -876,7 +877,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
setLValueToStorageItem(_indexAccess);
break;
case DataLocation::Memory:
- setLValue<MemoryItem>(_indexAccess, *_indexAccess.type(), !arrayType.isByteArray());
+ setLValue<MemoryItem>(_indexAccess, *_indexAccess.annotation().type, !arrayType.isByteArray());
break;
case DataLocation::CallData:
//@todo if we implement this, the value in calldata has to be added to the base offset
@@ -900,14 +901,14 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
void ExpressionCompiler::endVisit(Identifier const& _identifier)
{
CompilerContext::LocationSetter locationSetter(m_context, _identifier);
- Declaration const* declaration = &_identifier.referencedDeclaration();
+ Declaration const* declaration = _identifier.annotation().referencedDeclaration;
if (MagicVariableDeclaration const* magicVar = dynamic_cast<MagicVariableDeclaration const*>(declaration))
{
- switch (magicVar->type()->category())
+ switch (magicVar->type(_identifier.annotation().contractScope)->category())
{
case Type::Category::Contract:
// "this" or "super"
- if (!dynamic_cast<ContractType const&>(*magicVar->type()).isSuper())
+ if (!dynamic_cast<ContractType const&>(*magicVar->type(_identifier.annotation().contractScope)).isSuper())
m_context << eth::Instruction::ADDRESS;
break;
case Type::Category::Integer:
@@ -927,7 +928,7 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier)
else
{
variable->value()->accept(*this);
- utils().convertType(*variable->value()->type(), *variable->type());
+ utils().convertType(*variable->value()->annotation().type, *variable->annotation().type);
}
}
else if (auto contract = dynamic_cast<ContractDefinition const*>(declaration))
@@ -953,7 +954,7 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier)
void ExpressionCompiler::endVisit(Literal const& _literal)
{
CompilerContext::LocationSetter locationSetter(m_context, _literal);
- TypePointer type = _literal.type();
+ TypePointer type = _literal.annotation().type;
switch (type->category())
{
case Type::Category::IntegerConstant:
@@ -1141,7 +1142,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
bool manualFunctionId =
(funKind == FunctionKind::Bare || funKind == FunctionKind::BareCallCode) &&
!_arguments.empty() &&
- _arguments.front()->type()->mobileType()->calldataEncodedSize(false) ==
+ _arguments.front()->annotation().type->mobileType()->calldataEncodedSize(false) ==
CompilerUtils::dataStartOffset;
if (manualFunctionId)
{
@@ -1149,7 +1150,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
// function identifier.
_arguments.front()->accept(*this);
utils().convertType(
- *_arguments.front()->type(),
+ *_arguments.front()->annotation().type,
IntegerType(8 * CompilerUtils::dataStartOffset),
true
);
@@ -1161,7 +1162,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
for (size_t i = manualFunctionId ? 1 : 0; i < _arguments.size(); ++i)
{
_arguments[i]->accept(*this);
- argumentTypes.push_back(_arguments[i]->type());
+ argumentTypes.push_back(_arguments[i]->annotation().type);
}
// Copy function identifier to memory.
@@ -1266,16 +1267,16 @@ void ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType,
{
solAssert(_expectedType.isValueType(), "Not implemented for non-value types.");
_expression.accept(*this);
- utils().convertType(*_expression.type(), _expectedType, true);
+ utils().convertType(*_expression.annotation().type, _expectedType, true);
utils().storeInMemoryDynamic(_expectedType);
}
void ExpressionCompiler::setLValueFromDeclaration(Declaration const& _declaration, Expression const& _expression)
{
if (m_context.isLocalVariable(&_declaration))
- setLValue<StackVariable>(_expression, _declaration);
+ setLValue<StackVariable>(_expression, dynamic_cast<VariableDeclaration const&>(_declaration));
else if (m_context.isStateVariable(&_declaration))
- setLValue<StorageItem>(_expression, _declaration);
+ setLValue<StorageItem>(_expression, dynamic_cast<VariableDeclaration const&>(_declaration));
else
BOOST_THROW_EXCEPTION(InternalCompilerError()
<< errinfo_sourceLocation(_expression.location())
@@ -1284,7 +1285,7 @@ void ExpressionCompiler::setLValueFromDeclaration(Declaration const& _declaratio
void ExpressionCompiler::setLValueToStorageItem(Expression const& _expression)
{
- setLValue<StorageItem>(_expression, *_expression.type());
+ setLValue<StorageItem>(_expression, *_expression.annotation().type);
}
CompilerUtils ExpressionCompiler::utils()
diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h
index 02df4b87..d8fef5af 100644
--- a/libsolidity/ExpressionCompiler.h
+++ b/libsolidity/ExpressionCompiler.h
@@ -127,7 +127,7 @@ void ExpressionCompiler::setLValue(Expression const& _expression, _Arguments con
{
solAssert(!m_currentLValue, "Current LValue not reset before trying to set new one.");
std::unique_ptr<_LValueType> lvalue(new _LValueType(m_context, _arguments...));
- if (_expression.lvalueRequested())
+ if (_expression.annotation().lValueRequested)
m_currentLValue = move(lvalue);
else
lvalue->retrieveValue(_expression.location(), true);
diff --git a/libsolidity/InterfaceHandler.cpp b/libsolidity/InterfaceHandler.cpp
index fc79b493..50006caf 100644
--- a/libsolidity/InterfaceHandler.cpp
+++ b/libsolidity/InterfaceHandler.cpp
@@ -96,7 +96,7 @@ string InterfaceHandler::abiInterface(ContractDefinition const& _contractDef)
{
Json::Value input;
input["name"] = p->name();
- input["type"] = p->type()->toString(true);
+ input["type"] = p->annotation().type->toString(true);
input["indexed"] = p->isIndexed();
params.append(input);
}
diff --git a/libsolidity/LValue.cpp b/libsolidity/LValue.cpp
index eb7cc073..81aaeb4d 100644
--- a/libsolidity/LValue.cpp
+++ b/libsolidity/LValue.cpp
@@ -31,8 +31,8 @@ using namespace dev;
using namespace solidity;
-StackVariable::StackVariable(CompilerContext& _compilerContext, Declaration const& _declaration):
- LValue(_compilerContext, *_declaration.type()),
+StackVariable::StackVariable(CompilerContext& _compilerContext, VariableDeclaration const& _declaration):
+ LValue(_compilerContext, *_declaration.annotation().type),
m_baseStackOffset(m_context.baseStackOffsetOfVariable(_declaration)),
m_size(m_dataType.sizeOnStack())
{
@@ -131,8 +131,8 @@ void MemoryItem::setToZero(SourceLocation const&, bool _removeReference) const
m_context << eth::Instruction::POP;
}
-StorageItem::StorageItem(CompilerContext& _compilerContext, Declaration const& _declaration):
- StorageItem(_compilerContext, *_declaration.type())
+StorageItem::StorageItem(CompilerContext& _compilerContext, VariableDeclaration const& _declaration):
+ StorageItem(_compilerContext, *_declaration.annotation().type)
{
auto const& location = m_context.storageLocationOfVariable(_declaration);
m_context << location.first << u256(location.second);
diff --git a/libsolidity/LValue.h b/libsolidity/LValue.h
index f02d8ad1..cbbfb102 100644
--- a/libsolidity/LValue.h
+++ b/libsolidity/LValue.h
@@ -35,6 +35,7 @@ class Declaration;
class Type;
class ArrayType;
class CompilerContext;
+class VariableDeclaration;
/**
* Abstract class used to retrieve, delete and store data in lvalues/variables.
@@ -76,7 +77,7 @@ protected:
class StackVariable: public LValue
{
public:
- StackVariable(CompilerContext& _compilerContext, Declaration const& _declaration);
+ StackVariable(CompilerContext& _compilerContext, VariableDeclaration const& _declaration);
virtual unsigned sizeOnStack() const override { return 0; }
virtual void retrieveValue(SourceLocation const& _location, bool _remove = false) const override;
@@ -129,7 +130,7 @@ class StorageItem: public LValue
{
public:
/// Constructs the LValue and pushes the location of @a _declaration onto the stack.
- StorageItem(CompilerContext& _compilerContext, Declaration const& _declaration);
+ StorageItem(CompilerContext& _compilerContext, VariableDeclaration const& _declaration);
/// Constructs the LValue and assumes that the storage reference is already on the stack.
StorageItem(CompilerContext& _compilerContext, Type const& _type);
virtual unsigned sizeOnStack() const override { return 2; }
diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp
index c3b49abd..c3e31728 100644
--- a/libsolidity/NameAndTypeResolver.cpp
+++ b/libsolidity/NameAndTypeResolver.cpp
@@ -22,6 +22,7 @@
#include <libsolidity/NameAndTypeResolver.h>
#include <libsolidity/AST.h>
+#include <libsolidity/TypeChecker.h>
#include <libsolidity/Exceptions.h>
using namespace std;
@@ -31,7 +32,9 @@ namespace dev
namespace solidity
{
-NameAndTypeResolver::NameAndTypeResolver(vector<Declaration const*> const& _globals)
+NameAndTypeResolver::NameAndTypeResolver(
+ vector<Declaration const*> const& _globals
+)
{
for (Declaration const* declaration: _globals)
m_scopes[nullptr].registerDeclaration(*declaration);
@@ -54,8 +57,8 @@ void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
linearizeBaseContracts(_contract);
std::vector<ContractDefinition const*> properBases(
- ++_contract.linearizedBaseContracts().begin(),
- _contract.linearizedBaseContracts().end()
+ ++_contract.annotation().linearizedBaseContracts.begin(),
+ _contract.annotation().linearizedBaseContracts.end()
);
for (ContractDefinition const* base: properBases)
@@ -108,13 +111,6 @@ void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
}
}
-void NameAndTypeResolver::checkTypeRequirements(ContractDefinition& _contract)
-{
- for (ASTPointer<StructDefinition> const& structDef: _contract.definedStructs())
- structDef->checkValidityOfMembers();
- _contract.checkTypeRequirements();
-}
-
void NameAndTypeResolver::updateDeclaration(Declaration const& _declaration)
{
m_scopes[nullptr].registerDeclaration(_declaration, false, true);
@@ -187,23 +183,23 @@ void NameAndTypeResolver::linearizeBaseContracts(ContractDefinition& _contract)
list<list<ContractDefinition const*>> input(1, {});
for (ASTPointer<InheritanceSpecifier> const& baseSpecifier: _contract.baseContracts())
{
- ASTPointer<Identifier> baseName = baseSpecifier->name();
- auto base = dynamic_cast<ContractDefinition const*>(&baseName->referencedDeclaration());
+ Identifier const& baseName = baseSpecifier->name();
+ auto base = dynamic_cast<ContractDefinition const*>(baseName.annotation().referencedDeclaration);
if (!base)
- BOOST_THROW_EXCEPTION(baseName->createTypeError("Contract expected."));
+ BOOST_THROW_EXCEPTION(baseName.createTypeError("Contract expected."));
// "push_front" has the effect that bases mentioned later can overwrite members of bases
// mentioned earlier
input.back().push_front(base);
- vector<ContractDefinition const*> const& basesBases = base->linearizedBaseContracts();
+ vector<ContractDefinition const*> const& basesBases = base->annotation().linearizedBaseContracts;
if (basesBases.empty())
- BOOST_THROW_EXCEPTION(baseName->createTypeError("Definition of base has to precede definition of derived contract"));
+ BOOST_THROW_EXCEPTION(baseName.createTypeError("Definition of base has to precede definition of derived contract"));
input.push_front(list<ContractDefinition const*>(basesBases.begin(), basesBases.end()));
}
input.back().push_front(&_contract);
vector<ContractDefinition const*> result = cThreeMerge(input);
if (result.empty())
BOOST_THROW_EXCEPTION(_contract.createTypeError("Linearization of inheritance graph impossible"));
- _contract.setLinearizedBaseContracts(result);
+ _contract.annotation().linearizedBaseContracts = result;
}
template <class _T>
@@ -404,139 +400,5 @@ void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaratio
enterNewSubScope(_declaration);
}
-ReferencesResolver::ReferencesResolver(
- ASTNode& _root,
- NameAndTypeResolver& _resolver,
- ContractDefinition const* _currentContract,
- ParameterList const* _returnParameters,
- bool _resolveInsideCode,
- bool _allowLazyTypes
-):
- m_resolver(_resolver),
- m_currentContract(_currentContract),
- m_returnParameters(_returnParameters),
- m_resolveInsideCode(_resolveInsideCode),
- m_allowLazyTypes(_allowLazyTypes)
-{
- _root.accept(*this);
-}
-
-void ReferencesResolver::endVisit(VariableDeclaration& _variable)
-{
- // endVisit because the internal type needs resolving if it is a user defined type
- // or mapping
- if (_variable.typeName())
- {
- TypePointer type = _variable.typeName()->toType();
- using Location = VariableDeclaration::Location;
- Location loc = _variable.referenceLocation();
- // References are forced to calldata for external function parameters (not return)
- // and memory for parameters (also return) of publicly visible functions.
- // They default to memory for function parameters and storage for local variables.
- if (auto ref = dynamic_cast<ReferenceType const*>(type.get()))
- {
- if (_variable.isExternalCallableParameter())
- {
- // force location of external function parameters (not return) to calldata
- if (loc != Location::Default)
- BOOST_THROW_EXCEPTION(_variable.createTypeError(
- "Location has to be calldata for external functions "
- "(remove the \"memory\" or \"storage\" keyword)."
- ));
- type = ref->copyForLocation(DataLocation::CallData, true);
- }
- else if (_variable.isCallableParameter() && _variable.scope()->isPublic())
- {
- // force locations of public or external function (return) parameters to memory
- if (loc == VariableDeclaration::Location::Storage)
- BOOST_THROW_EXCEPTION(_variable.createTypeError(
- "Location has to be memory for publicly visible functions "
- "(remove the \"storage\" keyword)."
- ));
- type = ref->copyForLocation(DataLocation::Memory, true);
- }
- else
- {
- if (_variable.isConstant())
- {
- if (loc != Location::Default && loc != Location::Memory)
- BOOST_THROW_EXCEPTION(_variable.createTypeError(
- "Storage location has to be \"memory\" (or unspecified) for constants."
- ));
- loc = Location::Memory;
- }
- if (loc == Location::Default)
- loc = _variable.isCallableParameter() ? Location::Memory : Location::Storage;
- bool isPointer = !_variable.isStateVariable();
- type = ref->copyForLocation(
- loc == Location::Memory ?
- DataLocation::Memory :
- DataLocation::Storage,
- isPointer
- );
- }
- }
- else if (loc != Location::Default && !ref)
- BOOST_THROW_EXCEPTION(_variable.createTypeError(
- "Storage location can only be given for array or struct types."
- ));
-
- _variable.setType(type);
-
- if (!_variable.type())
- BOOST_THROW_EXCEPTION(_variable.typeName()->createTypeError("Invalid type name"));
- }
- else if (!m_allowLazyTypes)
- BOOST_THROW_EXCEPTION(_variable.createTypeError("Explicit type needed."));
- // otherwise we have a "var"-declaration whose type is resolved by the first assignment
-}
-
-bool ReferencesResolver::visit(Return& _return)
-{
- _return.setFunctionReturnParameters(m_returnParameters);
- return true;
-}
-
-bool ReferencesResolver::visit(Mapping&)
-{
- return true;
-}
-
-bool ReferencesResolver::visit(UserDefinedTypeName& _typeName)
-{
- auto declarations = m_resolver.nameFromCurrentScope(_typeName.name());
- if (declarations.empty())
- BOOST_THROW_EXCEPTION(
- DeclarationError() <<
- errinfo_sourceLocation(_typeName.location()) <<
- errinfo_comment("Undeclared identifier.")
- );
- else if (declarations.size() > 1)
- BOOST_THROW_EXCEPTION(
- DeclarationError() <<
- errinfo_sourceLocation(_typeName.location()) <<
- errinfo_comment("Duplicate identifier.")
- );
- else
- _typeName.setReferencedDeclaration(**declarations.begin());
- return false;
-}
-
-bool ReferencesResolver::visit(Identifier& _identifier)
-{
- auto declarations = m_resolver.nameFromCurrentScope(_identifier.name());
- if (declarations.empty())
- BOOST_THROW_EXCEPTION(
- DeclarationError() <<
- errinfo_sourceLocation(_identifier.location()) <<
- errinfo_comment("Undeclared identifier.")
- );
- else if (declarations.size() == 1)
- _identifier.setReferencedDeclaration(*declarations.front(), m_currentContract);
- else
- _identifier.setOverloadedDeclarations(m_resolver.cleanedDeclarations(_identifier, declarations));
- return false;
-}
-
}
}
diff --git a/libsolidity/NameAndTypeResolver.h b/libsolidity/NameAndTypeResolver.h
index 101787ea..d28671ed 100644
--- a/libsolidity/NameAndTypeResolver.h
+++ b/libsolidity/NameAndTypeResolver.h
@@ -25,9 +25,10 @@
#include <map>
#include <list>
#include <boost/noncopyable.hpp>
-
#include <libsolidity/DeclarationContainer.h>
+#include <libsolidity/ReferencesResolver.h>
#include <libsolidity/ASTVisitor.h>
+#include <libsolidity/ASTAnnotations.h>
namespace dev
{
@@ -42,13 +43,11 @@ namespace solidity
class NameAndTypeResolver: private boost::noncopyable
{
public:
- explicit NameAndTypeResolver(std::vector<Declaration const*> const& _globals);
+ NameAndTypeResolver(std::vector<Declaration const*> const& _globals);
/// Registers all declarations found in the source unit.
void registerDeclarations(SourceUnit& _sourceUnit);
/// Resolves all names and types referenced from the given contract.
void resolveNamesAndTypes(ContractDefinition& _contract);
- /// Check all type requirements in the given contract.
- void checkTypeRequirements(ContractDefinition& _contract);
/// Updates the given global declaration (used for "this"). Not to be used with declarations
/// that create their own scope.
void updateDeclaration(Declaration const& _declaration);
@@ -125,36 +124,5 @@ private:
VariableScope* m_currentFunction;
};
-/**
- * Resolves references to declarations (of variables and types) and also establishes the link
- * between a return statement and the return parameter list.
- */
-class ReferencesResolver: private ASTVisitor
-{
-public:
- ReferencesResolver(
- ASTNode& _root,
- NameAndTypeResolver& _resolver,
- ContractDefinition const* _currentContract,
- ParameterList const* _returnParameters,
- bool _resolveInsideCode = false,
- bool _allowLazyTypes = true
- );
-
-private:
- virtual void endVisit(VariableDeclaration& _variable) override;
- virtual bool visit(Block&) override { return m_resolveInsideCode; }
- virtual bool visit(Identifier& _identifier) override;
- virtual bool visit(UserDefinedTypeName& _typeName) override;
- virtual bool visit(Mapping&) override;
- virtual bool visit(Return& _return) override;
-
- NameAndTypeResolver& m_resolver;
- ContractDefinition const* m_currentContract;
- ParameterList const* m_returnParameters;
- bool m_resolveInsideCode;
- bool m_allowLazyTypes;
-};
-
}
}
diff --git a/libsolidity/ReferencesResolver.cpp b/libsolidity/ReferencesResolver.cpp
new file mode 100644
index 00000000..623ac8f7
--- /dev/null
+++ b/libsolidity/ReferencesResolver.cpp
@@ -0,0 +1,225 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ cpp-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @author Christian <c@ethdev.com>
+ * @date 2015
+ * Component that resolves type names to types and annotates the AST accordingly.
+ */
+
+#include <libsolidity/ReferencesResolver.h>
+#include <libsolidity/AST.h>
+#include <libsolidity/NameAndTypeResolver.h>
+#include <libsolidity/Exceptions.h>
+#include <libsolidity/ConstantEvaluator.h>
+
+using namespace std;
+using namespace dev;
+using namespace dev::solidity;
+
+
+ReferencesResolver::ReferencesResolver(
+ ASTNode& _root,
+ NameAndTypeResolver& _resolver,
+ ContractDefinition const* _currentContract,
+ ParameterList const* _returnParameters,
+ bool _resolveInsideCode
+):
+ m_resolver(_resolver),
+ m_currentContract(_currentContract),
+ m_returnParameters(_returnParameters),
+ m_resolveInsideCode(_resolveInsideCode)
+{
+ _root.accept(*this);
+}
+
+bool ReferencesResolver::visit(Return const& _return)
+{
+ _return.annotation().functionReturnParameters = m_returnParameters;
+ return true;
+}
+
+bool ReferencesResolver::visit(UserDefinedTypeName const& _typeName)
+{
+ auto declarations = m_resolver.nameFromCurrentScope(_typeName.name());
+ if (declarations.empty())
+ BOOST_THROW_EXCEPTION(
+ DeclarationError() <<
+ errinfo_sourceLocation(_typeName.location()) <<
+ errinfo_comment("Undeclared identifier.")
+ );
+ else if (declarations.size() > 1)
+ BOOST_THROW_EXCEPTION(
+ DeclarationError() <<
+ errinfo_sourceLocation(_typeName.location()) <<
+ errinfo_comment("Duplicate identifier.")
+ );
+ Declaration const* declaration = *declarations.begin();
+ _typeName.annotation().referencedDeclaration = declaration;
+ return true;
+}
+
+bool ReferencesResolver::visit(Identifier const& _identifier)
+{
+ auto declarations = m_resolver.nameFromCurrentScope(_identifier.name());
+ if (declarations.empty())
+ BOOST_THROW_EXCEPTION(
+ DeclarationError() <<
+ errinfo_sourceLocation(_identifier.location()) <<
+ errinfo_comment("Undeclared identifier.")
+ );
+ else if (declarations.size() == 1)
+ {
+ _identifier.annotation().referencedDeclaration = declarations.front();
+ _identifier.annotation().contractScope = m_currentContract;
+ }
+ else
+ _identifier.annotation().overloadedDeclarations =
+ m_resolver.cleanedDeclarations(_identifier, declarations);
+ return false;
+}
+
+void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
+{
+ if (_variable.annotation().type)
+ return;
+
+ TypePointer type;
+ if (_variable.typeName())
+ {
+ type = typeFor(*_variable.typeName());
+ using Location = VariableDeclaration::Location;
+ Location loc = _variable.referenceLocation();
+ // References are forced to calldata for external function parameters (not return)
+ // and memory for parameters (also return) of publicly visible functions.
+ // They default to memory for function parameters and storage for local variables.
+ if (auto ref = dynamic_cast<ReferenceType const*>(type.get()))
+ {
+ if (_variable.isExternalCallableParameter())
+ {
+ // force location of external function parameters (not return) to calldata
+ if (loc != Location::Default)
+ BOOST_THROW_EXCEPTION(_variable.createTypeError(
+ "Location has to be calldata for external functions "
+ "(remove the \"memory\" or \"storage\" keyword)."
+ ));
+ type = ref->copyForLocation(DataLocation::CallData, true);
+ }
+ else if (_variable.isCallableParameter() && _variable.scope()->isPublic())
+ {
+ // force locations of public or external function (return) parameters to memory
+ if (loc == VariableDeclaration::Location::Storage)
+ BOOST_THROW_EXCEPTION(_variable.createTypeError(
+ "Location has to be memory for publicly visible functions "
+ "(remove the \"storage\" keyword)."
+ ));
+ type = ref->copyForLocation(DataLocation::Memory, true);
+ }
+ else
+ {
+ if (_variable.isConstant())
+ {
+ if (loc != Location::Default && loc != Location::Memory)
+ BOOST_THROW_EXCEPTION(_variable.createTypeError(
+ "Storage location has to be \"memory\" (or unspecified) for constants."
+ ));
+ loc = Location::Memory;
+ }
+ if (loc == Location::Default)
+ loc = _variable.isCallableParameter() ? Location::Memory : Location::Storage;
+ bool isPointer = !_variable.isStateVariable();
+ type = ref->copyForLocation(
+ loc == Location::Memory ?
+ DataLocation::Memory :
+ DataLocation::Storage,
+ isPointer
+ );
+ }
+ }
+ else if (loc != Location::Default && !ref)
+ BOOST_THROW_EXCEPTION(_variable.createTypeError(
+ "Storage location can only be given for array or struct types."
+ ));
+
+ if (!type)
+ BOOST_THROW_EXCEPTION(_variable.typeName()->createTypeError("Invalid type name."));
+
+ }
+ else if (!_variable.canHaveAutoType())
+ BOOST_THROW_EXCEPTION(_variable.createTypeError("Explicit type needed."));
+ // otherwise we have a "var"-declaration whose type is resolved by the first assignment
+
+ _variable.annotation().type = type;
+}
+
+TypePointer ReferencesResolver::typeFor(TypeName const& _typeName)
+{
+ if (_typeName.annotation().type)
+ return _typeName.annotation().type;
+
+ TypePointer type;
+ if (auto elemTypeName = dynamic_cast<ElementaryTypeName const*>(&_typeName))
+ type = Type::fromElementaryTypeName(elemTypeName->typeName());
+ else if (auto typeName = dynamic_cast<UserDefinedTypeName const*>(&_typeName))
+ {
+ Declaration const* declaration = typeName->annotation().referencedDeclaration;
+ solAssert(!!declaration, "");
+
+ if (StructDefinition const* structDef = dynamic_cast<StructDefinition const*>(declaration))
+ type = make_shared<StructType>(*structDef);
+ else if (EnumDefinition const* enumDef = dynamic_cast<EnumDefinition const*>(declaration))
+ type = make_shared<EnumType>(*enumDef);
+ else if (ContractDefinition const* contract = dynamic_cast<ContractDefinition const*>(declaration))
+ type = make_shared<ContractType>(*contract);
+ else
+ BOOST_THROW_EXCEPTION(typeName->createTypeError(
+ "Name has to refer to a struct, enum or contract."
+ ));
+ }
+ else if (auto mapping = dynamic_cast<Mapping const*>(&_typeName))
+ {
+ TypePointer keyType = typeFor(mapping->keyType());
+ TypePointer valueType = typeFor(mapping->valueType());
+ // Convert key type to memory.
+ keyType = ReferenceType::copyForLocationIfReference(DataLocation::Memory, keyType);
+ // Convert value type to storage reference.
+ valueType = ReferenceType::copyForLocationIfReference(DataLocation::Storage, valueType);
+ type = make_shared<MappingType>(keyType, valueType);
+ }
+ else if (auto arrayType = dynamic_cast<ArrayTypeName const*>(&_typeName))
+ {
+ TypePointer baseType = typeFor(arrayType->baseType());
+ if (baseType->storageBytes() == 0)
+ BOOST_THROW_EXCEPTION(arrayType->baseType().createTypeError(
+ "Illegal base type of storage size zero for array."
+ ));
+ if (Expression const* length = arrayType->length())
+ {
+ if (!length->annotation().type)
+ ConstantEvaluator e(*length);
+
+ auto const* lengthType = dynamic_cast<IntegerConstantType const*>(length->annotation().type.get());
+ if (!lengthType)
+ BOOST_THROW_EXCEPTION(length->createTypeError("Invalid array length."));
+ type = make_shared<ArrayType>(DataLocation::Storage, baseType, lengthType->literalValue(nullptr));
+ }
+ else
+ type = make_shared<ArrayType>(DataLocation::Storage, baseType);
+ }
+
+ return _typeName.annotation().type = move(type);
+}
+
diff --git a/libsolidity/ReferencesResolver.h b/libsolidity/ReferencesResolver.h
new file mode 100644
index 00000000..b8a55dc2
--- /dev/null
+++ b/libsolidity/ReferencesResolver.h
@@ -0,0 +1,69 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ cpp-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @author Christian <c@ethdev.com>
+ * @date 2014
+ * Component that resolves type names to types and annotates the AST accordingly.
+ */
+
+#pragma once
+
+#include <map>
+#include <list>
+#include <boost/noncopyable.hpp>
+#include <libsolidity/ASTVisitor.h>
+#include <libsolidity/ASTAnnotations.h>
+
+namespace dev
+{
+namespace solidity
+{
+
+class NameAndTypeResolver;
+
+/**
+ * Resolves references to declarations (of variables and types) and also establishes the link
+ * between a return statement and the return parameter list.
+ */
+class ReferencesResolver: private ASTConstVisitor
+{
+public:
+ ReferencesResolver(
+ ASTNode& _root,
+ NameAndTypeResolver& _resolver,
+ ContractDefinition const* _currentContract,
+ ParameterList const* _returnParameters,
+ bool _resolveInsideCode = false
+ );
+
+private:
+ virtual bool visit(Block const&) override { return m_resolveInsideCode; }
+ virtual bool visit(Identifier const& _identifier) override;
+ virtual bool visit(UserDefinedTypeName const& _typeName) override;
+ virtual bool visit(Return const& _return) override;
+ virtual void endVisit(VariableDeclaration const& _variable) override;
+
+ TypePointer typeFor(TypeName const& _typeName);
+
+ NameAndTypeResolver& m_resolver;
+ ContractDefinition const* m_currentContract;
+ ParameterList const* m_returnParameters;
+ bool m_resolveInsideCode;
+};
+
+}
+}
diff --git a/libsolidity/TypeChecker.cpp b/libsolidity/TypeChecker.cpp
new file mode 100644
index 00000000..f453e2fa
--- /dev/null
+++ b/libsolidity/TypeChecker.cpp
@@ -0,0 +1,1143 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ cpp-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @author Christian <c@ethdev.com>
+ * @date 2015
+ * Type analyzer and checker.
+ */
+
+#include <libsolidity/TypeChecker.h>
+#include <memory>
+#include <boost/range/adaptor/reversed.hpp>
+#include <libsolidity/AST.h>
+
+using namespace std;
+using namespace dev;
+using namespace dev::solidity;
+
+
+bool TypeChecker::checkTypeRequirements(const ContractDefinition& _contract)
+{
+ try
+ {
+ visit(_contract);
+ }
+ catch (FatalError const&)
+ {
+ // We got a fatal error which required to stop further type checking, but we can
+ // continue normally from here.
+ if (m_errors.empty())
+ throw; // Something is weird here, rather throw again.
+ }
+
+ return m_errors.empty();
+}
+
+TypePointer const& TypeChecker::type(Expression const& _expression) const
+{
+ solAssert(!!_expression.annotation().type, "Type requested but not present.");
+ return _expression.annotation().type;
+}
+
+TypePointer const& TypeChecker::type(VariableDeclaration const& _variable) const
+{
+ solAssert(!!_variable.annotation().type, "Type requested but not present.");
+ return _variable.annotation().type;
+}
+
+bool TypeChecker::visit(ContractDefinition const& _contract)
+{
+ // We force our own visiting order here.
+ ASTNode::listAccept(_contract.definedStructs(), *this);
+ ASTNode::listAccept(_contract.baseContracts(), *this);
+
+ checkContractDuplicateFunctions(_contract);
+ checkContractIllegalOverrides(_contract);
+ checkContractAbstractFunctions(_contract);
+ checkContractAbstractConstructors(_contract);
+
+ FunctionDefinition const* function = _contract.constructor();
+ if (function && !function->returnParameters().empty())
+ typeError(*function->returnParameterList(), "Non-empty \"returns\" directive for constructor.");
+
+ FunctionDefinition const* fallbackFunction = nullptr;
+ for (ASTPointer<FunctionDefinition> const& function: _contract.definedFunctions())
+ {
+ if (function->name().empty())
+ {
+ if (fallbackFunction)
+ {
+ auto err = make_shared<DeclarationError>();
+ *err << errinfo_comment("Only one fallback function is allowed.");
+ m_errors.push_back(err);
+ }
+ else
+ {
+ fallbackFunction = function.get();
+ if (!fallbackFunction->parameters().empty())
+ typeError(fallbackFunction->parameterList(), "Fallback function cannot take parameters.");
+ }
+ }
+ if (!function->isImplemented())
+ _contract.annotation().isFullyImplemented = false;
+ }
+
+ ASTNode::listAccept(_contract.stateVariables(), *this);
+ ASTNode::listAccept(_contract.events(), *this);
+ ASTNode::listAccept(_contract.functionModifiers(), *this);
+ ASTNode::listAccept(_contract.definedFunctions(), *this);
+
+ checkContractExternalTypeClashes(_contract);
+ // check for hash collisions in function signatures
+ set<FixedHash<4>> hashes;
+ for (auto const& it: _contract.interfaceFunctionList())
+ {
+ FixedHash<4> const& hash = it.first;
+ if (hashes.count(hash))
+ typeError(
+ _contract,
+ string("Function signature hash collision for ") + it.second->externalSignature()
+ );
+ hashes.insert(hash);
+ }
+
+ if (_contract.isLibrary())
+ checkLibraryRequirements(_contract);
+
+ return false;
+}
+
+void TypeChecker::checkContractDuplicateFunctions(ContractDefinition const& _contract)
+{
+ /// Checks that two functions with the same name defined in this contract have different
+ /// argument types and that there is at most one constructor.
+ map<string, vector<FunctionDefinition const*>> functions;
+ for (ASTPointer<FunctionDefinition> const& function: _contract.definedFunctions())
+ functions[function->name()].push_back(function.get());
+
+ // Constructor
+ if (functions[_contract.name()].size() > 1)
+ {
+ SecondarySourceLocation ssl;
+ auto it = ++functions[_contract.name()].begin();
+ for (; it != functions[_contract.name()].end(); ++it)
+ ssl.append("Another declaration is here:", (*it)->location());
+
+ auto err = make_shared<DeclarationError>();
+ *err <<
+ errinfo_sourceLocation(functions[_contract.name()].front()->location()) <<
+ errinfo_comment("More than one constructor defined.") <<
+ errinfo_secondarySourceLocation(ssl);
+ m_errors.push_back(err);
+ }
+ for (auto const& it: functions)
+ {
+ vector<FunctionDefinition const*> const& overloads = it.second;
+ for (size_t i = 0; i < overloads.size(); ++i)
+ for (size_t j = i + 1; j < overloads.size(); ++j)
+ if (FunctionType(*overloads[i]).hasEqualArgumentTypes(FunctionType(*overloads[j])))
+ {
+ auto err = make_shared<DeclarationError>();
+ *err <<
+ errinfo_sourceLocation(overloads[j]->location()) <<
+ errinfo_comment("Function with same name and arguments defined twice.") <<
+ errinfo_secondarySourceLocation(SecondarySourceLocation().append(
+ "Other declaration is here:", overloads[i]->location()));
+ m_errors.push_back(err);
+ }
+ }
+}
+
+void TypeChecker::checkContractAbstractFunctions(ContractDefinition const& _contract)
+{
+ // Mapping from name to function definition (exactly one per argument type equality class) and
+ // flag to indicate whether it is fully implemented.
+ using FunTypeAndFlag = std::pair<FunctionTypePointer, bool>;
+ map<string, vector<FunTypeAndFlag>> functions;
+
+ // Search from base to derived
+ for (ContractDefinition const* contract: boost::adaptors::reverse(_contract.annotation().linearizedBaseContracts))
+ for (ASTPointer<FunctionDefinition> const& function: contract->definedFunctions())
+ {
+ auto& overloads = functions[function->name()];
+ FunctionTypePointer funType = make_shared<FunctionType>(*function);
+ auto it = find_if(overloads.begin(), overloads.end(), [&](FunTypeAndFlag const& _funAndFlag)
+ {
+ return funType->hasEqualArgumentTypes(*_funAndFlag.first);
+ });
+ if (it == overloads.end())
+ overloads.push_back(make_pair(funType, function->isImplemented()));
+ else if (it->second)
+ {
+ if (!function->isImplemented())
+ typeError(*function, "Redeclaring an already implemented function as abstract");
+ }
+ else if (function->isImplemented())
+ it->second = true;
+ }
+
+ // Set to not fully implemented if at least one flag is false.
+ for (auto const& it: functions)
+ for (auto const& funAndFlag: it.second)
+ if (!funAndFlag.second)
+ {
+ _contract.annotation().isFullyImplemented = false;
+ return;
+ }
+}
+
+void TypeChecker::checkContractAbstractConstructors(ContractDefinition const& _contract)
+{
+ set<ContractDefinition const*> argumentsNeeded;
+ // check that we get arguments for all base constructors that need it.
+ // If not mark the contract as abstract (not fully implemented)
+
+ vector<ContractDefinition const*> const& bases = _contract.annotation().linearizedBaseContracts;
+ for (ContractDefinition const* contract: bases)
+ if (FunctionDefinition const* constructor = contract->constructor())
+ if (contract != &_contract && !constructor->parameters().empty())
+ argumentsNeeded.insert(contract);
+
+ for (ContractDefinition const* contract: bases)
+ {
+ if (FunctionDefinition const* constructor = contract->constructor())
+ for (auto const& modifier: constructor->modifiers())
+ {
+ auto baseContract = dynamic_cast<ContractDefinition const*>(
+ &dereference(*modifier->name())
+ );
+ if (baseContract)
+ argumentsNeeded.erase(baseContract);
+ }
+
+
+ for (ASTPointer<InheritanceSpecifier> const& base: contract->baseContracts())
+ {
+ auto baseContract = dynamic_cast<ContractDefinition const*>(&dereference(base->name()));
+ solAssert(baseContract, "");
+ if (!base->arguments().empty())
+ argumentsNeeded.erase(baseContract);
+ }
+ }
+ if (!argumentsNeeded.empty())
+ _contract.annotation().isFullyImplemented = false;
+}
+
+void TypeChecker::checkContractIllegalOverrides(ContractDefinition const& _contract)
+{
+ // TODO unify this at a later point. for this we need to put the constness and the access specifier
+ // into the types
+ map<string, vector<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: _contract.annotation().linearizedBaseContracts)
+ {
+ for (ASTPointer<FunctionDefinition> const& function: contract->definedFunctions())
+ {
+ if (function->isConstructor())
+ continue; // constructors can neither be overridden nor override anything
+ string const& name = function->name();
+ if (modifiers.count(name))
+ typeError(*modifiers[name], "Override changes function to modifier.");
+ FunctionType functionType(*function);
+ // function should not change the return type
+ for (FunctionDefinition const* overriding: functions[name])
+ {
+ FunctionType overridingType(*overriding);
+ if (!overridingType.hasEqualArgumentTypes(functionType))
+ continue;
+ if (
+ overriding->visibility() != function->visibility() ||
+ overriding->isDeclaredConst() != function->isDeclaredConst() ||
+ overridingType != functionType
+ )
+ typeError(*overriding, "Override changes extended function signature.");
+ }
+ functions[name].push_back(function.get());
+ }
+ for (ASTPointer<ModifierDefinition> const& modifier: contract->functionModifiers())
+ {
+ string const& name = modifier->name();
+ ModifierDefinition const*& override = modifiers[name];
+ if (!override)
+ override = modifier.get();
+ else if (ModifierType(*override) != ModifierType(*modifier))
+ typeError(*override, "Override changes modifier signature.");
+ if (!functions[name].empty())
+ typeError(*override, "Override changes modifier to function.");
+ }
+ }
+}
+
+void TypeChecker::checkContractExternalTypeClashes(ContractDefinition const& _contract)
+{
+ map<string, vector<pair<Declaration const*, FunctionTypePointer>>> externalDeclarations;
+ for (ContractDefinition const* contract: _contract.annotation().linearizedBaseContracts)
+ {
+ for (ASTPointer<FunctionDefinition> const& f: contract->definedFunctions())
+ if (f->isPartOfExternalInterface())
+ {
+ auto functionType = make_shared<FunctionType>(*f);
+ externalDeclarations[functionType->externalSignature(f->name())].push_back(
+ make_pair(f.get(), functionType)
+ );
+ }
+ for (ASTPointer<VariableDeclaration> const& v: contract->stateVariables())
+ if (v->isPartOfExternalInterface())
+ {
+ auto functionType = make_shared<FunctionType>(*v);
+ externalDeclarations[functionType->externalSignature(v->name())].push_back(
+ make_pair(v.get(), functionType)
+ );
+ }
+ }
+ for (auto const& it: externalDeclarations)
+ for (size_t i = 0; i < it.second.size(); ++i)
+ for (size_t j = i + 1; j < it.second.size(); ++j)
+ if (!it.second[i].second->hasEqualArgumentTypes(*it.second[j].second))
+ typeError(
+ *it.second[j].first,
+ "Function overload clash during conversion to external types for arguments."
+ );
+}
+
+void TypeChecker::checkLibraryRequirements(ContractDefinition const& _contract)
+{
+ solAssert(_contract.isLibrary(), "");
+ if (!_contract.baseContracts().empty())
+ typeError(_contract, "Library is not allowed to inherit.");
+
+ for (auto const& var: _contract.stateVariables())
+ if (!var->isConstant())
+ typeError(*var, "Library cannot have non-constant state variables");
+}
+
+void TypeChecker::endVisit(InheritanceSpecifier const& _inheritance)
+{
+ auto base = dynamic_cast<ContractDefinition const*>(&dereference(_inheritance.name()));
+ solAssert(base, "Base contract not available.");
+
+ if (base->isLibrary())
+ typeError(_inheritance, "Libraries cannot be inherited from.");
+
+ auto const& arguments = _inheritance.arguments();
+ TypePointers parameterTypes = ContractType(*base).constructorType()->parameterTypes();
+ if (!arguments.empty() && parameterTypes.size() != arguments.size())
+ typeError(
+ _inheritance,
+ "Wrong argument count for constructor call: " +
+ toString(arguments.size()) +
+ " arguments given but expected " +
+ toString(parameterTypes.size()) +
+ "."
+ );
+
+ for (size_t i = 0; i < arguments.size(); ++i)
+ if (!type(*arguments[i])->isImplicitlyConvertibleTo(*parameterTypes[i]))
+ typeError(
+ *arguments[i],
+ "Invalid type for argument in constructor call. "
+ "Invalid implicit conversion from " +
+ type(*arguments[i])->toString() +
+ " to " +
+ parameterTypes[i]->toString() +
+ " requested."
+ );
+}
+
+bool TypeChecker::visit(StructDefinition const& _struct)
+{
+ for (ASTPointer<VariableDeclaration> const& member: _struct.members())
+ if (!type(*member)->canBeStored())
+ typeError(*member, "Type cannot be used in struct.");
+
+ // Check recursion, fatal error if detected.
+ using StructPointer = StructDefinition const*;
+ using StructPointersSet = set<StructPointer>;
+ function<void(StructPointer,StructPointersSet const&)> check = [&](StructPointer _struct, StructPointersSet const& _parents)
+ {
+ if (_parents.count(_struct))
+ fatalTypeError(*_struct, "Recursive struct definition.");
+ StructPointersSet parents = _parents;
+ parents.insert(_struct);
+ for (ASTPointer<VariableDeclaration> const& member: _struct->members())
+ if (type(*member)->category() == Type::Category::Struct)
+ {
+ auto const& typeName = dynamic_cast<UserDefinedTypeName const&>(*member->typeName());
+ check(&dynamic_cast<StructDefinition const&>(*typeName.annotation().referencedDeclaration), parents);
+ }
+ };
+ check(&_struct, StructPointersSet{});
+
+ ASTNode::listAccept(_struct.members(), *this);
+
+ return false;
+}
+
+bool TypeChecker::visit(FunctionDefinition const& _function)
+{
+ for (ASTPointer<VariableDeclaration> const& var: _function.parameters() + _function.returnParameters())
+ {
+ if (!type(*var)->canLiveOutsideStorage())
+ typeError(*var, "Type is required to live outside storage.");
+ if (_function.visibility() >= FunctionDefinition::Visibility::Public && !(type(*var)->externalType()))
+ typeError(*var, "Internal type is not allowed for public and external functions.");
+ }
+ for (ASTPointer<ModifierInvocation> const& modifier: _function.modifiers())
+ visitManually(
+ *modifier,
+ _function.isConstructor() ?
+ dynamic_cast<ContractDefinition const&>(*_function.scope()).annotation().linearizedBaseContracts :
+ vector<ContractDefinition const*>()
+ );
+ if (_function.isImplemented())
+ _function.body().accept(*this);
+ return false;
+}
+
+bool TypeChecker::visit(VariableDeclaration const& _variable)
+{
+ // 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.
+
+ // This only infers the type from its type name.
+ // If an explicit type is required, it throws, otherwise it returns TypePointer();
+ TypePointer varType = _variable.annotation().type;
+ if (_variable.isConstant())
+ {
+ if (!dynamic_cast<ContractDefinition const*>(_variable.scope()))
+ typeError(_variable, "Illegal use of \"constant\" specifier.");
+ if (!_variable.value())
+ typeError(_variable, "Uninitialized \"constant\" variable.");
+ if (varType && !varType->isValueType())
+ {
+ bool constImplemented = false;
+ if (auto arrayType = dynamic_cast<ArrayType const*>(varType.get()))
+ constImplemented = arrayType->isByteArray();
+ if (!constImplemented)
+ typeError(
+ _variable,
+ "Illegal use of \"constant\" specifier. \"constant\" "
+ "is not yet implemented for this type."
+ );
+ }
+ }
+ if (varType)
+ {
+ if (_variable.value())
+ expectType(*_variable.value(), *varType);
+ }
+ else
+ {
+ // Infer type from value.
+ if (!_variable.value())
+ fatalTypeError(_variable, "Assignment necessary for type detection.");
+ _variable.value()->accept(*this);
+
+ TypePointer const& valueType = type(*_variable.value());
+ solAssert(!!valueType, "");
+ if (
+ valueType->category() == Type::Category::IntegerConstant &&
+ !dynamic_pointer_cast<IntegerConstantType const>(valueType)->integerType()
+ )
+ fatalTypeError(*_variable.value(), "Invalid integer constant " + valueType->toString() + ".");
+ else if (valueType->category() == Type::Category::Void)
+ fatalTypeError(_variable, "Variable cannot have void type.");
+ varType = valueType->mobileType();
+ }
+ solAssert(!!varType, "");
+ _variable.annotation().type = varType;
+ if (!_variable.isStateVariable())
+ {
+ if (varType->dataStoredIn(DataLocation::Memory) || varType->dataStoredIn(DataLocation::CallData))
+ if (!varType->canLiveOutsideStorage())
+ typeError(_variable, "Type " + varType->toString() + " is only valid in storage.");
+ }
+ else if (
+ _variable.visibility() >= VariableDeclaration::Visibility::Public &&
+ !FunctionType(_variable).externalType()
+ )
+ typeError(_variable, "Internal type is not allowed for public state variables.");
+ return false;
+}
+
+void TypeChecker::visitManually(
+ ModifierInvocation const& _modifier,
+ vector<ContractDefinition const*> const& _bases
+)
+{
+ std::vector<ASTPointer<Expression>> const& arguments = _modifier.arguments();
+ for (ASTPointer<Expression> const& argument: arguments)
+ argument->accept(*this);
+ _modifier.name()->accept(*this);
+
+ auto const* declaration = &dereference(*_modifier.name());
+ vector<ASTPointer<VariableDeclaration>> emptyParameterList;
+ vector<ASTPointer<VariableDeclaration>> const* parameters = nullptr;
+ if (auto modifierDecl = dynamic_cast<ModifierDefinition const*>(declaration))
+ parameters = &modifierDecl->parameters();
+ else
+ // check parameters for Base constructors
+ for (ContractDefinition const* base: _bases)
+ if (declaration == base)
+ {
+ if (auto referencedConstructor = base->constructor())
+ parameters = &referencedConstructor->parameters();
+ else
+ parameters = &emptyParameterList;
+ break;
+ }
+ if (!parameters)
+ typeError(_modifier, "Referenced declaration is neither modifier nor base class.");
+ if (parameters->size() != arguments.size())
+ typeError(
+ _modifier,
+ "Wrong argument count for modifier invocation: " +
+ toString(arguments.size()) +
+ " arguments given but expected " +
+ toString(parameters->size()) +
+ "."
+ );
+ for (size_t i = 0; i < _modifier.arguments().size(); ++i)
+ if (!type(*arguments[i])->isImplicitlyConvertibleTo(*type(*(*parameters)[i])))
+ typeError(
+ *arguments[i],
+ "Invalid type for argument in modifier invocation. "
+ "Invalid implicit conversion from " +
+ type(*arguments[i])->toString() +
+ " to " +
+ type(*(*parameters)[i])->toString() +
+ " requested."
+ );
+}
+
+bool TypeChecker::visit(EventDefinition const& _eventDef)
+{
+ unsigned numIndexed = 0;
+ for (ASTPointer<VariableDeclaration> const& var: _eventDef.parameters())
+ {
+ if (var->isIndexed())
+ numIndexed++;
+ if (numIndexed > 3)
+ typeError(_eventDef, "More than 3 indexed arguments for event.");
+ if (!type(*var)->canLiveOutsideStorage())
+ typeError(*var, "Type is required to live outside storage.");
+ if (!type(*var)->externalType())
+ typeError(*var, "Internal type is not allowed as event parameter type.");
+ }
+ return false;
+}
+
+
+bool TypeChecker::visit(IfStatement const& _ifStatement)
+{
+ expectType(_ifStatement.condition(), BoolType());
+ _ifStatement.trueStatement().accept(*this);
+ if (_ifStatement.falseStatement())
+ _ifStatement.falseStatement()->accept(*this);
+ return false;
+}
+
+bool TypeChecker::visit(WhileStatement const& _whileStatement)
+{
+ expectType(_whileStatement.condition(), BoolType());
+ _whileStatement.body().accept(*this);
+ return false;
+}
+
+bool TypeChecker::visit(ForStatement const& _forStatement)
+{
+ if (_forStatement.initializationExpression())
+ _forStatement.initializationExpression()->accept(*this);
+ if (_forStatement.condition())
+ expectType(*_forStatement.condition(), BoolType());
+ if (_forStatement.loopExpression())
+ _forStatement.loopExpression()->accept(*this);
+ _forStatement.body().accept(*this);
+ return false;
+}
+
+void TypeChecker::endVisit(Return const& _return)
+{
+ if (!_return.expression())
+ return;
+ ParameterList const* params = _return.annotation().functionReturnParameters;
+ if (!params)
+ typeError(_return, "Return arguments not allowed.");
+ else if (params->parameters().size() != 1)
+ typeError(_return, "Different number of arguments in return statement than in returns declaration.");
+ else
+ {
+ // this could later be changed such that the paramaters type is an anonymous struct type,
+ // but for now, we only allow one return parameter
+ TypePointer const& expected = type(*params->parameters().front());
+ if (!type(*_return.expression())->isImplicitlyConvertibleTo(*expected))
+ typeError(
+ *_return.expression(),
+ "Return argument type " +
+ type(*_return.expression())->toString() +
+ " is not implicitly convertible to expected type (type of first return variable) " +
+ expected->toString() +
+ "."
+ );
+ }
+}
+
+void TypeChecker::endVisit(ExpressionStatement const& _statement)
+{
+ if (type(_statement.expression())->category() == Type::Category::IntegerConstant)
+ if (!dynamic_pointer_cast<IntegerConstantType const>(type(_statement.expression()))->integerType())
+ typeError(_statement.expression(), "Invalid integer constant.");
+}
+
+bool TypeChecker::visit(Assignment const& _assignment)
+{
+ requireLValue(_assignment.leftHandSide());
+ TypePointer t = type(_assignment.leftHandSide());
+ _assignment.annotation().type = t;
+ if (t->category() == Type::Category::Mapping)
+ {
+ typeError(_assignment, "Mappings cannot be assigned to.");
+ _assignment.rightHandSide().accept(*this);
+ }
+ else if (_assignment.assignmentOperator() == Token::Assign)
+ expectType(_assignment.rightHandSide(), *t);
+ else
+ {
+ // compound assignment
+ _assignment.rightHandSide().accept(*this);
+ TypePointer resultType = t->binaryOperatorResult(
+ Token::AssignmentToBinaryOp(_assignment.assignmentOperator()),
+ type(_assignment.rightHandSide())
+ );
+ if (!resultType || *resultType != *t)
+ typeError(
+ _assignment,
+ "Operator " +
+ string(Token::toString(_assignment.assignmentOperator())) +
+ " not compatible with types " +
+ t->toString() +
+ " and " +
+ type(_assignment.rightHandSide())->toString()
+ );
+ }
+ return false;
+}
+
+bool TypeChecker::visit(UnaryOperation const& _operation)
+{
+ // Inc, Dec, Add, Sub, Not, BitNot, Delete
+ Token::Value op = _operation.getOperator();
+ if (op == Token::Value::Inc || op == Token::Value::Dec || op == Token::Value::Delete)
+ requireLValue(_operation.subExpression());
+ else
+ _operation.subExpression().accept(*this);
+ TypePointer const& subExprType = type(_operation.subExpression());
+ TypePointer t = type(_operation.subExpression())->unaryOperatorResult(op);
+ if (!t)
+ {
+ typeError(
+ _operation,
+ "Unary operator " +
+ string(Token::toString(op)) +
+ " cannot be applied to type " +
+ subExprType->toString()
+ );
+ t = subExprType;
+ }
+ _operation.annotation().type = t;
+ return false;
+}
+
+void TypeChecker::endVisit(BinaryOperation const& _operation)
+{
+ TypePointer const& leftType = type(_operation.leftExpression());
+ TypePointer const& rightType = type(_operation.rightExpression());
+ TypePointer commonType = leftType->binaryOperatorResult(_operation.getOperator(), rightType);
+ if (!commonType)
+ {
+ typeError(
+ _operation,
+ "Operator " +
+ string(Token::toString(_operation.getOperator())) +
+ " not compatible with types " +
+ leftType->toString() +
+ " and " +
+ rightType->toString()
+ );
+ commonType = leftType;
+ }
+ _operation.annotation().commonType = commonType;
+ _operation.annotation().type =
+ Token::isCompareOp(_operation.getOperator()) ?
+ make_shared<BoolType>() :
+ commonType;
+}
+
+bool TypeChecker::visit(FunctionCall const& _functionCall)
+{
+ bool isPositionalCall = _functionCall.names().empty();
+ vector<ASTPointer<Expression const>> arguments = _functionCall.arguments();
+ vector<ASTPointer<ASTString>> const& argumentNames = _functionCall.names();
+
+ // We need to check arguments' type first as they will be needed for overload resolution.
+ shared_ptr<TypePointers> argumentTypes;
+ if (isPositionalCall)
+ argumentTypes = make_shared<TypePointers>();
+ for (ASTPointer<Expression const> const& argument: arguments)
+ {
+ argument->accept(*this);
+ // only store them for positional calls
+ if (isPositionalCall)
+ argumentTypes->push_back(type(*argument));
+ }
+ if (isPositionalCall)
+ _functionCall.expression().annotation().argumentTypes = move(argumentTypes);
+
+ _functionCall.expression().accept(*this);
+ TypePointer expressionType = type(_functionCall.expression());
+
+ if (auto const* typeType = dynamic_cast<TypeType const*>(expressionType.get()))
+ {
+ _functionCall.annotation().isStructConstructorCall = (typeType->actualType()->category() == Type::Category::Struct);
+ _functionCall.annotation().isTypeConversion = !_functionCall.annotation().isStructConstructorCall;
+ }
+ else
+ _functionCall.annotation().isStructConstructorCall = _functionCall.annotation().isTypeConversion = false;
+
+ if (_functionCall.annotation().isTypeConversion)
+ {
+ TypeType const& t = dynamic_cast<TypeType const&>(*expressionType);
+ TypePointer resultType = t.actualType();
+ if (arguments.size() != 1)
+ typeError(_functionCall, "Exactly one argument expected for explicit type conversion.");
+ else if (!isPositionalCall)
+ typeError(_functionCall, "Type conversion cannot allow named arguments.");
+ else
+ {
+ TypePointer const& argType = type(*arguments.front());
+ if (auto argRefType = dynamic_cast<ReferenceType const*>(argType.get()))
+ // do not change the data location when converting
+ // (data location cannot yet be specified for type conversions)
+ resultType = ReferenceType::copyForLocationIfReference(argRefType->location(), resultType);
+ if (!argType->isExplicitlyConvertibleTo(*resultType))
+ typeError(_functionCall, "Explicit type conversion not allowed.");
+ }
+ _functionCall.annotation().type = resultType;
+
+ return false;
+ }
+
+ // Actual function call or struct constructor call.
+
+ FunctionTypePointer functionType;
+
+ /// For error message: Struct members that were removed during conversion to memory.
+ set<string> membersRemovedForStructConstructor;
+ if (_functionCall.annotation().isStructConstructorCall)
+ {
+ TypeType const& t = dynamic_cast<TypeType const&>(*expressionType);
+ auto const& structType = dynamic_cast<StructType const&>(*t.actualType());
+ functionType = structType.constructorType();
+ membersRemovedForStructConstructor = structType.membersMissingInMemory();
+ }
+ else
+ functionType = dynamic_pointer_cast<FunctionType const>(expressionType);
+
+ if (!functionType)
+ {
+ typeError(_functionCall, "Type is not callable");
+ _functionCall.annotation().type = make_shared<VoidType>();
+ return false;
+ }
+ else
+ {
+ // @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 anonymous
+ // structs and tuples
+ if (functionType->returnParameterTypes().empty())
+ _functionCall.annotation().type = make_shared<VoidType>();
+ else
+ _functionCall.annotation().type = functionType->returnParameterTypes().front();
+ }
+
+ //@todo would be nice to create a struct type from the arguments
+ // and then ask if that is implicitly convertible to the struct represented by the
+ // function parameters
+ TypePointers const& parameterTypes = functionType->parameterTypes();
+ if (!functionType->takesArbitraryParameters() && parameterTypes.size() != arguments.size())
+ {
+ string msg =
+ "Wrong argument count for function call: " +
+ toString(arguments.size()) +
+ " arguments given but expected " +
+ toString(parameterTypes.size()) +
+ ".";
+ // Extend error message in case we try to construct a struct with mapping member.
+ if (_functionCall.annotation().isStructConstructorCall && !membersRemovedForStructConstructor.empty())
+ {
+ msg += " Members that have to be skipped in memory:";
+ for (auto const& member: membersRemovedForStructConstructor)
+ msg += " " + member;
+ }
+ typeError(_functionCall, msg);
+ }
+ else if (isPositionalCall)
+ {
+ // call by positional arguments
+ for (size_t i = 0; i < arguments.size(); ++i)
+ if (
+ !functionType->takesArbitraryParameters() &&
+ !type(*arguments[i])->isImplicitlyConvertibleTo(*parameterTypes[i])
+ )
+ typeError(
+ *arguments[i],
+ "Invalid type for argument in function call. "
+ "Invalid implicit conversion from " +
+ type(*arguments[i])->toString() +
+ " to " +
+ parameterTypes[i]->toString() +
+ " requested."
+ );
+ }
+ else
+ {
+ // call by named arguments
+ auto const& parameterNames = functionType->parameterNames();
+ if (functionType->takesArbitraryParameters())
+ typeError(
+ _functionCall,
+ "Named arguments cannnot be used for functions that take arbitrary parameters."
+ );
+ else if (parameterNames.size() > argumentNames.size())
+ typeError(_functionCall, "Some argument names are missing.");
+ else if (parameterNames.size() < argumentNames.size())
+ typeError(_functionCall, "Too many arguments.");
+ else
+ {
+ // check duplicate names
+ bool duplication = false;
+ for (size_t i = 0; i < argumentNames.size(); i++)
+ for (size_t j = i + 1; j < argumentNames.size(); j++)
+ if (*argumentNames[i] == *argumentNames[j])
+ {
+ duplication = true;
+ typeError(*arguments[i], "Duplicate named argument.");
+ }
+
+ // check actual types
+ if (!duplication)
+ for (size_t i = 0; i < argumentNames.size(); i++)
+ {
+ bool found = false;
+ for (size_t j = 0; j < parameterNames.size(); j++)
+ if (parameterNames[j] == *argumentNames[i])
+ {
+ found = true;
+ // check type convertible
+ if (!type(*arguments[i])->isImplicitlyConvertibleTo(*parameterTypes[j]))
+ typeError(
+ *arguments[i],
+ "Invalid type for argument in function call. "
+ "Invalid implicit conversion from " +
+ type(*arguments[i])->toString() +
+ " to " +
+ parameterTypes[i]->toString() +
+ " requested."
+ );
+ break;
+ }
+
+ if (!found)
+ typeError(
+ _functionCall,
+ "Named argument does not match function declaration."
+ );
+ }
+ }
+ }
+
+ return false;
+}
+
+void TypeChecker::endVisit(NewExpression const& _newExpression)
+{
+ auto contract = dynamic_cast<ContractDefinition const*>(&dereference(_newExpression.contractName()));
+
+ if (!contract)
+ fatalTypeError(_newExpression, "Identifier is not a contract.");
+ if (!contract->annotation().isFullyImplemented)
+ typeError(_newExpression, "Trying to create an instance of an abstract contract.");
+
+ auto scopeContract = _newExpression.contractName().annotation().contractScope;
+ auto const& bases = contract->annotation().linearizedBaseContracts;
+ solAssert(!bases.empty(), "Linearized base contracts not yet available.");
+ if (find(bases.begin(), bases.end(), scopeContract) != bases.end())
+ typeError(
+ _newExpression,
+ "Circular reference for contract creation: cannot create instance of derived or same contract."
+ );
+
+ auto contractType = make_shared<ContractType>(*contract);
+ TypePointers const& parameterTypes = contractType->constructorType()->parameterTypes();
+ _newExpression.annotation().type = make_shared<FunctionType>(
+ parameterTypes,
+ TypePointers{contractType},
+ strings(),
+ strings(),
+ FunctionType::Location::Creation
+ );
+}
+
+bool TypeChecker::visit(MemberAccess const& _memberAccess)
+{
+ _memberAccess.expression().accept(*this);
+ TypePointer exprType = type(_memberAccess.expression());
+ ASTString const& memberName = _memberAccess.memberName();
+
+ // Retrieve the types of the arguments if this is used to call a function.
+ auto const& argumentTypes = _memberAccess.annotation().argumentTypes;
+ MemberList::MemberMap possibleMembers = exprType->members().membersByName(memberName);
+ if (possibleMembers.size() > 1 && argumentTypes)
+ {
+ // do overload resolution
+ for (auto it = possibleMembers.begin(); it != possibleMembers.end();)
+ if (
+ it->type->category() == Type::Category::Function &&
+ !dynamic_cast<FunctionType const&>(*it->type).canTakeArguments(*argumentTypes)
+ )
+ it = possibleMembers.erase(it);
+ else
+ ++it;
+ }
+ if (possibleMembers.size() == 0)
+ {
+ auto storageType = ReferenceType::copyForLocationIfReference(
+ DataLocation::Storage,
+ exprType
+ );
+ if (!storageType->members().membersByName(memberName).empty())
+ fatalTypeError(
+ _memberAccess,
+ "Member \"" + memberName + "\" is not available in " +
+ exprType->toString() +
+ " outside of storage."
+ );
+ fatalTypeError(
+ _memberAccess,
+ "Member \"" + memberName + "\" not found or not visible "
+ "after argument-dependent lookup in " + exprType->toString()
+ );
+ }
+ else if (possibleMembers.size() > 1)
+ fatalTypeError(
+ _memberAccess,
+ "Member \"" + memberName + "\" not unique "
+ "after argument-dependent lookup in " + exprType->toString()
+ );
+
+ auto& annotation = _memberAccess.annotation();
+ annotation.referencedDeclaration = possibleMembers.front().declaration;
+ annotation.type = possibleMembers.front().type;
+ if (exprType->category() == Type::Category::Struct)
+ annotation.isLValue = true;
+ else if (exprType->category() == Type::Category::Array)
+ {
+ auto const& arrayType(dynamic_cast<ArrayType const&>(*exprType));
+ annotation.isLValue = (
+ memberName == "length" &&
+ arrayType.location() == DataLocation::Storage &&
+ arrayType.isDynamicallySized()
+ );
+ }
+
+ return false;
+}
+
+bool TypeChecker::visit(IndexAccess const& _access)
+{
+ _access.baseExpression().accept(*this);
+ TypePointer baseType = type(_access.baseExpression());
+ TypePointer resultType;
+ bool isLValue = false;
+ Expression const* index = _access.indexExpression();
+ switch (baseType->category())
+ {
+ case Type::Category::Array:
+ {
+ ArrayType const& actualType = dynamic_cast<ArrayType const&>(*baseType);
+ if (!index)
+ typeError(_access, "Index expression cannot be omitted.");
+ else if (actualType.isString())
+ {
+ typeError(_access, "Index access for string is not possible.");
+ index->accept(*this);
+ }
+ else
+ {
+ expectType(*index, IntegerType(256));
+ if (auto integerType = dynamic_cast<IntegerConstantType const*>(type(*index).get()))
+ if (!actualType.isDynamicallySized() && actualType.length() <= integerType->literalValue(nullptr))
+ typeError(_access, "Out of bounds array access.");
+ }
+ resultType = actualType.baseType();
+ isLValue = actualType.location() != DataLocation::CallData;
+ break;
+ }
+ case Type::Category::Mapping:
+ {
+ MappingType const& actualType = dynamic_cast<MappingType const&>(*baseType);
+ if (!index)
+ typeError(_access, "Index expression cannot be omitted.");
+ else
+ expectType(*index, *actualType.keyType());
+ resultType = actualType.valueType();
+ isLValue = true;
+ break;
+ }
+ case Type::Category::TypeType:
+ {
+ TypeType const& typeType = dynamic_cast<TypeType const&>(*baseType);
+ if (!index)
+ resultType = make_shared<TypeType>(make_shared<ArrayType>(DataLocation::Memory, typeType.actualType()));
+ else
+ {
+ index->accept(*this);
+ if (auto length = dynamic_cast<IntegerConstantType const*>(type(*index).get()))
+ resultType = make_shared<TypeType>(make_shared<ArrayType>(
+ DataLocation::Memory,
+ typeType.actualType(),
+ length->literalValue(nullptr)
+ ));
+ else
+ typeError(*index, "Integer constant expected.");
+ }
+ break;
+ }
+ default:
+ fatalTypeError(
+ _access.baseExpression(),
+ "Indexed expression has to be a type, mapping or array (is " + baseType->toString() + ")"
+ );
+ }
+ _access.annotation().type = move(resultType);
+ _access.annotation().isLValue = isLValue;
+
+ return false;
+}
+
+bool TypeChecker::visit(Identifier const& _identifier)
+{
+ IdentifierAnnotation& annotation = _identifier.annotation();
+ if (!annotation.referencedDeclaration)
+ {
+ if (!annotation.argumentTypes)
+ fatalTypeError(_identifier, "Unable to determine overloaded type.");
+ if (annotation.overloadedDeclarations.empty())
+ fatalTypeError(_identifier, "No candidates for overload resolution found.");
+ else if (annotation.overloadedDeclarations.size() == 1)
+ annotation.referencedDeclaration = *annotation.overloadedDeclarations.begin();
+ else
+ {
+ vector<Declaration const*> candidates;
+
+ for (Declaration const* declaration: annotation.overloadedDeclarations)
+ {
+ TypePointer function = declaration->type(_identifier.annotation().contractScope);
+ solAssert(!!function, "Requested type not present.");
+ auto const* functionType = dynamic_cast<FunctionType const*>(function.get());
+ if (functionType && functionType->canTakeArguments(*annotation.argumentTypes))
+ candidates.push_back(declaration);
+ }
+ if (candidates.empty())
+ fatalTypeError(_identifier, "No matching declaration found after argument-dependent lookup.");
+ else if (candidates.size() == 1)
+ annotation.referencedDeclaration = candidates.front();
+ else
+ fatalTypeError(_identifier, "No unique declaration found after argument-dependent lookup.");
+ }
+ }
+ solAssert(
+ !!annotation.referencedDeclaration,
+ "Referenced declaration is null after overload resolution."
+ );
+ annotation.isLValue = annotation.referencedDeclaration->isLValue();
+ annotation.type = annotation.referencedDeclaration->type(_identifier.annotation().contractScope);
+ if (!annotation.type)
+ fatalTypeError(_identifier, "Declaration referenced before type could be determined.");
+ return false;
+}
+
+void TypeChecker::endVisit(ElementaryTypeNameExpression const& _expr)
+{
+ _expr.annotation().type = make_shared<TypeType>(Type::fromElementaryTypeName(_expr.typeToken()));
+}
+
+void TypeChecker::endVisit(Literal const& _literal)
+{
+ _literal.annotation().type = Type::forLiteral(_literal);
+ if (!_literal.annotation().type)
+ fatalTypeError(_literal, "Invalid literal value.");
+}
+
+Declaration const& TypeChecker::dereference(Identifier const& _identifier)
+{
+ solAssert(!!_identifier.annotation().referencedDeclaration, "Declaration not stored.");
+ return *_identifier.annotation().referencedDeclaration;
+}
+
+void TypeChecker::expectType(Expression const& _expression, Type const& _expectedType)
+{
+ _expression.accept(*this);
+
+ if (!type(_expression)->isImplicitlyConvertibleTo(_expectedType))
+ typeError(
+ _expression,
+ "Type " +
+ type(_expression)->toString() +
+ " is not implicitly convertible to expected type " +
+ _expectedType.toString() +
+ "."
+ );
+}
+
+void TypeChecker::requireLValue(Expression const& _expression)
+{
+ _expression.accept(*this);
+ if (!_expression.annotation().isLValue)
+ typeError(_expression, "Expression has to be an lvalue.");
+ _expression.annotation().lValueRequested = true;
+}
+
+void TypeChecker::typeError(ASTNode const& _node, string const& _description)
+{
+ auto err = make_shared<TypeError>();
+ *err <<
+ errinfo_sourceLocation(_node.location()) <<
+ errinfo_comment(_description);
+
+ m_errors.push_back(err);
+}
+
+void TypeChecker::fatalTypeError(ASTNode const& _node, string const& _description)
+{
+ typeError(_node, _description);
+ BOOST_THROW_EXCEPTION(FatalError());
+}
diff --git a/libsolidity/TypeChecker.h b/libsolidity/TypeChecker.h
new file mode 100644
index 00000000..cc539e22
--- /dev/null
+++ b/libsolidity/TypeChecker.h
@@ -0,0 +1,114 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ cpp-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @author Christian <c@ethdev.com>
+ * @date 2015
+ * Type analyzer and checker.
+ */
+
+#pragma once
+
+#include <libsolidity/TypeChecker.h>
+#include <libsolidity/Types.h>
+#include <libsolidity/ASTAnnotations.h>
+#include <libsolidity/ASTForward.h>
+#include <libsolidity/ASTVisitor.h>
+
+namespace dev
+{
+namespace solidity
+{
+
+
+/**
+ * The module that performs type analysis on the AST, checks the applicability of operations on
+ * those types and stores errors for invalid operations.
+ * Provides a way to retrieve the type of an AST node.
+ */
+class TypeChecker: private ASTConstVisitor
+{
+public:
+ /// Performs type checking on the given contract and all of its sub-nodes.
+ /// @returns true iff all checks passed.
+ bool checkTypeRequirements(ContractDefinition const& _contract);
+
+ /// @returns the list of errors found during type checking.
+ std::vector<std::shared_ptr<Error const>> const& errors() const { return m_errors; }
+
+ /// @returns the type of an expression and asserts that it is present.
+ TypePointer const& type(Expression const& _expression) const;
+ /// @returns the type of the given variable and throws if the type is not present
+ /// (this can happen for variables with non-explicit types before their types are resolved)
+ TypePointer const& type(VariableDeclaration const& _variable) const;
+
+ /// Adds a new error to the list of errors.
+ void typeError(ASTNode const& _node, std::string const& _description);
+ /// Adds a new error to the list of errors and throws to abort type checking.
+ void fatalTypeError(ASTNode const& _node, std::string const& _description);
+
+private:
+ virtual bool visit(ContractDefinition const& _contract) override;
+ /// Checks that two functions defined in this contract with the same name have different
+ /// arguments and that there is at most one constructor.
+ void checkContractDuplicateFunctions(ContractDefinition const& _contract);
+ void checkContractIllegalOverrides(ContractDefinition const& _contract);
+ void checkContractAbstractFunctions(ContractDefinition const& _contract);
+ void checkContractAbstractConstructors(ContractDefinition const& _contract);
+ /// Checks that different functions with external visibility end up having different
+ /// external argument types (i.e. different signature).
+ void checkContractExternalTypeClashes(ContractDefinition const& _contract);
+ /// Checks that all requirements for a library are fulfilled if this is a library.
+ void checkLibraryRequirements(ContractDefinition const& _contract);
+
+ virtual void endVisit(InheritanceSpecifier const& _inheritance) override;
+ virtual bool visit(StructDefinition const& _struct) override;
+ virtual bool visit(FunctionDefinition const& _function) override;
+ virtual bool visit(VariableDeclaration const& _variable) override;
+ /// We need to do this manually because we want to pass the bases of the current contract in
+ /// case this is a base constructor call.
+ void visitManually(ModifierInvocation const& _modifier, std::vector<ContractDefinition const*> const& _bases);
+ virtual bool visit(EventDefinition const& _eventDef) override;
+ virtual bool visit(IfStatement const& _ifStatement) override;
+ virtual bool visit(WhileStatement const& _whileStatement) override;
+ virtual bool visit(ForStatement const& _forStatement) override;
+ virtual void endVisit(Return const& _return) override;
+ virtual void endVisit(ExpressionStatement const& _statement) override;
+ virtual bool visit(Assignment const& _assignment) override;
+ virtual void endVisit(BinaryOperation const& _operation) override;
+ virtual bool visit(UnaryOperation const& _operation) override;
+ virtual bool visit(FunctionCall const& _functionCall) override;
+ virtual void endVisit(NewExpression const& _newExpression) override;
+ virtual bool visit(MemberAccess const& _memberAccess) override;
+ virtual bool visit(IndexAccess const& _indexAccess) override;
+ virtual bool visit(Identifier const& _identifier) override;
+ virtual void endVisit(ElementaryTypeNameExpression const& _expr) override;
+ virtual void endVisit(Literal const& _literal) override;
+
+ /// @returns the referenced declaration and throws on error.
+ Declaration const& dereference(Identifier const& _identifier);
+
+ /// Runs type checks on @a _expression to infer its type and then checks that it is implicitly
+ /// convertible to @a _expectedType.
+ void expectType(Expression const& _expression, Type const& _expectedType);
+ /// Runs type checks on @a _expression to infer its type and then checks that it is an LValue.
+ void requireLValue(Expression const& _expression);
+
+ std::vector<std::shared_ptr<Error const>> m_errors;
+};
+
+}
+}
diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp
index beb5becd..68e8e91d 100644
--- a/libsolidity/Types.cpp
+++ b/libsolidity/Types.cpp
@@ -157,55 +157,6 @@ TypePointer Type::fromElementaryTypeName(string const& _name)
return fromElementaryTypeName(Token::fromIdentifierOrKeyword(_name));
}
-TypePointer Type::fromUserDefinedTypeName(UserDefinedTypeName const& _typeName)
-{
- Declaration const* declaration = _typeName.referencedDeclaration();
- if (StructDefinition const* structDef = dynamic_cast<StructDefinition const*>(declaration))
- return make_shared<StructType>(*structDef);
- else if (EnumDefinition const* enumDef = dynamic_cast<EnumDefinition const*>(declaration))
- return make_shared<EnumType>(*enumDef);
- else if (FunctionDefinition const* function = dynamic_cast<FunctionDefinition const*>(declaration))
- return make_shared<FunctionType>(*function);
- else if (ContractDefinition const* contract = dynamic_cast<ContractDefinition const*>(declaration))
- return make_shared<ContractType>(*contract);
- return TypePointer();
-}
-
-TypePointer Type::fromMapping(ElementaryTypeName& _keyType, TypeName& _valueType)
-{
- TypePointer keyType = _keyType.toType();
- if (!keyType)
- BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Error resolving type name."));
- TypePointer valueType = _valueType.toType();
- if (!valueType)
- BOOST_THROW_EXCEPTION(_valueType.createTypeError("Invalid type name."));
- // Convert value type to storage reference.
- valueType = ReferenceType::copyForLocationIfReference(DataLocation::Storage, valueType);
- // Convert key type to memory.
- keyType = ReferenceType::copyForLocationIfReference(DataLocation::Memory, keyType);
- return make_shared<MappingType>(keyType, valueType);
-}
-
-TypePointer Type::fromArrayTypeName(TypeName& _baseTypeName, Expression* _length)
-{
- TypePointer baseType = _baseTypeName.toType();
- if (!baseType)
- BOOST_THROW_EXCEPTION(_baseTypeName.createTypeError("Invalid type name."));
- if (baseType->storageBytes() == 0)
- BOOST_THROW_EXCEPTION(_baseTypeName.createTypeError("Illegal base type of storage size zero for array."));
- if (_length)
- {
- if (!_length->type())
- _length->checkTypeRequirements(nullptr);
- auto const* length = dynamic_cast<IntegerConstantType const*>(_length->type().get());
- if (!length)
- BOOST_THROW_EXCEPTION(_length->createTypeError("Invalid array length."));
- return make_shared<ArrayType>(DataLocation::Storage, baseType, length->literalValue(nullptr));
- }
- else
- return make_shared<ArrayType>(DataLocation::Storage, baseType);
-}
-
TypePointer Type::forLiteral(Literal const& _literal)
{
switch (_literal.token())
@@ -686,7 +637,7 @@ bool ContractType::isImplicitlyConvertibleTo(Type const& _convertTo) const
return dynamic_cast<IntegerType const&>(_convertTo).isAddress();
if (_convertTo.category() == Category::Contract)
{
- auto const& bases = contractDefinition().linearizedBaseContracts();
+ auto const& bases = contractDefinition().annotation().linearizedBaseContracts;
if (m_super && bases.size() <= 1)
return false;
return find(m_super ? ++bases.begin() : bases.begin(), bases.end(),
@@ -944,7 +895,7 @@ MemberList const& ContractType::members() const
if (m_super)
{
// add the most derived of all functions which are visible in derived contracts
- for (ContractDefinition const* base: m_contract.linearizedBaseContracts())
+ for (ContractDefinition const* base: m_contract.annotation().linearizedBaseContracts)
for (ASTPointer<FunctionDefinition> const& function: base->definedFunctions())
{
if (!function->isVisibleInDerivedContracts())
@@ -998,13 +949,13 @@ shared_ptr<FunctionType const> const& ContractType::constructorType() const
vector<tuple<VariableDeclaration const*, u256, unsigned>> ContractType::stateVariables() const
{
vector<VariableDeclaration const*> variables;
- for (ContractDefinition const* contract: boost::adaptors::reverse(m_contract.linearizedBaseContracts()))
+ for (ContractDefinition const* contract: boost::adaptors::reverse(m_contract.annotation().linearizedBaseContracts))
for (ASTPointer<VariableDeclaration> const& variable: contract->stateVariables())
if (!variable->isConstant())
variables.push_back(variable.get());
TypePointers types;
for (auto variable: variables)
- types.push_back(variable->type());
+ types.push_back(variable->annotation().type);
StorageOffsets offsets;
offsets.computeOffsets(types);
@@ -1082,7 +1033,7 @@ MemberList const& StructType::members() const
MemberList::MemberMap members;
for (ASTPointer<VariableDeclaration> const& variable: m_struct.members())
{
- TypePointer type = variable->type();
+ TypePointer type = variable->annotation().type;
// Skip all mapping members if we are not in storage.
if (location() != DataLocation::Storage && !type->canLiveOutsideStorage())
continue;
@@ -1147,7 +1098,7 @@ set<string> StructType::membersMissingInMemory() const
{
set<string> missing;
for (ASTPointer<VariableDeclaration> const& variable: m_struct.members())
- if (!variable->type()->canLiveOutsideStorage())
+ if (!variable->annotation().type->canLiveOutsideStorage())
missing.insert(variable->name());
return missing;
}
@@ -1211,14 +1162,14 @@ FunctionType::FunctionType(FunctionDefinition const& _function, bool _isInternal
for (ASTPointer<VariableDeclaration> const& var: _function.parameters())
{
paramNames.push_back(var->name());
- params.push_back(var->type());
+ params.push_back(var->annotation().type);
}
retParams.reserve(_function.returnParameters().size());
retParamNames.reserve(_function.returnParameters().size());
for (ASTPointer<VariableDeclaration> const& var: _function.returnParameters())
{
retParamNames.push_back(var->name());
- retParams.push_back(var->type());
+ retParams.push_back(var->annotation().type);
}
swap(params, m_parameterTypes);
swap(paramNames, m_parameterNames);
@@ -1231,7 +1182,7 @@ FunctionType::FunctionType(VariableDeclaration const& _varDecl):
{
TypePointers paramTypes;
vector<string> paramNames;
- auto returnType = _varDecl.type();
+ auto returnType = _varDecl.annotation().type;
while (true)
{
@@ -1293,7 +1244,7 @@ FunctionType::FunctionType(const EventDefinition& _event):
for (ASTPointer<VariableDeclaration> const& var: _event.parameters())
{
paramNames.push_back(var->name());
- params.push_back(var->type());
+ params.push_back(var->annotation().type);
}
swap(params, m_parameterTypes);
swap(paramNames, m_parameterNames);
@@ -1662,7 +1613,7 @@ MemberList const& TypeType::members() const
));
else if (m_currentContract != nullptr)
{
- vector<ContractDefinition const*> currentBases = m_currentContract->linearizedBaseContracts();
+ auto const& currentBases = m_currentContract->annotation().linearizedBaseContracts;
if (find(currentBases.begin(), currentBases.end(), &contract) != currentBases.end())
// We are accessing the type of a base contract, so add all public and protected
// members. Note that this does not add inherited functions on purpose.
@@ -1687,7 +1638,7 @@ ModifierType::ModifierType(const ModifierDefinition& _modifier)
TypePointers params;
params.reserve(_modifier.parameters().size());
for (ASTPointer<VariableDeclaration> const& var: _modifier.parameters())
- params.push_back(var->type());
+ params.push_back(var->annotation().type);
swap(params, m_parameterTypes);
}
diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp
index cfc8a5e0..587dcded 100644
--- a/solc/CommandLineInterface.cpp
+++ b/solc/CommandLineInterface.cpp
@@ -490,7 +490,12 @@ bool CommandLineInterface::processInput()
// TODO: Perhaps we should not compile unless requested
bool optimize = m_args.count("optimize") > 0;
unsigned runs = m_args["optimize-runs"].as<unsigned>();
- m_compiler->compile(optimize, runs);
+ if (!m_compiler->compile(optimize, runs))
+ {
+ for (auto const& error: m_compiler->errors())
+ SourceReferenceFormatter::printExceptionInformation(cerr, *error, "Error", *m_compiler);
+ return false;
+ }
m_compiler->link(m_libraries);
}
catch (ParserError const& _exception)
diff --git a/solc/jsonCompiler.cpp b/solc/jsonCompiler.cpp
index d265ed9c..ba3e6912 100644
--- a/solc/jsonCompiler.cpp
+++ b/solc/jsonCompiler.cpp
@@ -46,10 +46,7 @@ string formatError(Exception const& _exception, string const& _name, CompilerSta
{
ostringstream errorOutput;
SourceReferenceFormatter::printExceptionInformation(errorOutput, _exception, _name, _compiler);
-
- Json::Value output(Json::objectValue);
- output["error"] = errorOutput.str();
- return Json::FastWriter().write(output);
+ return errorOutput.str();
}
Json::Value functionHashes(ContractDefinition const& _contract)
@@ -123,43 +120,52 @@ string compile(string _input, bool _optimize)
sources[""] = _input;
Json::Value output(Json::objectValue);
+ Json::Value errors(Json::arrayValue);
CompilerStack compiler;
try
{
- compiler.compile(_input, _optimize);
+ if (!compiler.compile(_input, _optimize))
+ {
+ for (auto const& error: compiler.errors())
+ errors.append(formatError(*error, "Error", compiler));
+ }
}
catch (ParserError const& exception)
{
- return formatError(exception, "Parser error", compiler);
+ errors.append(formatError(exception, "Parser error", compiler));
}
catch (DeclarationError const& exception)
{
- return formatError(exception, "Declaration error", compiler);
+ errors.append(formatError(exception, "Declaration error", compiler));
}
catch (TypeError const& exception)
{
- return formatError(exception, "Type error", compiler);
+ errors.append(formatError(exception, "Type error", compiler));
}
catch (CompilerError const& exception)
{
- return formatError(exception, "Compiler error", compiler);
+ errors.append(formatError(exception, "Compiler error", compiler));
}
catch (InternalCompilerError const& exception)
{
- return formatError(exception, "Internal compiler error", compiler);
+ errors.append(formatError(exception, "Internal compiler error", compiler));
}
catch (DocstringParsingError const& exception)
{
- return formatError(exception, "Documentation parsing error", compiler);
+ errors.append(formatError(exception, "Documentation parsing error", compiler));
}
catch (Exception const& exception)
{
- output["error"] = "Exception during compilation: " + boost::diagnostic_information(exception);
- return Json::FastWriter().write(output);
+ errors.append("Exception during compilation: " + boost::diagnostic_information(exception));
}
catch (...)
{
- output["error"] = "Unknown exception during compilation.";
+ errors.append("Unknown exception during compilation.");
+ }
+
+ if (errors.size() > 0)
+ {
+ output["errors"] = errors;
return Json::FastWriter().write(output);
}
diff --git a/test/libsolidity/Assembly.cpp b/test/libsolidity/Assembly.cpp
index 5bd6fed3..b4678611 100644
--- a/test/libsolidity/Assembly.cpp
+++ b/test/libsolidity/Assembly.cpp
@@ -31,6 +31,7 @@
#include <libsolidity/NameAndTypeResolver.h>
#include <libsolidity/Compiler.h>
#include <libsolidity/AST.h>
+#include <libsolidity/TypeChecker.h>
using namespace std;
using namespace dev::eth;
@@ -60,7 +61,8 @@ eth::AssemblyItems compileContract(const string& _sourceCode)
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
{
- BOOST_REQUIRE_NO_THROW(resolver.checkTypeRequirements(*contract));
+ TypeChecker checker;
+ BOOST_REQUIRE_NO_THROW(checker.checkTypeRequirements(*contract));
}
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index 98da1e27..8026f216 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -1999,7 +1999,7 @@ BOOST_AUTO_TEST_CASE(single_copy_with_multiple_inheritance)
BOOST_CHECK(callContractFunction("getViaB()") == encodeArgs(23));
}
-BOOST_AUTO_TEST_CASE(explicit_base_cass)
+BOOST_AUTO_TEST_CASE(explicit_base_class)
{
char const* sourceCode = R"(
contract BaseBase { function g() returns (uint r) { return 1; } }
diff --git a/test/libsolidity/SolidityExpressionCompiler.cpp b/test/libsolidity/SolidityExpressionCompiler.cpp
index 747668b0..545775ee 100644
--- a/test/libsolidity/SolidityExpressionCompiler.cpp
+++ b/test/libsolidity/SolidityExpressionCompiler.cpp
@@ -29,6 +29,7 @@
#include <libsolidity/CompilerContext.h>
#include <libsolidity/ExpressionCompiler.h>
#include <libsolidity/AST.h>
+#include <libsolidity/TypeChecker.h>
#include "../TestHelper.h"
using namespace std;
@@ -117,7 +118,8 @@ bytes compileFirstExpression(const string& _sourceCode, vector<vector<string>> _
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
{
- ETH_TEST_REQUIRE_NO_THROW(resolver.checkTypeRequirements(*contract), "Checking type Requirements failed");
+ TypeChecker typeChecker;
+ BOOST_REQUIRE(typeChecker.checkTypeRequirements(*contract));
}
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp
index 2a720494..8346b8ca 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -29,6 +29,7 @@
#include <libsolidity/NameAndTypeResolver.h>
#include <libsolidity/Exceptions.h>
#include <libsolidity/GlobalContext.h>
+#include <libsolidity/TypeChecker.h>
#include "../TestHelper.h"
using namespace std;
@@ -43,33 +44,69 @@ namespace test
namespace
{
-ASTPointer<SourceUnit> parseTextAndResolveNames(std::string const& _source)
+pair<ASTPointer<SourceUnit>, shared_ptr<Exception const>>
+parseAnalyseAndReturnError(string const& _source)
{
Parser parser;
- ASTPointer<SourceUnit> sourceUnit = parser.parse(std::make_shared<Scanner>(CharStream(_source)));
- NameAndTypeResolver resolver({});
- resolver.registerDeclarations(*sourceUnit);
- std::shared_ptr<GlobalContext> globalContext = make_shared<GlobalContext>();
-
- for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
- if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
- {
- globalContext->setCurrentContract(*contract);
- resolver.updateDeclaration(*globalContext->currentThis());
- resolver.updateDeclaration(*globalContext->currentSuper());
- resolver.resolveNamesAndTypes(*contract);
- }
- for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
- if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
- {
- globalContext->setCurrentContract(*contract);
- resolver.updateDeclaration(*globalContext->currentThis());
- resolver.checkTypeRequirements(*contract);
- }
+ ASTPointer<SourceUnit> sourceUnit;
+ shared_ptr<Exception const> err;
+ // catch exceptions for a transition period
+ try
+ {
+ sourceUnit = parser.parse(std::make_shared<Scanner>(CharStream(_source)));
+ NameAndTypeResolver resolver({});
+ resolver.registerDeclarations(*sourceUnit);
+ std::shared_ptr<GlobalContext> globalContext = make_shared<GlobalContext>();
+
+ for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
+ if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
+ {
+ globalContext->setCurrentContract(*contract);
+ resolver.updateDeclaration(*globalContext->currentThis());
+ resolver.updateDeclaration(*globalContext->currentSuper());
+ resolver.resolveNamesAndTypes(*contract);
+ }
+ for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
+ if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
+ {
+ globalContext->setCurrentContract(*contract);
+ resolver.updateDeclaration(*globalContext->currentThis());
+ TypeChecker typeChecker;
+ if (!typeChecker.checkTypeRequirements(*contract))
+ {
+ err = typeChecker.errors().front();
+ break;
+ }
+ }
+ }
+ catch (ParserError const& _exception)
+ {
+ return make_pair(sourceUnit, make_shared<ParserError>(_exception));
+ }
+ catch (DeclarationError const& _exception)
+ {
+ return make_pair(sourceUnit, make_shared<DeclarationError>(_exception));
+ }
+ catch (TypeError const& _exception)
+ {
+ return make_pair(sourceUnit, make_shared<TypeError>(_exception));
+ }
+ return make_pair(sourceUnit, err);
+}
- return sourceUnit;
+ASTPointer<SourceUnit> parseAndAnalyse(string const& _source)
+{
+ auto sourceAndError = parseAnalyseAndReturnError(_source);
+ BOOST_REQUIRE(!sourceAndError.second);
+ return sourceAndError.first;
}
+shared_ptr<Exception const> parseAndAnalyseReturnError(std::string const& _source)
+{
+ auto sourceAndError = parseAnalyseAndReturnError(_source);
+ BOOST_REQUIRE(!!sourceAndError.second);
+ return sourceAndError.second;
+}
static ContractDefinition const* retrieveContract(ASTPointer<SourceUnit> _source, unsigned index)
{
@@ -79,7 +116,7 @@ static ContractDefinition const* retrieveContract(ASTPointer<SourceUnit> _source
if ((contract = dynamic_cast<ContractDefinition*>(node.get())) && counter == index)
return contract;
- return NULL;
+ return nullptr;
}
static FunctionTypePointer const& retrieveFunctionBySignature(ContractDefinition const* _contract,
@@ -91,6 +128,10 @@ static FunctionTypePointer const& retrieveFunctionBySignature(ContractDefinition
}
+#define SOLIDITY_CHECK_ERROR_TYPE(_statement, _ErrorType) \
+ BOOST_CHECK(!!dynamic_cast<_ErrorType const*>(_statement.get()))
+
+
BOOST_AUTO_TEST_SUITE(SolidityNameAndTypeResolution)
BOOST_AUTO_TEST_CASE(smoke_test)
@@ -99,7 +140,7 @@ BOOST_AUTO_TEST_CASE(smoke_test)
" uint256 stateVariable1;\n"
" function fun(uint256 arg1) { uint256 y; }"
"}\n";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(double_stateVariable_declaration)
@@ -108,7 +149,7 @@ BOOST_AUTO_TEST_CASE(double_stateVariable_declaration)
" uint256 variable;\n"
" uint128 variable;\n"
"}\n";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), DeclarationError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), DeclarationError);
}
BOOST_AUTO_TEST_CASE(double_function_declaration)
@@ -117,7 +158,7 @@ BOOST_AUTO_TEST_CASE(double_function_declaration)
" function fun() { var x; }\n"
" function fun() { var x; }\n"
"}\n";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), DeclarationError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), DeclarationError);
}
BOOST_AUTO_TEST_CASE(double_variable_declaration)
@@ -125,7 +166,7 @@ BOOST_AUTO_TEST_CASE(double_variable_declaration)
char const* text = "contract test {\n"
" function f() { uint256 x; if (true) { uint256 x; } }\n"
"}\n";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), DeclarationError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), DeclarationError);
}
BOOST_AUTO_TEST_CASE(name_shadowing)
@@ -134,7 +175,7 @@ BOOST_AUTO_TEST_CASE(name_shadowing)
" uint256 variable;\n"
" function f() { uint32 variable ; }"
"}\n";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(name_references)
@@ -143,7 +184,7 @@ BOOST_AUTO_TEST_CASE(name_references)
" uint256 variable;\n"
" function f(uint256 arg) returns (uint out) { f(variable); test; out; }"
"}\n";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(undeclared_name)
@@ -152,7 +193,7 @@ BOOST_AUTO_TEST_CASE(undeclared_name)
" uint256 variable;\n"
" function f(uint256 arg) { f(notfound); }"
"}\n";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), DeclarationError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), DeclarationError);
}
BOOST_AUTO_TEST_CASE(reference_to_later_declaration)
@@ -161,7 +202,7 @@ BOOST_AUTO_TEST_CASE(reference_to_later_declaration)
" function g() { f(); }"
" function f() { }"
"}\n";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(struct_definition_directly_recursive)
@@ -172,7 +213,7 @@ BOOST_AUTO_TEST_CASE(struct_definition_directly_recursive)
" MyStructName x;\n"
" }\n"
"}\n";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), ParserError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(struct_definition_indirectly_recursive)
@@ -187,7 +228,7 @@ BOOST_AUTO_TEST_CASE(struct_definition_indirectly_recursive)
" MyStructName1 x;\n"
" }\n"
"}\n";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), ParserError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(struct_definition_not_really_recursive)
@@ -198,7 +239,7 @@ BOOST_AUTO_TEST_CASE(struct_definition_not_really_recursive)
struct s2 { s1 x; s1 y; }
}
)";
- BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
+ BOOST_CHECK_NO_THROW(parseAndAnalyse(text));
}
BOOST_AUTO_TEST_CASE(struct_definition_recursion_via_mapping)
@@ -210,7 +251,7 @@ BOOST_AUTO_TEST_CASE(struct_definition_recursion_via_mapping)
" mapping(uint => MyStructName1) x;\n"
" }\n"
"}\n";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(type_inference_smoke_test)
@@ -218,7 +259,7 @@ BOOST_AUTO_TEST_CASE(type_inference_smoke_test)
char const* text = "contract test {\n"
" function f(uint256 arg1, uint32 arg2) returns (bool ret) { var x = arg1 + arg2 == 8; ret = x; }"
"}\n";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(type_checking_return)
@@ -226,7 +267,7 @@ BOOST_AUTO_TEST_CASE(type_checking_return)
char const* text = "contract test {\n"
" function f() returns (bool r) { return 1 >= 2; }"
"}\n";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(type_checking_return_wrong_number)
@@ -234,7 +275,7 @@ BOOST_AUTO_TEST_CASE(type_checking_return_wrong_number)
char const* text = "contract test {\n"
" function f() returns (bool r1, bool r2) { return 1 >= 2; }"
"}\n";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(type_checking_return_wrong_type)
@@ -242,7 +283,7 @@ BOOST_AUTO_TEST_CASE(type_checking_return_wrong_type)
char const* text = "contract test {\n"
" function f() returns (uint256 r) { return 1 >= 2; }"
"}\n";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(type_checking_function_call)
@@ -251,7 +292,7 @@ BOOST_AUTO_TEST_CASE(type_checking_function_call)
" function f() returns (bool r) { return g(12, true) == 3; }\n"
" function g(uint256 a, bool b) returns (uint256 r) { }\n"
"}\n";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(type_conversion_for_comparison)
@@ -259,7 +300,7 @@ BOOST_AUTO_TEST_CASE(type_conversion_for_comparison)
char const* text = "contract test {\n"
" function f() { uint32(2) == int64(2); }"
"}\n";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(type_conversion_for_comparison_invalid)
@@ -267,7 +308,7 @@ BOOST_AUTO_TEST_CASE(type_conversion_for_comparison_invalid)
char const* text = "contract test {\n"
" function f() { int32(2) == uint64(2); }"
"}\n";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(type_inference_explicit_conversion)
@@ -275,7 +316,7 @@ BOOST_AUTO_TEST_CASE(type_inference_explicit_conversion)
char const* text = "contract test {\n"
" function f() returns (int256 r) { var x = int256(uint32(2)); return x; }"
"}\n";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(large_string_literal)
@@ -283,7 +324,7 @@ BOOST_AUTO_TEST_CASE(large_string_literal)
char const* text = "contract test {\n"
" function f() { var x = \"123456789012345678901234567890123\"; }"
"}\n";
- BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
+ BOOST_CHECK_NO_THROW(parseAndAnalyse(text));
}
BOOST_AUTO_TEST_CASE(balance)
@@ -293,7 +334,7 @@ BOOST_AUTO_TEST_CASE(balance)
" uint256 x = address(0).balance;\n"
" }\n"
"}\n";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(balance_invalid)
@@ -303,7 +344,7 @@ BOOST_AUTO_TEST_CASE(balance_invalid)
" address(0).balance = 7;\n"
" }\n"
"}\n";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(assignment_to_mapping)
@@ -318,7 +359,7 @@ BOOST_AUTO_TEST_CASE(assignment_to_mapping)
" data.map = a;\n"
" }\n"
"}\n";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(assignment_to_struct)
@@ -333,7 +374,7 @@ BOOST_AUTO_TEST_CASE(assignment_to_struct)
" data = a;\n"
" }\n"
"}\n";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(returns_in_constructor)
@@ -342,7 +383,7 @@ BOOST_AUTO_TEST_CASE(returns_in_constructor)
" function test() returns (uint a) {\n"
" }\n"
"}\n";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(forward_function_reference)
@@ -357,7 +398,7 @@ BOOST_AUTO_TEST_CASE(forward_function_reference)
" if (First(2).fun() == true) return 1;\n"
" }\n"
"}\n";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(comparison_bitop_precedence)
@@ -367,7 +408,7 @@ BOOST_AUTO_TEST_CASE(comparison_bitop_precedence)
" return 1 & 2 == 8 & 9 && 1 ^ 2 < 4 | 6;\n"
" }\n"
"}\n";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(function_no_implementation)
@@ -376,12 +417,12 @@ BOOST_AUTO_TEST_CASE(function_no_implementation)
char const* text = "contract test {\n"
" function functionName(bytes32 input) returns (bytes32 out);\n"
"}\n";
- ETH_TEST_REQUIRE_NO_THROW(sourceUnit = parseTextAndResolveNames(text), "Parsing and name Resolving failed");
+ ETH_TEST_REQUIRE_NO_THROW(sourceUnit = parseAndAnalyse(text), "Parsing and name Resolving failed");
std::vector<ASTPointer<ASTNode>> nodes = sourceUnit->nodes();
ContractDefinition* contract = dynamic_cast<ContractDefinition*>(nodes[0].get());
BOOST_CHECK(contract);
- BOOST_CHECK(!contract->isFullyImplemented());
- BOOST_CHECK(!contract->definedFunctions()[0]->isFullyImplemented());
+ BOOST_CHECK(!contract->annotation().isFullyImplemented);
+ BOOST_CHECK(!contract->definedFunctions()[0]->isImplemented());
}
BOOST_AUTO_TEST_CASE(abstract_contract)
@@ -391,16 +432,16 @@ BOOST_AUTO_TEST_CASE(abstract_contract)
contract base { function foo(); }
contract derived is base { function foo() {} }
)";
- ETH_TEST_REQUIRE_NO_THROW(sourceUnit = parseTextAndResolveNames(text), "Parsing and name Resolving failed");
+ ETH_TEST_REQUIRE_NO_THROW(sourceUnit = parseAndAnalyse(text), "Parsing and name Resolving failed");
std::vector<ASTPointer<ASTNode>> nodes = sourceUnit->nodes();
ContractDefinition* base = dynamic_cast<ContractDefinition*>(nodes[0].get());
ContractDefinition* derived = dynamic_cast<ContractDefinition*>(nodes[1].get());
BOOST_CHECK(base);
- BOOST_CHECK(!base->isFullyImplemented());
- BOOST_CHECK(!base->definedFunctions()[0]->isFullyImplemented());
+ BOOST_CHECK(!base->annotation().isFullyImplemented);
+ BOOST_CHECK(!base->definedFunctions()[0]->isImplemented());
BOOST_CHECK(derived);
- BOOST_CHECK(derived->isFullyImplemented());
- BOOST_CHECK(derived->definedFunctions()[0]->isFullyImplemented());
+ BOOST_CHECK(derived->annotation().isFullyImplemented);
+ BOOST_CHECK(derived->definedFunctions()[0]->isImplemented());
}
BOOST_AUTO_TEST_CASE(abstract_contract_with_overload)
@@ -410,14 +451,14 @@ BOOST_AUTO_TEST_CASE(abstract_contract_with_overload)
contract base { function foo(bool); }
contract derived is base { function foo(uint) {} }
)";
- ETH_TEST_REQUIRE_NO_THROW(sourceUnit = parseTextAndResolveNames(text), "Parsing and name Resolving failed");
+ ETH_TEST_REQUIRE_NO_THROW(sourceUnit = parseAndAnalyse(text), "Parsing and name Resolving failed");
std::vector<ASTPointer<ASTNode>> nodes = sourceUnit->nodes();
ContractDefinition* base = dynamic_cast<ContractDefinition*>(nodes[0].get());
ContractDefinition* derived = dynamic_cast<ContractDefinition*>(nodes[1].get());
BOOST_REQUIRE(base);
- BOOST_CHECK(!base->isFullyImplemented());
+ BOOST_CHECK(!base->annotation().isFullyImplemented);
BOOST_REQUIRE(derived);
- BOOST_CHECK(!derived->isFullyImplemented());
+ BOOST_CHECK(!derived->annotation().isFullyImplemented);
}
BOOST_AUTO_TEST_CASE(create_abstract_contract)
@@ -430,7 +471,7 @@ BOOST_AUTO_TEST_CASE(create_abstract_contract)
function foo() { b = new base();}
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(abstract_contract_constructor_args_optional)
@@ -444,7 +485,7 @@ BOOST_AUTO_TEST_CASE(abstract_contract_constructor_args_optional)
function foo() {}
}
)";
- ETH_TEST_REQUIRE_NO_THROW(parseTextAndResolveNames(text), "Parsing and name resolving failed");
+ ETH_TEST_REQUIRE_NO_THROW(parseAndAnalyse(text), "Parsing and name resolving failed");
}
BOOST_AUTO_TEST_CASE(abstract_contract_constructor_args_not_provided)
@@ -458,12 +499,12 @@ BOOST_AUTO_TEST_CASE(abstract_contract_constructor_args_not_provided)
function foo() {}
}
)";
- ETH_TEST_REQUIRE_NO_THROW(sourceUnit = parseTextAndResolveNames(text), "Parsing and name resolving failed");
+ ETH_TEST_REQUIRE_NO_THROW(sourceUnit = parseAndAnalyse(text), "Parsing and name resolving failed");
std::vector<ASTPointer<ASTNode>> nodes = sourceUnit->nodes();
BOOST_CHECK_EQUAL(nodes.size(), 3);
ContractDefinition* derived = dynamic_cast<ContractDefinition*>(nodes[2].get());
BOOST_CHECK(derived);
- BOOST_CHECK(!derived->isFullyImplemented());
+ BOOST_CHECK(!derived->annotation().isFullyImplemented);
}
BOOST_AUTO_TEST_CASE(redeclare_implemented_abstract_function_as_abstract)
@@ -474,7 +515,7 @@ BOOST_AUTO_TEST_CASE(redeclare_implemented_abstract_function_as_abstract)
contract derived is base { function foo() {} }
contract wrong is derived { function foo(); }
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(function_canonical_signature)
@@ -485,7 +526,7 @@ BOOST_AUTO_TEST_CASE(function_canonical_signature)
" ret = arg1 + arg2;\n"
" }\n"
"}\n";
- ETH_TEST_REQUIRE_NO_THROW(sourceUnit = parseTextAndResolveNames(text), "Parsing and name Resolving failed");
+ ETH_TEST_REQUIRE_NO_THROW(sourceUnit = parseAndAnalyse(text), "Parsing and name Resolving failed");
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
{
@@ -502,7 +543,7 @@ BOOST_AUTO_TEST_CASE(function_canonical_signature_type_aliases)
" ret = 5;\n"
" }\n"
"}\n";
- ETH_TEST_REQUIRE_NO_THROW(sourceUnit = parseTextAndResolveNames(text), "Parsing and name Resolving failed");
+ ETH_TEST_REQUIRE_NO_THROW(sourceUnit = parseAndAnalyse(text), "Parsing and name Resolving failed");
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
{
@@ -525,7 +566,7 @@ BOOST_AUTO_TEST_CASE(function_external_types)
ret = 5;
}
})";
- ETH_TEST_REQUIRE_NO_THROW(sourceUnit = parseTextAndResolveNames(text), "Parsing and name Resolving failed");
+ ETH_TEST_REQUIRE_NO_THROW(sourceUnit = parseAndAnalyse(text), "Parsing and name Resolving failed");
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
{
@@ -547,7 +588,7 @@ BOOST_AUTO_TEST_CASE(enum_external_type)
ret = 5;
}
})";
- ETH_TEST_REQUIRE_NO_THROW(sourceUnit = parseTextAndResolveNames(text), "Parsing and name Resolving failed");
+ ETH_TEST_REQUIRE_NO_THROW(sourceUnit = parseAndAnalyse(text), "Parsing and name Resolving failed");
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
{
@@ -569,7 +610,7 @@ BOOST_AUTO_TEST_CASE(function_external_call_allowed_conversion)
}
function g (C c) external {}
})";
- BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
+ BOOST_CHECK_NO_THROW(parseAndAnalyse(text));
}
BOOST_AUTO_TEST_CASE(function_external_call_not_allowed_conversion)
@@ -583,7 +624,7 @@ BOOST_AUTO_TEST_CASE(function_external_call_not_allowed_conversion)
}
function g (C c) external {}
})";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(function_internal_allowed_conversion)
@@ -599,7 +640,7 @@ BOOST_AUTO_TEST_CASE(function_internal_allowed_conversion)
g(a);
}
})";
- BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
+ BOOST_CHECK_NO_THROW(parseAndAnalyse(text));
}
BOOST_AUTO_TEST_CASE(function_internal_not_allowed_conversion)
@@ -615,7 +656,7 @@ BOOST_AUTO_TEST_CASE(function_internal_not_allowed_conversion)
g(a);
}
})";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(hash_collision_in_interface)
@@ -626,7 +667,7 @@ BOOST_AUTO_TEST_CASE(hash_collision_in_interface)
" function tgeo() {\n"
" }\n"
"}\n";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(inheritance_basic)
@@ -638,7 +679,7 @@ BOOST_AUTO_TEST_CASE(inheritance_basic)
function f() { baseMember = 7; }
}
)";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(inheritance_diamond_basic)
@@ -651,7 +692,7 @@ BOOST_AUTO_TEST_CASE(inheritance_diamond_basic)
function g() { f(); rootFunction(); }
}
)";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(cyclic_inheritance)
@@ -660,7 +701,7 @@ BOOST_AUTO_TEST_CASE(cyclic_inheritance)
contract A is B { }
contract B is A { }
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(legal_override_direct)
@@ -669,7 +710,7 @@ BOOST_AUTO_TEST_CASE(legal_override_direct)
contract B { function f() {} }
contract C is B { function f(uint i) {} }
)";
- BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
+ BOOST_CHECK_NO_THROW(parseAndAnalyse(text));
}
BOOST_AUTO_TEST_CASE(legal_override_indirect)
@@ -679,7 +720,7 @@ BOOST_AUTO_TEST_CASE(legal_override_indirect)
contract B { function f() {} }
contract C is A, B { }
)";
- BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
+ BOOST_CHECK_NO_THROW(parseAndAnalyse(text));
}
BOOST_AUTO_TEST_CASE(illegal_override_visibility)
@@ -688,7 +729,7 @@ BOOST_AUTO_TEST_CASE(illegal_override_visibility)
contract B { function f() internal {} }
contract C is B { function f() public {} }
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(illegal_override_constness)
@@ -697,7 +738,7 @@ BOOST_AUTO_TEST_CASE(illegal_override_constness)
contract B { function f() constant {} }
contract C is B { function f() {} }
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(complex_inheritance)
@@ -707,7 +748,7 @@ BOOST_AUTO_TEST_CASE(complex_inheritance)
contract B { function f() {} function g() returns (uint8 r) {} }
contract C is A, B { }
)";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(constructor_visibility)
@@ -717,7 +758,7 @@ BOOST_AUTO_TEST_CASE(constructor_visibility)
contract A { function A() { } }
contract B is A { function f() { A x = A(0); } }
)";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(overriding_constructor)
@@ -727,7 +768,7 @@ BOOST_AUTO_TEST_CASE(overriding_constructor)
contract A { function A() { } }
contract B is A { function A() returns (uint8 r) {} }
)";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(missing_base_constructor_arguments)
@@ -736,7 +777,7 @@ BOOST_AUTO_TEST_CASE(missing_base_constructor_arguments)
contract A { function A(uint a) { } }
contract B is A { }
)";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(base_constructor_arguments_override)
@@ -745,7 +786,7 @@ BOOST_AUTO_TEST_CASE(base_constructor_arguments_override)
contract A { function A(uint a) { } }
contract B is A { }
)";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(implicit_derived_to_base_conversion)
@@ -756,7 +797,7 @@ BOOST_AUTO_TEST_CASE(implicit_derived_to_base_conversion)
function f() { A a = B(1); }
}
)";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(implicit_base_to_derived_conversion)
@@ -767,7 +808,7 @@ BOOST_AUTO_TEST_CASE(implicit_base_to_derived_conversion)
function f() { B b = A(1); }
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(function_modifier_invocation)
@@ -779,7 +820,7 @@ BOOST_AUTO_TEST_CASE(function_modifier_invocation)
modifier mod2(bytes7 a) { while (a == "1234567") _ }
}
)";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(invalid_function_modifier_type)
@@ -790,7 +831,7 @@ BOOST_AUTO_TEST_CASE(invalid_function_modifier_type)
modifier mod1(uint a) { if (a > 0) _ }
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(function_modifier_invocation_parameters)
@@ -802,7 +843,7 @@ BOOST_AUTO_TEST_CASE(function_modifier_invocation_parameters)
modifier mod2(bytes7 a) { while (a == "1234567") _ }
}
)";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(function_modifier_invocation_local_variables)
@@ -813,7 +854,7 @@ BOOST_AUTO_TEST_CASE(function_modifier_invocation_local_variables)
modifier mod(uint a) { if (a > 0) _ }
}
)";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(legal_modifier_override)
@@ -822,7 +863,7 @@ BOOST_AUTO_TEST_CASE(legal_modifier_override)
contract A { modifier mod(uint a) {} }
contract B is A { modifier mod(uint a) {} }
)";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(illegal_modifier_override)
@@ -831,7 +872,7 @@ BOOST_AUTO_TEST_CASE(illegal_modifier_override)
contract A { modifier mod(uint a) {} }
contract B is A { modifier mod(uint8 a) {} }
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(modifier_overrides_function)
@@ -840,7 +881,7 @@ BOOST_AUTO_TEST_CASE(modifier_overrides_function)
contract A { modifier mod(uint a) {} }
contract B is A { function mod(uint a) {} }
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(function_overrides_modifier)
@@ -849,7 +890,7 @@ BOOST_AUTO_TEST_CASE(function_overrides_modifier)
contract A { function mod(uint a) {} }
contract B is A { modifier mod(uint a) {} }
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(modifier_returns_value)
@@ -860,7 +901,7 @@ BOOST_AUTO_TEST_CASE(modifier_returns_value)
modifier mod(uint a) { return 7; }
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(state_variable_accessors)
@@ -876,7 +917,7 @@ BOOST_AUTO_TEST_CASE(state_variable_accessors)
ASTPointer<SourceUnit> source;
ContractDefinition const* contract;
- ETH_TEST_CHECK_NO_THROW(source = parseTextAndResolveNames(text), "Parsing and Resolving names failed");
+ ETH_TEST_CHECK_NO_THROW(source = parseAndAnalyse(text), "Parsing and Resolving names failed");
BOOST_REQUIRE((contract = retrieveContract(source, 0)) != nullptr);
FunctionTypePointer function = retrieveFunctionBySignature(contract, "foo()");
BOOST_REQUIRE(function && function->hasDeclaration());
@@ -911,7 +952,7 @@ BOOST_AUTO_TEST_CASE(function_clash_with_state_variable_accessor)
"uint256 foo;\n"
" function foo() {}\n"
"}\n";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), DeclarationError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), DeclarationError);
}
BOOST_AUTO_TEST_CASE(private_state_variable)
@@ -926,7 +967,7 @@ BOOST_AUTO_TEST_CASE(private_state_variable)
ASTPointer<SourceUnit> source;
ContractDefinition const* contract;
- ETH_TEST_CHECK_NO_THROW(source = parseTextAndResolveNames(text), "Parsing and Resolving names failed");
+ ETH_TEST_CHECK_NO_THROW(source = parseAndAnalyse(text), "Parsing and Resolving names failed");
BOOST_CHECK((contract = retrieveContract(source, 0)) != nullptr);
FunctionTypePointer function;
function = retrieveFunctionBySignature(contract, "foo()");
@@ -944,7 +985,7 @@ BOOST_AUTO_TEST_CASE(base_class_state_variable_accessor)
"contract Child is Parent{\n"
" function foo() returns (uint256) { return Parent.m_aMember; }\n"
"}\n";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(base_class_state_variable_internal_member)
@@ -955,7 +996,7 @@ BOOST_AUTO_TEST_CASE(base_class_state_variable_internal_member)
"contract Child is Parent{\n"
" function foo() returns (uint256) { return Parent.m_aMember; }\n"
"}\n";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(state_variable_member_of_wrong_class1)
@@ -969,7 +1010,7 @@ BOOST_AUTO_TEST_CASE(state_variable_member_of_wrong_class1)
"contract Child is Parent2{\n"
" function foo() returns (uint256) { return Parent2.m_aMember1; }\n"
"}\n";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(state_variable_member_of_wrong_class2)
@@ -984,7 +1025,7 @@ BOOST_AUTO_TEST_CASE(state_variable_member_of_wrong_class2)
" function foo() returns (uint256) { return Child.m_aMember2; }\n"
" uint256 public m_aMember3;\n"
"}\n";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(fallback_function)
@@ -995,7 +1036,7 @@ BOOST_AUTO_TEST_CASE(fallback_function)
function() { x = 2; }
}
)";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(fallback_function_with_arguments)
@@ -1006,7 +1047,7 @@ BOOST_AUTO_TEST_CASE(fallback_function_with_arguments)
function(uint a) { x = 2; }
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(fallback_function_twice)
@@ -1018,7 +1059,7 @@ BOOST_AUTO_TEST_CASE(fallback_function_twice)
function() { x = 3; }
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), DeclarationError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), DeclarationError);
}
BOOST_AUTO_TEST_CASE(fallback_function_inheritance)
@@ -1032,7 +1073,7 @@ BOOST_AUTO_TEST_CASE(fallback_function_inheritance)
function() { x = 2; }
}
)";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(event)
@@ -1042,7 +1083,7 @@ BOOST_AUTO_TEST_CASE(event)
event e(uint indexed a, bytes3 indexed s, bool indexed b);
function f() { e(2, "abc", true); }
})";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(event_too_many_indexed)
@@ -1051,7 +1092,7 @@ BOOST_AUTO_TEST_CASE(event_too_many_indexed)
contract c {
event e(uint indexed a, bytes3 indexed b, bool indexed c, uint indexed d);
})";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(event_call)
@@ -1061,7 +1102,7 @@ BOOST_AUTO_TEST_CASE(event_call)
event e(uint a, bytes3 indexed s, bool indexed b);
function f() { e(2, "abc", true); }
})";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(event_inheritance)
@@ -1073,7 +1114,7 @@ BOOST_AUTO_TEST_CASE(event_inheritance)
contract c is base {
function f() { e(2, "abc", true); }
})";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(multiple_events_argument_clash)
@@ -1083,7 +1124,7 @@ BOOST_AUTO_TEST_CASE(multiple_events_argument_clash)
event e1(uint a, uint e1, uint e2);
event e2(uint a, uint e1, uint e2);
})";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(access_to_default_function_visibility)
@@ -1095,7 +1136,7 @@ BOOST_AUTO_TEST_CASE(access_to_default_function_visibility)
contract d {
function g() { c(0).f(); }
})";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(access_to_internal_function)
@@ -1107,7 +1148,7 @@ BOOST_AUTO_TEST_CASE(access_to_internal_function)
contract d {
function g() { c(0).f(); }
})";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(access_to_default_state_variable_visibility)
@@ -1119,7 +1160,7 @@ BOOST_AUTO_TEST_CASE(access_to_default_state_variable_visibility)
contract d {
function g() { c(0).a(); }
})";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(access_to_internal_state_variable)
@@ -1131,7 +1172,7 @@ BOOST_AUTO_TEST_CASE(access_to_internal_state_variable)
contract d {
function g() { c(0).a(); }
})";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(error_count_in_named_args)
@@ -1140,7 +1181,7 @@ BOOST_AUTO_TEST_CASE(error_count_in_named_args)
" function a(uint a, uint b) returns (uint r) { r = a + b; }\n"
" function b() returns (uint r) { r = a({a: 1}); }\n"
"}\n";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(empty_in_named_args)
@@ -1149,7 +1190,7 @@ BOOST_AUTO_TEST_CASE(empty_in_named_args)
" function a(uint a, uint b) returns (uint r) { r = a + b; }\n"
" function b() returns (uint r) { r = a({}); }\n"
"}\n";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(duplicate_parameter_names_in_named_args)
@@ -1158,7 +1199,7 @@ BOOST_AUTO_TEST_CASE(duplicate_parameter_names_in_named_args)
" function a(uint a, uint b) returns (uint r) { r = a + b; }\n"
" function b() returns (uint r) { r = a({a: 1, a: 2}); }\n"
"}\n";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(invalid_parameter_names_in_named_args)
@@ -1167,7 +1208,7 @@ BOOST_AUTO_TEST_CASE(invalid_parameter_names_in_named_args)
" function a(uint a, uint b) returns (uint r) { r = a + b; }\n"
" function b() returns (uint r) { r = a({a: 1, c: 2}); }\n"
"}\n";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(empty_name_input_parameter)
@@ -1177,7 +1218,7 @@ BOOST_AUTO_TEST_CASE(empty_name_input_parameter)
function f(uint){
}
})";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(empty_name_return_parameter)
@@ -1187,7 +1228,7 @@ BOOST_AUTO_TEST_CASE(empty_name_return_parameter)
function f() returns(bool){
}
})";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(empty_name_input_parameter_with_named_one)
@@ -1198,7 +1239,7 @@ BOOST_AUTO_TEST_CASE(empty_name_input_parameter_with_named_one)
return k;
}
})";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(empty_name_return_parameter_with_named_one)
@@ -1209,13 +1250,13 @@ BOOST_AUTO_TEST_CASE(empty_name_return_parameter_with_named_one)
return 5;
}
})";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(disallow_declaration_of_void_type)
{
char const* sourceCode = "contract c { function f() { var x = f(); } }";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(overflow_caused_by_ether_units)
@@ -1228,7 +1269,7 @@ BOOST_AUTO_TEST_CASE(overflow_caused_by_ether_units)
}
uint256 a;
})";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(sourceCodeFine),
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(sourceCodeFine),
"Parsing and Resolving names failed");
char const* sourceCode = R"(
contract c {
@@ -1238,7 +1279,7 @@ BOOST_AUTO_TEST_CASE(overflow_caused_by_ether_units)
}
uint256 a;
})";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(exp_operator_negative_exponent)
@@ -1247,7 +1288,7 @@ BOOST_AUTO_TEST_CASE(exp_operator_negative_exponent)
contract test {
function f() returns(uint d) { return 2 ** -3; }
})";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(exp_operator_exponent_too_big)
@@ -1256,7 +1297,7 @@ BOOST_AUTO_TEST_CASE(exp_operator_exponent_too_big)
contract test {
function f() returns(uint d) { return 2 ** 10000000000; }
})";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(enum_member_access)
@@ -1271,7 +1312,7 @@ BOOST_AUTO_TEST_CASE(enum_member_access)
ActionChoices choices;
}
)";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(enum_invalid_member_access)
@@ -1286,7 +1327,7 @@ BOOST_AUTO_TEST_CASE(enum_invalid_member_access)
ActionChoices choices;
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(enum_explicit_conversion_is_okay)
@@ -1303,7 +1344,7 @@ BOOST_AUTO_TEST_CASE(enum_explicit_conversion_is_okay)
uint64 b;
}
)";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(int_to_enum_explicit_conversion_is_okay)
@@ -1320,7 +1361,7 @@ BOOST_AUTO_TEST_CASE(int_to_enum_explicit_conversion_is_okay)
ActionChoices b;
}
)";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(enum_implicit_conversion_is_not_okay)
@@ -1337,7 +1378,7 @@ BOOST_AUTO_TEST_CASE(enum_implicit_conversion_is_not_okay)
uint64 b;
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(enum_duplicate_values)
@@ -1347,7 +1388,7 @@ BOOST_AUTO_TEST_CASE(enum_duplicate_values)
enum ActionChoices { GoLeft, GoRight, GoLeft, Sit }
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), DeclarationError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), DeclarationError);
}
BOOST_AUTO_TEST_CASE(private_visibility)
@@ -1360,7 +1401,7 @@ BOOST_AUTO_TEST_CASE(private_visibility)
function g() { f(); }
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), DeclarationError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), DeclarationError);
}
BOOST_AUTO_TEST_CASE(private_visibility_via_explicit_base_access)
@@ -1373,7 +1414,7 @@ BOOST_AUTO_TEST_CASE(private_visibility_via_explicit_base_access)
function g() { base.f(); }
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(external_visibility)
@@ -1384,7 +1425,7 @@ BOOST_AUTO_TEST_CASE(external_visibility)
function g() { f(); }
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), DeclarationError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), DeclarationError);
}
BOOST_AUTO_TEST_CASE(external_base_visibility)
@@ -1397,7 +1438,7 @@ BOOST_AUTO_TEST_CASE(external_base_visibility)
function g() { base.f(); }
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(external_argument_assign)
@@ -1407,7 +1448,7 @@ BOOST_AUTO_TEST_CASE(external_argument_assign)
function f(uint a) external { a = 1; }
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(external_argument_increment)
@@ -1417,7 +1458,7 @@ BOOST_AUTO_TEST_CASE(external_argument_increment)
function f(uint a) external { a++; }
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(external_argument_delete)
@@ -1427,7 +1468,7 @@ BOOST_AUTO_TEST_CASE(external_argument_delete)
function f(uint a) external { delete a; }
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(test_for_bug_override_function_with_bytearray_type)
@@ -1440,7 +1481,7 @@ BOOST_AUTO_TEST_CASE(test_for_bug_override_function_with_bytearray_type)
function f(bytes _a) external returns (uint256 r) {r = 42;}
}
)";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(sourceCode), "Parsing and Name Resolving failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(sourceCode), "Parsing and Name Resolving failed");
}
BOOST_AUTO_TEST_CASE(array_with_nonconstant_length)
@@ -1449,7 +1490,7 @@ BOOST_AUTO_TEST_CASE(array_with_nonconstant_length)
contract c {
function f(uint a) { uint8[a] x; }
})";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(array_copy_with_different_types1)
@@ -1460,7 +1501,7 @@ BOOST_AUTO_TEST_CASE(array_copy_with_different_types1)
uint[] b;
function f() { b = a; }
})";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(array_copy_with_different_types2)
@@ -1471,7 +1512,7 @@ BOOST_AUTO_TEST_CASE(array_copy_with_different_types2)
uint8[] b;
function f() { b = a; }
})";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(array_copy_with_different_types_conversion_possible)
@@ -1482,7 +1523,7 @@ BOOST_AUTO_TEST_CASE(array_copy_with_different_types_conversion_possible)
uint8[] b;
function f() { a = b; }
})";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(array_copy_with_different_types_static_dynamic)
@@ -1493,7 +1534,7 @@ BOOST_AUTO_TEST_CASE(array_copy_with_different_types_static_dynamic)
uint8[80] b;
function f() { a = b; }
})";
- ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
+ ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(array_copy_with_different_types_dynamic_static)
@@ -1504,7 +1545,7 @@ BOOST_AUTO_TEST_CASE(array_copy_with_different_types_dynamic_static)
uint[80] b;
function f() { b = a; }
})";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(storage_variable_initialization_with_incorrect_type_int)
@@ -1513,7 +1554,7 @@ BOOST_AUTO_TEST_CASE(storage_variable_initialization_with_incorrect_type_int)
contract c {
uint8 a = 1000;
})";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(storage_variable_initialization_with_incorrect_type_string)
@@ -1522,7 +1563,7 @@ BOOST_AUTO_TEST_CASE(storage_variable_initialization_with_incorrect_type_string)
contract c {
uint a = "abc";
})";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(test_fromElementaryTypeName)
@@ -1637,7 +1678,7 @@ BOOST_AUTO_TEST_CASE(test_byte_is_alias_of_byte1)
bytes arr;
function f() { byte a = arr[0];}
})";
- ETH_TEST_REQUIRE_NO_THROW(parseTextAndResolveNames(text), "Type resolving failed");
+ ETH_TEST_REQUIRE_NO_THROW(parseAndAnalyse(text), "Type resolving failed");
}
BOOST_AUTO_TEST_CASE(assigning_value_to_const_variable)
@@ -1647,7 +1688,7 @@ BOOST_AUTO_TEST_CASE(assigning_value_to_const_variable)
function changeIt() { x = 9; }
uint constant x = 56;
})";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(complex_const_variable)
@@ -1657,7 +1698,7 @@ BOOST_AUTO_TEST_CASE(complex_const_variable)
contract Foo {
mapping(uint => bool) constant mapVar;
})";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(uninitialized_const_variable)
@@ -1666,7 +1707,7 @@ BOOST_AUTO_TEST_CASE(uninitialized_const_variable)
contract Foo {
uint constant y;
})";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(local_const_variable)
@@ -1679,7 +1720,7 @@ BOOST_AUTO_TEST_CASE(local_const_variable)
return local;
}
})";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), ParserError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), ParserError);
}
BOOST_AUTO_TEST_CASE(overloaded_function_cannot_resolve)
@@ -1691,7 +1732,7 @@ BOOST_AUTO_TEST_CASE(overloaded_function_cannot_resolve)
function g() returns(uint) { return f(3, 5); }
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(ambiguous_overloaded_function)
@@ -1704,7 +1745,7 @@ BOOST_AUTO_TEST_CASE(ambiguous_overloaded_function)
function g() returns(uint) { return f(1); }
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(assignment_of_nonoverloaded_function)
@@ -1715,7 +1756,7 @@ BOOST_AUTO_TEST_CASE(assignment_of_nonoverloaded_function)
function g() returns(uint) { var x = f; return x(7); }
}
)";
- ETH_TEST_REQUIRE_NO_THROW(parseTextAndResolveNames(sourceCode), "Type resolving failed");
+ ETH_TEST_REQUIRE_NO_THROW(parseAndAnalyse(sourceCode), "Type resolving failed");
}
BOOST_AUTO_TEST_CASE(assignment_of_overloaded_function)
@@ -1727,7 +1768,7 @@ BOOST_AUTO_TEST_CASE(assignment_of_overloaded_function)
function g() returns(uint) { var x = f; return x(7); }
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(external_types_clash)
@@ -1741,7 +1782,7 @@ BOOST_AUTO_TEST_CASE(external_types_clash)
function f(uint8 a) { }
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(override_changes_return_types)
@@ -1754,7 +1795,7 @@ BOOST_AUTO_TEST_CASE(override_changes_return_types)
function f(uint a) returns (uint8) { }
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(multiple_constructors)
@@ -1765,7 +1806,7 @@ BOOST_AUTO_TEST_CASE(multiple_constructors)
function test() {}
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), DeclarationError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), DeclarationError);
}
BOOST_AUTO_TEST_CASE(equal_overload)
@@ -1776,7 +1817,7 @@ BOOST_AUTO_TEST_CASE(equal_overload)
function test(uint a) external {}
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), DeclarationError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), DeclarationError);
}
BOOST_AUTO_TEST_CASE(uninitialized_var)
@@ -1786,7 +1827,7 @@ BOOST_AUTO_TEST_CASE(uninitialized_var)
function f() returns (uint) { var x; return 2; }
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(string)
@@ -1797,7 +1838,7 @@ BOOST_AUTO_TEST_CASE(string)
function f(string x) external { s = x; }
}
)";
- BOOST_CHECK_NO_THROW(parseTextAndResolveNames(sourceCode));
+ BOOST_CHECK_NO_THROW(parseAndAnalyse(sourceCode));
}
BOOST_AUTO_TEST_CASE(string_index)
@@ -1808,7 +1849,7 @@ BOOST_AUTO_TEST_CASE(string_index)
function f() { var a = s[2]; }
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(string_length)
@@ -1819,7 +1860,7 @@ BOOST_AUTO_TEST_CASE(string_length)
function f() { var a = s.length; }
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(negative_integers_to_signed_out_of_bound)
@@ -1829,7 +1870,7 @@ BOOST_AUTO_TEST_CASE(negative_integers_to_signed_out_of_bound)
int8 public i = -129;
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(negative_integers_to_signed_min)
@@ -1839,7 +1880,7 @@ BOOST_AUTO_TEST_CASE(negative_integers_to_signed_min)
int8 public i = -128;
}
)";
- BOOST_CHECK_NO_THROW(parseTextAndResolveNames(sourceCode));
+ BOOST_CHECK_NO_THROW(parseAndAnalyse(sourceCode));
}
BOOST_AUTO_TEST_CASE(positive_integers_to_signed_out_of_bound)
@@ -1849,7 +1890,7 @@ BOOST_AUTO_TEST_CASE(positive_integers_to_signed_out_of_bound)
int8 public j = 128;
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(positive_integers_to_signed_out_of_bound_max)
@@ -1859,7 +1900,7 @@ BOOST_AUTO_TEST_CASE(positive_integers_to_signed_out_of_bound_max)
int8 public j = 127;
}
)";
- BOOST_CHECK_NO_THROW(parseTextAndResolveNames(sourceCode));
+ BOOST_CHECK_NO_THROW(parseAndAnalyse(sourceCode));
}
BOOST_AUTO_TEST_CASE(negative_integers_to_unsigned)
@@ -1869,7 +1910,7 @@ BOOST_AUTO_TEST_CASE(negative_integers_to_unsigned)
uint8 public x = -1;
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(positive_integers_to_unsigned_out_of_bound)
@@ -1879,7 +1920,7 @@ BOOST_AUTO_TEST_CASE(positive_integers_to_unsigned_out_of_bound)
uint8 public x = 700;
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(integer_boolean_operators)
@@ -1887,15 +1928,15 @@ BOOST_AUTO_TEST_CASE(integer_boolean_operators)
char const* sourceCode1 = R"(
contract test { function() { uint x = 1; uint y = 2; x || y; } }
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode1), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode1), TypeError);
char const* sourceCode2 = R"(
contract test { function() { uint x = 1; uint y = 2; x && y; } }
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode2), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode2), TypeError);
char const* sourceCode3 = R"(
contract test { function() { uint x = 1; !x; } }
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode3), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode3), TypeError);
}
BOOST_AUTO_TEST_CASE(reference_compare_operators)
@@ -1903,11 +1944,11 @@ BOOST_AUTO_TEST_CASE(reference_compare_operators)
char const* sourceCode1 = R"(
contract test { bytes a; bytes b; function() { a == b; } }
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode1), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode1), TypeError);
char const* sourceCode2 = R"(
contract test { struct s {uint a;} s x; s y; function() { x == y; } }
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode2), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode2), TypeError);
}
BOOST_AUTO_TEST_CASE(overwrite_memory_location_external)
@@ -1917,7 +1958,7 @@ BOOST_AUTO_TEST_CASE(overwrite_memory_location_external)
function f(uint[] memory a) external {}
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(overwrite_storage_location_external)
@@ -1927,7 +1968,7 @@ BOOST_AUTO_TEST_CASE(overwrite_storage_location_external)
function f(uint[] storage a) external {}
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(storage_location_local_variables)
@@ -1941,7 +1982,7 @@ BOOST_AUTO_TEST_CASE(storage_location_local_variables)
}
}
)";
- BOOST_CHECK_NO_THROW(parseTextAndResolveNames(sourceCode));
+ BOOST_CHECK_NO_THROW(parseAndAnalyse(sourceCode));
}
BOOST_AUTO_TEST_CASE(no_mappings_in_memory_array)
@@ -1953,7 +1994,7 @@ BOOST_AUTO_TEST_CASE(no_mappings_in_memory_array)
}
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(assignment_mem_to_local_storage_variable)
@@ -1967,7 +2008,7 @@ BOOST_AUTO_TEST_CASE(assignment_mem_to_local_storage_variable)
}
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(storage_assign_to_different_local_variable)
@@ -1984,7 +2025,7 @@ BOOST_AUTO_TEST_CASE(storage_assign_to_different_local_variable)
}
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(no_delete_on_storage_pointers)
@@ -1998,7 +2039,7 @@ BOOST_AUTO_TEST_CASE(no_delete_on_storage_pointers)
}
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(assignment_mem_storage_variable_directly)
@@ -2011,7 +2052,7 @@ BOOST_AUTO_TEST_CASE(assignment_mem_storage_variable_directly)
}
}
)";
- BOOST_CHECK_NO_THROW(parseTextAndResolveNames(sourceCode));
+ BOOST_CHECK_NO_THROW(parseAndAnalyse(sourceCode));
}
BOOST_AUTO_TEST_CASE(function_argument_mem_to_storage)
@@ -2025,7 +2066,7 @@ BOOST_AUTO_TEST_CASE(function_argument_mem_to_storage)
}
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(function_argument_storage_to_mem)
@@ -2039,7 +2080,7 @@ BOOST_AUTO_TEST_CASE(function_argument_storage_to_mem)
}
}
)";
- BOOST_CHECK_NO_THROW(parseTextAndResolveNames(sourceCode));
+ BOOST_CHECK_NO_THROW(parseAndAnalyse(sourceCode));
}
BOOST_AUTO_TEST_CASE(mem_array_assignment_changes_base_type)
@@ -2054,7 +2095,7 @@ BOOST_AUTO_TEST_CASE(mem_array_assignment_changes_base_type)
}
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(dynamic_return_types_not_possible)
@@ -2067,7 +2108,7 @@ BOOST_AUTO_TEST_CASE(dynamic_return_types_not_possible)
}
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(memory_arrays_not_resizeable)
@@ -2080,7 +2121,7 @@ BOOST_AUTO_TEST_CASE(memory_arrays_not_resizeable)
}
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(struct_constructor)
@@ -2093,7 +2134,7 @@ BOOST_AUTO_TEST_CASE(struct_constructor)
}
}
)";
- BOOST_CHECK_NO_THROW(parseTextAndResolveNames(sourceCode));
+ BOOST_CHECK_NO_THROW(parseAndAnalyse(sourceCode));
}
BOOST_AUTO_TEST_CASE(struct_constructor_nested)
@@ -2108,7 +2149,7 @@ BOOST_AUTO_TEST_CASE(struct_constructor_nested)
}
}
)";
- BOOST_CHECK_NO_THROW(parseTextAndResolveNames(sourceCode));
+ BOOST_CHECK_NO_THROW(parseAndAnalyse(sourceCode));
}
BOOST_AUTO_TEST_CASE(struct_named_constructor)
@@ -2121,7 +2162,7 @@ BOOST_AUTO_TEST_CASE(struct_named_constructor)
}
}
)";
- BOOST_CHECK_NO_THROW(parseTextAndResolveNames(sourceCode));
+ BOOST_CHECK_NO_THROW(parseAndAnalyse(sourceCode));
}
BOOST_AUTO_TEST_CASE(literal_strings)
@@ -2134,7 +2175,7 @@ BOOST_AUTO_TEST_CASE(literal_strings)
}
}
)";
- BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
+ BOOST_CHECK_NO_THROW(parseAndAnalyse(text));
}
BOOST_AUTO_TEST_CASE(invalid_integer_literal_fraction)
@@ -2146,7 +2187,7 @@ BOOST_AUTO_TEST_CASE(invalid_integer_literal_fraction)
}
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(invalid_integer_literal_exp)
@@ -2158,7 +2199,7 @@ BOOST_AUTO_TEST_CASE(invalid_integer_literal_exp)
}
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(memory_structs_with_mappings)
@@ -2173,7 +2214,7 @@ BOOST_AUTO_TEST_CASE(memory_structs_with_mappings)
}
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(string_bytes_conversion)
@@ -2190,7 +2231,7 @@ BOOST_AUTO_TEST_CASE(string_bytes_conversion)
function m() internal { string(b); }
}
)";
- BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
+ BOOST_CHECK_NO_THROW(parseAndAnalyse(text));
}
BOOST_AUTO_TEST_CASE(inheriting_from_library)
@@ -2199,7 +2240,7 @@ BOOST_AUTO_TEST_CASE(inheriting_from_library)
library Lib {}
contract Test is Lib {}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(inheriting_library)
@@ -2208,7 +2249,7 @@ BOOST_AUTO_TEST_CASE(inheriting_library)
contract Test {}
library Lib is Test {}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(library_having_variables)
@@ -2216,7 +2257,7 @@ BOOST_AUTO_TEST_CASE(library_having_variables)
char const* text = R"(
library Lib { uint x; }
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_CASE(valid_library)
@@ -2224,7 +2265,7 @@ BOOST_AUTO_TEST_CASE(valid_library)
char const* text = R"(
library Lib { uint constant x = 9; }
)";
- BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
+ BOOST_CHECK_NO_THROW(parseAndAnalyse(text));
}
BOOST_AUTO_TEST_CASE(call_to_library_function)
@@ -2240,7 +2281,7 @@ BOOST_AUTO_TEST_CASE(call_to_library_function)
}
}
)";
- BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
+ BOOST_CHECK_NO_THROW(parseAndAnalyse(text));
}
BOOST_AUTO_TEST_CASE(creating_contract_within_the_contract)
@@ -2250,7 +2291,7 @@ BOOST_AUTO_TEST_CASE(creating_contract_within_the_contract)
function f() { var x = new Test(); }
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(sourceCode), TypeError);
}
BOOST_AUTO_TEST_CASE(array_out_of_bound_access)
@@ -2264,7 +2305,7 @@ BOOST_AUTO_TEST_CASE(array_out_of_bound_access)
}
}
)";
- BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+ SOLIDITY_CHECK_ERROR_TYPE(parseAndAnalyseReturnError(text), TypeError);
}
BOOST_AUTO_TEST_SUITE_END()