From d997dc55d154c93af01175d880734b9e737d34ca Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 2 Apr 2015 15:10:35 +0200 Subject: [PATCH 01/10] Allowing abstract contracts constructor to have no args - If a constructor is part of an abstract contract we can omit its arguments - IF a contract is abstract make sure to not create and/or request Assembly code about it since it's not compiled --- AST.cpp | 14 +++++++------- AST.h | 2 +- Compiler.cpp | 1 + CompilerStack.cpp | 16 +++++++++++----- CompilerStack.h | 4 ++-- 5 files changed, 22 insertions(+), 15 deletions(-) diff --git a/AST.cpp b/AST.cpp index 0abdf7819..370166462 100644 --- a/AST.cpp +++ b/AST.cpp @@ -281,7 +281,7 @@ void InheritanceSpecifier::checkTypeRequirements() ContractDefinition const* base = dynamic_cast(m_baseName->getReferencedDeclaration()); solAssert(base, "Base contract not available."); TypePointers parameterTypes = ContractType(*base).getConstructorType()->getParameterTypes(); - if (parameterTypes.size() != m_arguments.size()) + if (m_arguments.size() != 0 && parameterTypes.size() != m_arguments.size()) BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for constructor call.")); for (size_t i = 0; i < m_arguments.size(); ++i) if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i])) @@ -348,8 +348,8 @@ void FunctionDefinition::checkTypeRequirements() } for (ASTPointer const& modifier: m_functionModifiers) modifier->checkTypeRequirements(isConstructor() ? - dynamic_cast(*getScope()).getBaseContracts() : - vector>()); + dynamic_cast(*getScope()).getLinearizedBaseContracts() : + vector()); if (m_body) m_body->checkTypeRequirements(); } @@ -426,7 +426,7 @@ void ModifierDefinition::checkTypeRequirements() m_body->checkTypeRequirements(); } -void ModifierInvocation::checkTypeRequirements(vector> const& _bases) +void ModifierInvocation::checkTypeRequirements(vector const& _bases) { m_modifierName->checkTypeRequirements(); for (ASTPointer const& argument: m_arguments) @@ -439,10 +439,10 @@ void ModifierInvocation::checkTypeRequirements(vectorgetParameters(); else // check parameters for Base constructors - for (auto const& base: _bases) - if (declaration == base->getName()->getReferencedDeclaration()) + for (auto const* base: _bases) + if (declaration == base) { - if (auto referencedConstructor = dynamic_cast(*declaration).getConstructor()) + if (auto referencedConstructor = base->getConstructor()) parameters = &referencedConstructor->getParameters(); else parameters = &emptyParameterList; diff --git a/AST.h b/AST.h index 9f5f9fcb1..8c36caeaf 100644 --- a/AST.h +++ b/AST.h @@ -566,7 +566,7 @@ public: std::vector> const& getArguments() 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> const& _bases); + void checkTypeRequirements(std::vector const& _bases); private: ASTPointer m_modifierName; diff --git a/Compiler.cpp b/Compiler.cpp index 886565cb4..f0197e23b 100644 --- a/Compiler.cpp +++ b/Compiler.cpp @@ -136,6 +136,7 @@ void Compiler::appendBaseConstructor(FunctionDefinition const& _constructor) FunctionType constructorType(_constructor); if (!constructorType.getParameterTypes().empty()) { + solAssert(m_baseArguments.count(&_constructor), ""); std::vector> const* arguments = m_baseArguments[&_constructor]; solAssert(arguments, ""); for (unsigned i = 0; i < arguments->size(); ++i) diff --git a/CompilerStack.cpp b/CompilerStack.cpp index 1301bfa5d..c35d9324c 100644 --- a/CompilerStack.cpp +++ b/CompilerStack.cpp @@ -157,14 +157,16 @@ bytes const& CompilerStack::compile(string const& _sourceCode, bool _optimize) return getBytecode(); } -eth::AssemblyItems const& CompilerStack::getAssemblyItems(string const& _contractName) const +eth::AssemblyItems const* CompilerStack::getAssemblyItems(string const& _contractName) const { - return getContract(_contractName).compiler->getAssemblyItems(); + Contract const& contract = getContract(_contractName); + return contract.compiler ? &getContract(_contractName).compiler->getAssemblyItems() : nullptr; } -eth::AssemblyItems const& CompilerStack::getRuntimeAssemblyItems(string const& _contractName) const +eth::AssemblyItems const* CompilerStack::getRuntimeAssemblyItems(string const& _contractName) const { - return getContract(_contractName).compiler->getRuntimeAssemblyItems(); + Contract const& contract = getContract(_contractName); + return contract.compiler ? &getContract(_contractName).compiler->getRuntimeAssemblyItems() : nullptr; } bytes const& CompilerStack::getBytecode(string const& _contractName) const @@ -184,7 +186,11 @@ dev::h256 CompilerStack::getContractCodeHash(string const& _contractName) const void CompilerStack::streamAssembly(ostream& _outStream, string const& _contractName, StringMap _sourceCodes) const { - getContract(_contractName).compiler->streamAssembly(_outStream, _sourceCodes); + Contract const& contract = getContract(_contractName); + if (contract.compiler) + getContract(_contractName).compiler->streamAssembly(_outStream, _sourceCodes); + else + _outStream << "Contract not fully implemented" << endl; } string const& CompilerStack::getInterface(string const& _contractName) const diff --git a/CompilerStack.h b/CompilerStack.h index 1cf576ab4..19c1ba4e1 100644 --- a/CompilerStack.h +++ b/CompilerStack.h @@ -94,9 +94,9 @@ public: /// @returns the runtime bytecode for the contract, i.e. the code that is returned by the constructor. bytes const& getRuntimeBytecode(std::string const& _contractName = "") const; /// @returns normal contract assembly items - eth::AssemblyItems const& getAssemblyItems(std::string const& _contractName = "") const; + eth::AssemblyItems const* getAssemblyItems(std::string const& _contractName = "") const; /// @returns runtime contract assembly items - eth::AssemblyItems const& getRuntimeAssemblyItems(std::string const& _contractName = "") const; + eth::AssemblyItems const* getRuntimeAssemblyItems(std::string const& _contractName = "") const; /// @returns hash of the runtime bytecode for the contract, i.e. the code that is returned by the constructor. dev::h256 getContractCodeHash(std::string const& _contractName = "") const; From beba2705ba2fd9f87bf76f439c4a99cec0f6a06d Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 2 Apr 2015 16:56:12 +0200 Subject: [PATCH 02/10] Check all constructors in inheritance chain get args - Also add a missing override in a function of EnumValue --- AST.cpp | 42 ++++++++++++++++++++++++++++++++++++++++++ AST.h | 3 ++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/AST.cpp b/AST.cpp index 370166462..4d183889c 100644 --- a/AST.cpp +++ b/AST.cpp @@ -54,6 +54,7 @@ void ContractDefinition::checkTypeRequirements() checkIllegalOverrides(); checkAbstractFunctions(); + checkAbstractConstructors(); FunctionDefinition const* constructor = getConstructor(); if (constructor && !constructor->getReturnParameters().empty()) @@ -152,6 +153,47 @@ void ContractDefinition::checkAbstractFunctions() } } +void ContractDefinition::checkAbstractConstructors() +{ + set argumentsNeeded; + set argumentsProvided; + // check that we get arguments for all base constructors that need it. + // If not mark the contract as abstract (not fully implemented) + vector const& bases = getLinearizedBaseContracts(); + for (ContractDefinition const* contract: bases) + { + FunctionDefinition const* constructor = contract->getConstructor(); + if (constructor) + { + if (!constructor->getParameters().empty()) + argumentsProvided.insert(constructor); + for (auto const& modifier: constructor->getModifiers()) + { + auto baseContract = dynamic_cast( + modifier->getName()->getReferencedDeclaration()); + if (baseContract) + { + FunctionDefinition const* baseConstructor = baseContract->getConstructor(); + if (argumentsProvided.count(baseConstructor) == 1) + argumentsNeeded.insert(baseConstructor); + } + } + } + + for (ASTPointer const& base: contract->getBaseContracts()) + { + ContractDefinition const* baseContract = dynamic_cast( + base->getName()->getReferencedDeclaration()); + solAssert(baseContract, ""); + FunctionDefinition const* baseConstructor = baseContract->getConstructor(); + if (argumentsProvided.count(baseConstructor) == 1) + argumentsNeeded.insert(baseConstructor); + } + } + if (argumentsProvided != argumentsNeeded) + 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 diff --git a/AST.h b/AST.h index 8c36caeaf..99abf2295 100644 --- a/AST.h +++ b/AST.h @@ -284,6 +284,7 @@ public: private: void checkIllegalOverrides() const; void checkAbstractFunctions(); + void checkAbstractConstructors(); std::vector, FunctionTypePointer>> const& getInterfaceFunctionList() const; @@ -376,7 +377,7 @@ class EnumValue: public Declaration virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; - TypePointer getType(ContractDefinition const* = nullptr) const; + TypePointer getType(ContractDefinition const* = nullptr) const override; }; /** From 52a442a100ef065ec36cc9e20f62f6d878347e6d Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 2 Apr 2015 17:05:27 +0200 Subject: [PATCH 03/10] size()!=0 -> !empty() --- AST.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AST.cpp b/AST.cpp index 4d183889c..a66aa9897 100644 --- a/AST.cpp +++ b/AST.cpp @@ -323,7 +323,7 @@ void InheritanceSpecifier::checkTypeRequirements() ContractDefinition const* base = dynamic_cast(m_baseName->getReferencedDeclaration()); solAssert(base, "Base contract not available."); TypePointers parameterTypes = ContractType(*base).getConstructorType()->getParameterTypes(); - if (m_arguments.size() != 0 && parameterTypes.size() != m_arguments.size()) + if (!m_arguments.empty() && parameterTypes.size() != m_arguments.size()) BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for constructor call.")); for (size_t i = 0; i < m_arguments.size(); ++i) if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i])) From 0c296cd8093af05507426f9a5a5b25bb2b51f4fb Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 2 Apr 2015 17:12:15 +0200 Subject: [PATCH 04/10] Fixing new abstract contract error location reporting --- AST.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AST.cpp b/AST.cpp index a66aa9897..7f4b8710e 100644 --- a/AST.cpp +++ b/AST.cpp @@ -728,7 +728,7 @@ void NewExpression::checkTypeRequirements() if (!m_contract) BOOST_THROW_EXCEPTION(createTypeError("Identifier is not a contract.")); if (!m_contract->isFullyImplemented()) - BOOST_THROW_EXCEPTION(m_contract->createTypeError("Trying to create an instance of an abstract contract.")); + BOOST_THROW_EXCEPTION(createTypeError("Trying to create an instance of an abstract contract.")); shared_ptr contractType = make_shared(*m_contract); TypePointers const& parameterTypes = contractType->getConstructorType()->getParameterTypes(); m_type = make_shared(parameterTypes, TypePointers{contractType}, From eb84c3171aa362c507c7213c937748b9e9f78ca9 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 2 Apr 2015 17:42:43 +0200 Subject: [PATCH 05/10] Add "this" contract's ctor to provided ctors set - Also properly naming the 2 sets in checkAbstractConstructors() function --- AST.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/AST.cpp b/AST.cpp index 7f4b8710e..1c12ef5a1 100644 --- a/AST.cpp +++ b/AST.cpp @@ -166,7 +166,7 @@ void ContractDefinition::checkAbstractConstructors() if (constructor) { if (!constructor->getParameters().empty()) - argumentsProvided.insert(constructor); + argumentsNeeded.insert(constructor); for (auto const& modifier: constructor->getModifiers()) { auto baseContract = dynamic_cast( @@ -174,8 +174,8 @@ void ContractDefinition::checkAbstractConstructors() if (baseContract) { FunctionDefinition const* baseConstructor = baseContract->getConstructor(); - if (argumentsProvided.count(baseConstructor) == 1) - argumentsNeeded.insert(baseConstructor); + if (argumentsNeeded.count(baseConstructor) == 1) + argumentsProvided.insert(baseConstructor); } } } @@ -186,10 +186,13 @@ void ContractDefinition::checkAbstractConstructors() base->getName()->getReferencedDeclaration()); solAssert(baseContract, ""); FunctionDefinition const* baseConstructor = baseContract->getConstructor(); - if (argumentsProvided.count(baseConstructor) == 1) - argumentsNeeded.insert(baseConstructor); + if (argumentsNeeded.count(baseConstructor) == 1) + argumentsProvided.insert(baseConstructor); } } + // add this contract's constructor to the provided too + if (getConstructor() && !getConstructor()->getParameters().empty()) + argumentsProvided.insert(getConstructor()); if (argumentsProvided != argumentsNeeded) setFullyImplemented(false); } From 1a19d436db535b2ea1325b7c00295befdb8be216 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 2 Apr 2015 17:50:43 +0200 Subject: [PATCH 06/10] Adding forgotten virtual specifier to EnumValue getType() --- AST.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AST.h b/AST.h index 99abf2295..0c133ff1a 100644 --- a/AST.h +++ b/AST.h @@ -377,7 +377,7 @@ class EnumValue: public Declaration virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; - TypePointer getType(ContractDefinition const* = nullptr) const override; + virtual TypePointer getType(ContractDefinition const* = nullptr) const override; }; /** From c558aa06567f4e6e28b8f15c3dee73867fde447b Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 17 Apr 2015 16:17:21 +0200 Subject: [PATCH 07/10] Fixing detection of abstract contract --- AST.cpp | 41 ++++++++++++++++++----------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/AST.cpp b/AST.cpp index 1c12ef5a1..5f681205d 100644 --- a/AST.cpp +++ b/AST.cpp @@ -155,45 +155,40 @@ void ContractDefinition::checkAbstractFunctions() void ContractDefinition::checkAbstractConstructors() { - set argumentsNeeded; - set argumentsProvided; + set argumentsNeeded; // check that we get arguments for all base constructors that need it. // If not mark the contract as abstract (not fully implemented) + vector const& bases = getLinearizedBaseContracts(); + for (ContractDefinition const* contract: bases) + if (FunctionDefinition const* constructor = contract->getConstructor()) + if (contract != this && !constructor->getParameters().empty()) + argumentsNeeded.insert(contract); + for (ContractDefinition const* contract: bases) { - FunctionDefinition const* constructor = contract->getConstructor(); - if (constructor) - { - if (!constructor->getParameters().empty()) - argumentsNeeded.insert(constructor); + if (FunctionDefinition const* constructor = contract->getConstructor()) for (auto const& modifier: constructor->getModifiers()) { auto baseContract = dynamic_cast( - modifier->getName()->getReferencedDeclaration()); + modifier->getName()->getReferencedDeclaration() + ); if (baseContract) - { - FunctionDefinition const* baseConstructor = baseContract->getConstructor(); - if (argumentsNeeded.count(baseConstructor) == 1) - argumentsProvided.insert(baseConstructor); - } + argumentsNeeded.erase(baseContract); } - } + for (ASTPointer const& base: contract->getBaseContracts()) { - ContractDefinition const* baseContract = dynamic_cast( - base->getName()->getReferencedDeclaration()); + auto baseContract = dynamic_cast( + base->getName()->getReferencedDeclaration() + ); solAssert(baseContract, ""); - FunctionDefinition const* baseConstructor = baseContract->getConstructor(); - if (argumentsNeeded.count(baseConstructor) == 1) - argumentsProvided.insert(baseConstructor); + if (!base->getArguments().empty()) + argumentsNeeded.erase(baseContract); } } - // add this contract's constructor to the provided too - if (getConstructor() && !getConstructor()->getParameters().empty()) - argumentsProvided.insert(getConstructor()); - if (argumentsProvided != argumentsNeeded) + if (!argumentsNeeded.empty()) setFullyImplemented(false); } From f829dad7e385aa9578d56fe926a4741f9f90c105 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Fri, 17 Apr 2015 17:41:41 +0200 Subject: [PATCH 08/10] added asm-json flag to cl compiler Conflicts: libsolidity/CompilerStack.cpp --- Compiler.h | 5 +++-- CompilerContext.h | 3 ++- CompilerStack.cpp | 4 ++-- CompilerStack.h | 3 ++- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Compiler.h b/Compiler.h index 4b1e1b4d6..260aebd33 100644 --- a/Compiler.h +++ b/Compiler.h @@ -42,9 +42,10 @@ public: bytes getAssembledBytecode() { return m_context.getAssembledBytecode(m_optimize); } bytes getRuntimeBytecode() { return m_runtimeContext.getAssembledBytecode(m_optimize);} /// @arg _sourceCodes is the map of input files to source code strings - void streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap()) const + /// @arg _inJsonFromat shows weather the out should be in Json format + void streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap(), bool _inJsonFormat = false) const { - m_context.streamAssembly(_stream, _sourceCodes); + m_context.streamAssembly(_stream, _sourceCodes, _inJsonFormat); } /// @returns Assembly items of the normal compiler context eth::AssemblyItems const& getAssemblyItems() const { return m_context.getAssembly().getItems(); } diff --git a/CompilerContext.h b/CompilerContext.h index e752d59b8..3fcf0706d 100644 --- a/CompilerContext.h +++ b/CompilerContext.h @@ -122,7 +122,8 @@ public: eth::Assembly const& getAssembly() const { return m_asm; } /// @arg _sourceCodes is the map of input files to source code strings - void streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap()) const { m_asm.stream(_stream, "", _sourceCodes); } + /// @arg _inJsonFromat shows weather the out should be in Json format + void streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap(), bool _inJsonFormat = false) const { m_asm.stream(_stream, "", _sourceCodes, _inJsonFormat); } bytes getAssembledBytecode(bool _optimize = false) { return m_asm.optimise(_optimize).assemble(); } diff --git a/CompilerStack.cpp b/CompilerStack.cpp index c35d9324c..592f61276 100644 --- a/CompilerStack.cpp +++ b/CompilerStack.cpp @@ -184,11 +184,11 @@ dev::h256 CompilerStack::getContractCodeHash(string const& _contractName) const return dev::sha3(getRuntimeBytecode(_contractName)); } -void CompilerStack::streamAssembly(ostream& _outStream, string const& _contractName, StringMap _sourceCodes) const +void CompilerStack::streamAssembly(ostream& _outStream, string const& _contractName, StringMap _sourceCodes, bool _inJsonFormat) const { Contract const& contract = getContract(_contractName); if (contract.compiler) - getContract(_contractName).compiler->streamAssembly(_outStream, _sourceCodes); + contract(_contractName).compiler->streamAssembly(_outStream, _sourceCodes, _inJsonFormat); else _outStream << "Contract not fully implemented" << endl; } diff --git a/CompilerStack.h b/CompilerStack.h index 19c1ba4e1..ef3d09663 100644 --- a/CompilerStack.h +++ b/CompilerStack.h @@ -102,8 +102,9 @@ public: /// Streams a verbose version of the assembly to @a _outStream. /// @arg _sourceCodes is the map of input files to source code strings + /// @arg _inJsonFromat shows weather the out should be in Json format /// Prerequisite: Successful compilation. - void streamAssembly(std::ostream& _outStream, std::string const& _contractName = "", StringMap _sourceCodes = StringMap()) const; + void streamAssembly(std::ostream& _outStream, std::string const& _contractName = "", StringMap _sourceCodes = StringMap(), bool _inJsonFormat = false) const; /// Returns a string representing the contract interface in JSON. /// Prerequisite: Successful call to parse or compile. From 1cfa9649901a0093816f9afac403d7931ab560be Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Tue, 14 Apr 2015 11:38:36 +0200 Subject: [PATCH 09/10] style fixes --- Compiler.h | 2 +- CompilerContext.h | 7 +++++-- CompilerStack.h | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Compiler.h b/Compiler.h index 260aebd33..d476ec684 100644 --- a/Compiler.h +++ b/Compiler.h @@ -42,7 +42,7 @@ public: bytes getAssembledBytecode() { return m_context.getAssembledBytecode(m_optimize); } bytes getRuntimeBytecode() { return m_runtimeContext.getAssembledBytecode(m_optimize);} /// @arg _sourceCodes is the map of input files to source code strings - /// @arg _inJsonFromat shows weather the out should be in Json format + /// @arg _inJsonFromat shows whether the out should be in Json format void streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap(), bool _inJsonFormat = false) const { m_context.streamAssembly(_stream, _sourceCodes, _inJsonFormat); diff --git a/CompilerContext.h b/CompilerContext.h index 3fcf0706d..9c2156bfa 100644 --- a/CompilerContext.h +++ b/CompilerContext.h @@ -122,8 +122,11 @@ public: eth::Assembly const& getAssembly() const { return m_asm; } /// @arg _sourceCodes is the map of input files to source code strings - /// @arg _inJsonFromat shows weather the out should be in Json format - void streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap(), bool _inJsonFormat = false) const { m_asm.stream(_stream, "", _sourceCodes, _inJsonFormat); } + /// @arg _inJsonFormat shows whether the out should be in Json format + void streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap(), bool _inJsonFormat = false) const + { + m_asm.stream(_stream, "", _sourceCodes, _inJsonFormat); + } bytes getAssembledBytecode(bool _optimize = false) { return m_asm.optimise(_optimize).assemble(); } diff --git a/CompilerStack.h b/CompilerStack.h index ef3d09663..2e7c217d5 100644 --- a/CompilerStack.h +++ b/CompilerStack.h @@ -102,7 +102,7 @@ public: /// Streams a verbose version of the assembly to @a _outStream. /// @arg _sourceCodes is the map of input files to source code strings - /// @arg _inJsonFromat shows weather the out should be in Json format + /// @arg _inJsonFromat shows whether the out should be in Json format /// Prerequisite: Successful compilation. void streamAssembly(std::ostream& _outStream, std::string const& _contractName = "", StringMap _sourceCodes = StringMap(), bool _inJsonFormat = false) const; From e4808305a17f43392e03e29546494d464c5f0895 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Fri, 17 Apr 2015 16:40:40 +0200 Subject: [PATCH 10/10] removed unused parameter from streamAsmJson --- CompilerStack.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CompilerStack.cpp b/CompilerStack.cpp index 592f61276..d6274e2c7 100644 --- a/CompilerStack.cpp +++ b/CompilerStack.cpp @@ -188,7 +188,7 @@ void CompilerStack::streamAssembly(ostream& _outStream, string const& _contractN { Contract const& contract = getContract(_contractName); if (contract.compiler) - contract(_contractName).compiler->streamAssembly(_outStream, _sourceCodes, _inJsonFormat); + contract.compiler->streamAssembly(_outStream, _sourceCodes, _inJsonFormat); else _outStream << "Contract not fully implemented" << endl; }