mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #6417 from ethereum/memleaks
Type System API refactor
This commit is contained in:
commit
b8ad8fb15e
@ -47,6 +47,8 @@ set(sources
|
|||||||
ast/ExperimentalFeatures.h
|
ast/ExperimentalFeatures.h
|
||||||
ast/Types.cpp
|
ast/Types.cpp
|
||||||
ast/Types.h
|
ast/Types.h
|
||||||
|
ast/TypeProvider.cpp
|
||||||
|
ast/TypeProvider.h
|
||||||
codegen/ABIFunctions.cpp
|
codegen/ABIFunctions.cpp
|
||||||
codegen/ABIFunctions.h
|
codegen/ABIFunctions.h
|
||||||
codegen/ArrayUtils.cpp
|
codegen/ArrayUtils.cpp
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include <libsolidity/analysis/ConstantEvaluator.h>
|
#include <libsolidity/analysis/ConstantEvaluator.h>
|
||||||
|
|
||||||
#include <libsolidity/ast/AST.h>
|
#include <libsolidity/ast/AST.h>
|
||||||
|
#include <libsolidity/ast/TypeProvider.h>
|
||||||
#include <liblangutil/ErrorReporter.h>
|
#include <liblangutil/ErrorReporter.h>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
@ -56,7 +57,7 @@ void ConstantEvaluator::endVisit(BinaryOperation const& _operation)
|
|||||||
setType(
|
setType(
|
||||||
_operation,
|
_operation,
|
||||||
TokenTraits::isCompareOp(_operation.getOperator()) ?
|
TokenTraits::isCompareOp(_operation.getOperator()) ?
|
||||||
make_shared<BoolType>() :
|
TypeProvider::boolType() :
|
||||||
commonType
|
commonType
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -64,7 +65,7 @@ void ConstantEvaluator::endVisit(BinaryOperation const& _operation)
|
|||||||
|
|
||||||
void ConstantEvaluator::endVisit(Literal const& _literal)
|
void ConstantEvaluator::endVisit(Literal const& _literal)
|
||||||
{
|
{
|
||||||
setType(_literal, Type::forLiteral(_literal));
|
setType(_literal, TypeProvider::forLiteral(_literal));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConstantEvaluator::endVisit(Identifier const& _identifier)
|
void ConstantEvaluator::endVisit(Identifier const& _identifier)
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include <libsolidity/analysis/ContractLevelChecker.h>
|
#include <libsolidity/analysis/ContractLevelChecker.h>
|
||||||
|
|
||||||
#include <libsolidity/ast/AST.h>
|
#include <libsolidity/ast/AST.h>
|
||||||
|
#include <libsolidity/ast/TypeProvider.h>
|
||||||
#include <libsolidity/analysis/TypeChecker.h>
|
#include <libsolidity/analysis/TypeChecker.h>
|
||||||
#include <liblangutil/ErrorReporter.h>
|
#include <liblangutil/ErrorReporter.h>
|
||||||
#include <boost/range/adaptor/reversed.hpp>
|
#include <boost/range/adaptor/reversed.hpp>
|
||||||
@ -244,13 +245,13 @@ void ContractLevelChecker::checkAbstractFunctions(ContractDefinition const& _con
|
|||||||
{
|
{
|
||||||
for (VariableDeclaration const* v: contract->stateVariables())
|
for (VariableDeclaration const* v: contract->stateVariables())
|
||||||
if (v->isPartOfExternalInterface())
|
if (v->isPartOfExternalInterface())
|
||||||
registerFunction(*v, make_shared<FunctionType>(*v), true);
|
registerFunction(*v, TypeProvider::functionType(*v), true);
|
||||||
|
|
||||||
for (FunctionDefinition const* function: contract->definedFunctions())
|
for (FunctionDefinition const* function: contract->definedFunctions())
|
||||||
if (!function->isConstructor())
|
if (!function->isConstructor())
|
||||||
registerFunction(
|
registerFunction(
|
||||||
*function,
|
*function,
|
||||||
make_shared<FunctionType>(*function)->asCallableFunction(false),
|
TypeProvider::functionType(*function)->asCallableFunction(false),
|
||||||
function->isImplemented()
|
function->isImplemented()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -407,7 +408,7 @@ void ContractLevelChecker::checkExternalTypeClashes(ContractDefinition const& _c
|
|||||||
for (FunctionDefinition const* f: contract->definedFunctions())
|
for (FunctionDefinition const* f: contract->definedFunctions())
|
||||||
if (f->isPartOfExternalInterface())
|
if (f->isPartOfExternalInterface())
|
||||||
{
|
{
|
||||||
auto functionType = make_shared<FunctionType>(*f);
|
auto functionType = TypeProvider::functionType(*f);
|
||||||
// under non error circumstances this should be true
|
// under non error circumstances this should be true
|
||||||
if (functionType->interfaceFunctionType())
|
if (functionType->interfaceFunctionType())
|
||||||
externalDeclarations[functionType->externalSignature()].emplace_back(
|
externalDeclarations[functionType->externalSignature()].emplace_back(
|
||||||
@ -417,7 +418,7 @@ void ContractLevelChecker::checkExternalTypeClashes(ContractDefinition const& _c
|
|||||||
for (VariableDeclaration const* v: contract->stateVariables())
|
for (VariableDeclaration const* v: contract->stateVariables())
|
||||||
if (v->isPartOfExternalInterface())
|
if (v->isPartOfExternalInterface())
|
||||||
{
|
{
|
||||||
auto functionType = make_shared<FunctionType>(*v);
|
auto functionType = TypeProvider::functionType(*v);
|
||||||
// under non error circumstances this should be true
|
// under non error circumstances this should be true
|
||||||
if (functionType->interfaceFunctionType())
|
if (functionType->interfaceFunctionType())
|
||||||
externalDeclarations[functionType->externalSignature()].emplace_back(
|
externalDeclarations[functionType->externalSignature()].emplace_back(
|
||||||
|
@ -235,7 +235,7 @@ bool ControlFlowBuilder::visit(FunctionCall const& _functionCall)
|
|||||||
solAssert(!!m_currentNode, "");
|
solAssert(!!m_currentNode, "");
|
||||||
solAssert(!!_functionCall.expression().annotation().type, "");
|
solAssert(!!_functionCall.expression().annotation().type, "");
|
||||||
|
|
||||||
if (auto functionType = dynamic_pointer_cast<FunctionType const>(_functionCall.expression().annotation().type))
|
if (auto functionType = dynamic_cast<FunctionType const*>(_functionCall.expression().annotation().type))
|
||||||
switch (functionType->kind())
|
switch (functionType->kind())
|
||||||
{
|
{
|
||||||
case FunctionType::Kind::Revert:
|
case FunctionType::Kind::Revert:
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include <libsolidity/analysis/GlobalContext.h>
|
#include <libsolidity/analysis/GlobalContext.h>
|
||||||
|
|
||||||
#include <libsolidity/ast/AST.h>
|
#include <libsolidity/ast/AST.h>
|
||||||
|
#include <libsolidity/ast/TypeProvider.h>
|
||||||
#include <libsolidity/ast/Types.h>
|
#include <libsolidity/ast/Types.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@ -34,42 +35,50 @@ namespace dev
|
|||||||
namespace solidity
|
namespace solidity
|
||||||
{
|
{
|
||||||
|
|
||||||
GlobalContext::GlobalContext():
|
inline vector<shared_ptr<MagicVariableDeclaration const>> constructMagicVariables()
|
||||||
m_magicVariables(vector<shared_ptr<MagicVariableDeclaration const>>{
|
{
|
||||||
make_shared<MagicVariableDeclaration>("abi", make_shared<MagicType>(MagicType::Kind::ABI)),
|
static auto const magicVarDecl = [](string const& _name, Type const* _type) {
|
||||||
make_shared<MagicVariableDeclaration>("addmod", make_shared<FunctionType>(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Kind::AddMod, false, StateMutability::Pure)),
|
return make_shared<MagicVariableDeclaration>(_name, _type);
|
||||||
make_shared<MagicVariableDeclaration>("assert", make_shared<FunctionType>(strings{"bool"}, strings{}, FunctionType::Kind::Assert, false, StateMutability::Pure)),
|
};
|
||||||
make_shared<MagicVariableDeclaration>("block", make_shared<MagicType>(MagicType::Kind::Block)),
|
|
||||||
make_shared<MagicVariableDeclaration>("blockhash", make_shared<FunctionType>(strings{"uint256"}, strings{"bytes32"}, FunctionType::Kind::BlockHash, false, StateMutability::View)),
|
return {
|
||||||
make_shared<MagicVariableDeclaration>("ecrecover", make_shared<FunctionType>(strings{"bytes32", "uint8", "bytes32", "bytes32"}, strings{"address"}, FunctionType::Kind::ECRecover, false, StateMutability::Pure)),
|
magicVarDecl("abi", TypeProvider::magicType(MagicType::Kind::ABI)),
|
||||||
make_shared<MagicVariableDeclaration>("gasleft", make_shared<FunctionType>(strings(), strings{"uint256"}, FunctionType::Kind::GasLeft, false, StateMutability::View)),
|
magicVarDecl("addmod", TypeProvider::functionType(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Kind::AddMod, false, StateMutability::Pure)),
|
||||||
make_shared<MagicVariableDeclaration>("keccak256", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::KECCAK256, false, StateMutability::Pure)),
|
magicVarDecl("assert", TypeProvider::functionType(strings{"bool"}, strings{}, FunctionType::Kind::Assert, false, StateMutability::Pure)),
|
||||||
make_shared<MagicVariableDeclaration>("log0", make_shared<FunctionType>(strings{"bytes32"}, strings{}, FunctionType::Kind::Log0)),
|
magicVarDecl("block", TypeProvider::magicType(MagicType::Kind::Block)),
|
||||||
make_shared<MagicVariableDeclaration>("log1", make_shared<FunctionType>(strings{"bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log1)),
|
magicVarDecl("blockhash", TypeProvider::functionType(strings{"uint256"}, strings{"bytes32"}, FunctionType::Kind::BlockHash, false, StateMutability::View)),
|
||||||
make_shared<MagicVariableDeclaration>("log2", make_shared<FunctionType>(strings{"bytes32", "bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log2)),
|
magicVarDecl("ecrecover", TypeProvider::functionType(strings{"bytes32", "uint8", "bytes32", "bytes32"}, strings{"address"}, FunctionType::Kind::ECRecover, false, StateMutability::Pure)),
|
||||||
make_shared<MagicVariableDeclaration>("log3", make_shared<FunctionType>(strings{"bytes32", "bytes32", "bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log3)),
|
magicVarDecl("gasleft", TypeProvider::functionType(strings(), strings{"uint256"}, FunctionType::Kind::GasLeft, false, StateMutability::View)),
|
||||||
make_shared<MagicVariableDeclaration>("log4", make_shared<FunctionType>(strings{"bytes32", "bytes32", "bytes32", "bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log4)),
|
magicVarDecl("keccak256", TypeProvider::functionType(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::KECCAK256, false, StateMutability::Pure)),
|
||||||
make_shared<MagicVariableDeclaration>("msg", make_shared<MagicType>(MagicType::Kind::Message)),
|
magicVarDecl("log0", TypeProvider::functionType(strings{"bytes32"}, strings{}, FunctionType::Kind::Log0)),
|
||||||
make_shared<MagicVariableDeclaration>("mulmod", make_shared<FunctionType>(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Kind::MulMod, false, StateMutability::Pure)),
|
magicVarDecl("log1", TypeProvider::functionType(strings{"bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log1)),
|
||||||
make_shared<MagicVariableDeclaration>("now", make_shared<IntegerType>(256)),
|
magicVarDecl("log2", TypeProvider::functionType(strings{"bytes32", "bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log2)),
|
||||||
make_shared<MagicVariableDeclaration>("require", make_shared<FunctionType>(strings{"bool"}, strings{}, FunctionType::Kind::Require, false, StateMutability::Pure)),
|
magicVarDecl("log3", TypeProvider::functionType(strings{"bytes32", "bytes32", "bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log3)),
|
||||||
make_shared<MagicVariableDeclaration>("require", make_shared<FunctionType>(strings{"bool", "string memory"}, strings{}, FunctionType::Kind::Require, false, StateMutability::Pure)),
|
magicVarDecl("log4", TypeProvider::functionType(strings{"bytes32", "bytes32", "bytes32", "bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log4)),
|
||||||
make_shared<MagicVariableDeclaration>("revert", make_shared<FunctionType>(strings(), strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)),
|
magicVarDecl("msg", TypeProvider::magicType(MagicType::Kind::Message)),
|
||||||
make_shared<MagicVariableDeclaration>("revert", make_shared<FunctionType>(strings{"string memory"}, strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)),
|
magicVarDecl("mulmod", TypeProvider::functionType(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Kind::MulMod, false, StateMutability::Pure)),
|
||||||
make_shared<MagicVariableDeclaration>("ripemd160", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bytes20"}, FunctionType::Kind::RIPEMD160, false, StateMutability::Pure)),
|
magicVarDecl("now", TypeProvider::uint256()),
|
||||||
make_shared<MagicVariableDeclaration>("selfdestruct", make_shared<FunctionType>(strings{"address payable"}, strings{}, FunctionType::Kind::Selfdestruct)),
|
magicVarDecl("require", TypeProvider::functionType(strings{"bool"}, strings{}, FunctionType::Kind::Require, false, StateMutability::Pure)),
|
||||||
make_shared<MagicVariableDeclaration>("sha256", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::SHA256, false, StateMutability::Pure)),
|
magicVarDecl("require", TypeProvider::functionType(strings{"bool", "string memory"}, strings{}, FunctionType::Kind::Require, false, StateMutability::Pure)),
|
||||||
make_shared<MagicVariableDeclaration>("sha3", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::KECCAK256, false, StateMutability::Pure)),
|
magicVarDecl("revert", TypeProvider::functionType(strings(), strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)),
|
||||||
make_shared<MagicVariableDeclaration>("suicide", make_shared<FunctionType>(strings{"address payable"}, strings{}, FunctionType::Kind::Selfdestruct)),
|
magicVarDecl("revert", TypeProvider::functionType(strings{"string memory"}, strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)),
|
||||||
make_shared<MagicVariableDeclaration>("tx", make_shared<MagicType>(MagicType::Kind::Transaction)),
|
magicVarDecl("ripemd160", TypeProvider::functionType(strings{"bytes memory"}, strings{"bytes20"}, FunctionType::Kind::RIPEMD160, false, StateMutability::Pure)),
|
||||||
make_shared<MagicVariableDeclaration>("type", make_shared<FunctionType>(
|
magicVarDecl("selfdestruct", TypeProvider::functionType(strings{"address payable"}, strings{}, FunctionType::Kind::Selfdestruct)),
|
||||||
|
magicVarDecl("sha256", TypeProvider::functionType(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::SHA256, false, StateMutability::Pure)),
|
||||||
|
magicVarDecl("sha3", TypeProvider::functionType(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::KECCAK256, false, StateMutability::Pure)),
|
||||||
|
magicVarDecl("suicide", TypeProvider::functionType(strings{"address payable"}, strings{}, FunctionType::Kind::Selfdestruct)),
|
||||||
|
magicVarDecl("tx", TypeProvider::magicType(MagicType::Kind::Transaction)),
|
||||||
|
magicVarDecl("type", TypeProvider::functionType(
|
||||||
strings{"address"} /* accepts any contract type, handled by the type checker */,
|
strings{"address"} /* accepts any contract type, handled by the type checker */,
|
||||||
strings{} /* returns a MagicType, handled by the type checker */,
|
strings{} /* returns a MagicType, handled by the type checker */,
|
||||||
FunctionType::Kind::MetaType,
|
FunctionType::Kind::MetaType,
|
||||||
false,
|
false,
|
||||||
StateMutability::Pure
|
StateMutability::Pure
|
||||||
)),
|
)),
|
||||||
})
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalContext::GlobalContext(): m_magicVariables{constructMagicVariables()}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,7 +99,7 @@ vector<Declaration const*> GlobalContext::declarations() const
|
|||||||
MagicVariableDeclaration const* GlobalContext::currentThis() const
|
MagicVariableDeclaration const* GlobalContext::currentThis() const
|
||||||
{
|
{
|
||||||
if (!m_thisPointer[m_currentContract])
|
if (!m_thisPointer[m_currentContract])
|
||||||
m_thisPointer[m_currentContract] = make_shared<MagicVariableDeclaration>("this", make_shared<ContractType>(*m_currentContract));
|
m_thisPointer[m_currentContract] = make_shared<MagicVariableDeclaration>("this", TypeProvider::contractType(*m_currentContract));
|
||||||
return m_thisPointer[m_currentContract].get();
|
return m_thisPointer[m_currentContract].get();
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -98,7 +107,7 @@ MagicVariableDeclaration const* GlobalContext::currentThis() const
|
|||||||
MagicVariableDeclaration const* GlobalContext::currentSuper() const
|
MagicVariableDeclaration const* GlobalContext::currentSuper() const
|
||||||
{
|
{
|
||||||
if (!m_superPointer[m_currentContract])
|
if (!m_superPointer[m_currentContract])
|
||||||
m_superPointer[m_currentContract] = make_shared<MagicVariableDeclaration>("super", make_shared<ContractType>(*m_currentContract, true));
|
m_superPointer[m_currentContract] = make_shared<MagicVariableDeclaration>("super", TypeProvider::contractType(*m_currentContract, true));
|
||||||
return m_superPointer[m_currentContract].get();
|
return m_superPointer[m_currentContract].get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,7 +228,7 @@ vector<Declaration const*> NameAndTypeResolver::cleanedDeclarations(
|
|||||||
uniqueFunctions.end(),
|
uniqueFunctions.end(),
|
||||||
[&](Declaration const* d)
|
[&](Declaration const* d)
|
||||||
{
|
{
|
||||||
shared_ptr<FunctionType const> newFunctionType { d->functionType(false) };
|
FunctionType const* newFunctionType = d->functionType(false);
|
||||||
if (!newFunctionType)
|
if (!newFunctionType)
|
||||||
newFunctionType = d->functionType(true);
|
newFunctionType = d->functionType(true);
|
||||||
return newFunctionType && functionType->hasEqualParameterTypes(*newFunctionType);
|
return newFunctionType && functionType->hasEqualParameterTypes(*newFunctionType);
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include <libsolidity/analysis/NameAndTypeResolver.h>
|
#include <libsolidity/analysis/NameAndTypeResolver.h>
|
||||||
#include <libsolidity/analysis/ConstantEvaluator.h>
|
#include <libsolidity/analysis/ConstantEvaluator.h>
|
||||||
#include <libsolidity/ast/AST.h>
|
#include <libsolidity/ast/AST.h>
|
||||||
|
#include <libsolidity/ast/TypeProvider.h>
|
||||||
|
|
||||||
#include <libyul/AsmAnalysis.h>
|
#include <libyul/AsmAnalysis.h>
|
||||||
#include <libyul/AsmAnalysisInfo.h>
|
#include <libyul/AsmAnalysisInfo.h>
|
||||||
@ -120,7 +121,7 @@ bool ReferencesResolver::visit(ElementaryTypeName const& _typeName)
|
|||||||
{
|
{
|
||||||
if (!_typeName.annotation().type)
|
if (!_typeName.annotation().type)
|
||||||
{
|
{
|
||||||
_typeName.annotation().type = Type::fromElementaryTypeName(_typeName.typeName());
|
_typeName.annotation().type = TypeProvider::fromElementaryTypeName(_typeName.typeName());
|
||||||
if (_typeName.stateMutability().is_initialized())
|
if (_typeName.stateMutability().is_initialized())
|
||||||
{
|
{
|
||||||
// for non-address types this was already caught by the parser
|
// for non-address types this was already caught by the parser
|
||||||
@ -128,8 +129,10 @@ bool ReferencesResolver::visit(ElementaryTypeName const& _typeName)
|
|||||||
switch(*_typeName.stateMutability())
|
switch(*_typeName.stateMutability())
|
||||||
{
|
{
|
||||||
case StateMutability::Payable:
|
case StateMutability::Payable:
|
||||||
|
_typeName.annotation().type = TypeProvider::payableAddressType();
|
||||||
|
break;
|
||||||
case StateMutability::NonPayable:
|
case StateMutability::NonPayable:
|
||||||
_typeName.annotation().type = make_shared<AddressType>(*_typeName.stateMutability());
|
_typeName.annotation().type = TypeProvider::addressType();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
m_errorReporter.typeError(
|
m_errorReporter.typeError(
|
||||||
@ -179,14 +182,14 @@ void ReferencesResolver::endVisit(UserDefinedTypeName const& _typeName)
|
|||||||
_typeName.annotation().referencedDeclaration = declaration;
|
_typeName.annotation().referencedDeclaration = declaration;
|
||||||
|
|
||||||
if (StructDefinition const* structDef = dynamic_cast<StructDefinition const*>(declaration))
|
if (StructDefinition const* structDef = dynamic_cast<StructDefinition const*>(declaration))
|
||||||
_typeName.annotation().type = make_shared<StructType>(*structDef);
|
_typeName.annotation().type = TypeProvider::structType(*structDef, DataLocation::Storage);
|
||||||
else if (EnumDefinition const* enumDef = dynamic_cast<EnumDefinition const*>(declaration))
|
else if (EnumDefinition const* enumDef = dynamic_cast<EnumDefinition const*>(declaration))
|
||||||
_typeName.annotation().type = make_shared<EnumType>(*enumDef);
|
_typeName.annotation().type = TypeProvider::enumType(*enumDef);
|
||||||
else if (ContractDefinition const* contract = dynamic_cast<ContractDefinition const*>(declaration))
|
else if (ContractDefinition const* contract = dynamic_cast<ContractDefinition const*>(declaration))
|
||||||
_typeName.annotation().type = make_shared<ContractType>(*contract);
|
_typeName.annotation().type = TypeProvider::contractType(*contract);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_typeName.annotation().type = make_shared<TupleType>();
|
_typeName.annotation().type = TypeProvider::emptyTupleType();
|
||||||
typeError(_typeName.location(), "Name has to refer to a struct, enum or contract.");
|
typeError(_typeName.location(), "Name has to refer to a struct, enum or contract.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -220,7 +223,7 @@ void ReferencesResolver::endVisit(FunctionTypeName const& _typeName)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_typeName.annotation().type = make_shared<FunctionType>(_typeName);
|
_typeName.annotation().type = TypeProvider::functionType(_typeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReferencesResolver::endVisit(Mapping const& _typeName)
|
void ReferencesResolver::endVisit(Mapping const& _typeName)
|
||||||
@ -231,7 +234,7 @@ void ReferencesResolver::endVisit(Mapping const& _typeName)
|
|||||||
keyType = ReferenceType::copyForLocationIfReference(DataLocation::Memory, keyType);
|
keyType = ReferenceType::copyForLocationIfReference(DataLocation::Memory, keyType);
|
||||||
// Convert value type to storage reference.
|
// Convert value type to storage reference.
|
||||||
valueType = ReferenceType::copyForLocationIfReference(DataLocation::Storage, valueType);
|
valueType = ReferenceType::copyForLocationIfReference(DataLocation::Storage, valueType);
|
||||||
_typeName.annotation().type = make_shared<MappingType>(keyType, valueType);
|
_typeName.annotation().type = TypeProvider::mappingType(keyType, valueType);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReferencesResolver::endVisit(ArrayTypeName const& _typeName)
|
void ReferencesResolver::endVisit(ArrayTypeName const& _typeName)
|
||||||
@ -249,7 +252,7 @@ void ReferencesResolver::endVisit(ArrayTypeName const& _typeName)
|
|||||||
TypePointer& lengthTypeGeneric = length->annotation().type;
|
TypePointer& lengthTypeGeneric = length->annotation().type;
|
||||||
if (!lengthTypeGeneric)
|
if (!lengthTypeGeneric)
|
||||||
lengthTypeGeneric = ConstantEvaluator(m_errorReporter).evaluate(*length);
|
lengthTypeGeneric = ConstantEvaluator(m_errorReporter).evaluate(*length);
|
||||||
RationalNumberType const* lengthType = dynamic_cast<RationalNumberType const*>(lengthTypeGeneric.get());
|
RationalNumberType const* lengthType = dynamic_cast<RationalNumberType const*>(lengthTypeGeneric);
|
||||||
if (!lengthType || !lengthType->mobileType())
|
if (!lengthType || !lengthType->mobileType())
|
||||||
fatalTypeError(length->location(), "Invalid array length, expected integer literal or constant expression.");
|
fatalTypeError(length->location(), "Invalid array length, expected integer literal or constant expression.");
|
||||||
else if (lengthType->isZero())
|
else if (lengthType->isZero())
|
||||||
@ -259,10 +262,10 @@ void ReferencesResolver::endVisit(ArrayTypeName const& _typeName)
|
|||||||
else if (lengthType->isNegative())
|
else if (lengthType->isNegative())
|
||||||
fatalTypeError(length->location(), "Array with negative length specified.");
|
fatalTypeError(length->location(), "Array with negative length specified.");
|
||||||
else
|
else
|
||||||
_typeName.annotation().type = make_shared<ArrayType>(DataLocation::Storage, baseType, lengthType->literalValue(nullptr));
|
_typeName.annotation().type = TypeProvider::arrayType(DataLocation::Storage, baseType, lengthType->literalValue(nullptr));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
_typeName.annotation().type = make_shared<ArrayType>(DataLocation::Storage, baseType);
|
_typeName.annotation().type = TypeProvider::arrayType(DataLocation::Storage, baseType);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly)
|
bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly)
|
||||||
@ -436,10 +439,10 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
|
|||||||
}
|
}
|
||||||
|
|
||||||
TypePointer type = _variable.typeName()->annotation().type;
|
TypePointer type = _variable.typeName()->annotation().type;
|
||||||
if (auto ref = dynamic_cast<ReferenceType const*>(type.get()))
|
if (auto ref = dynamic_cast<ReferenceType const*>(type))
|
||||||
{
|
{
|
||||||
bool isPointer = !_variable.isStateVariable();
|
bool isPointer = !_variable.isStateVariable();
|
||||||
type = ref->copyForLocation(typeLoc, isPointer);
|
type = TypeProvider::withLocation(ref, typeLoc, isPointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
_variable.annotation().type = type;
|
_variable.annotation().type = type;
|
||||||
|
@ -190,7 +190,7 @@ bool StaticAnalyzer::visit(ExpressionStatement const& _statement)
|
|||||||
|
|
||||||
bool StaticAnalyzer::visit(MemberAccess const& _memberAccess)
|
bool StaticAnalyzer::visit(MemberAccess const& _memberAccess)
|
||||||
{
|
{
|
||||||
if (MagicType const* type = dynamic_cast<MagicType const*>(_memberAccess.expression().annotation().type.get()))
|
if (MagicType const* type = dynamic_cast<MagicType const*>(_memberAccess.expression().annotation().type))
|
||||||
{
|
{
|
||||||
if (type->kind() == MagicType::Kind::Message && _memberAccess.memberName() == "gas")
|
if (type->kind() == MagicType::Kind::Message && _memberAccess.memberName() == "gas")
|
||||||
m_errorReporter.typeError(
|
m_errorReporter.typeError(
|
||||||
@ -217,7 +217,7 @@ bool StaticAnalyzer::visit(MemberAccess const& _memberAccess)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (_memberAccess.memberName() == "callcode")
|
if (_memberAccess.memberName() == "callcode")
|
||||||
if (auto const* type = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type.get()))
|
if (auto const* type = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type))
|
||||||
if (type->kind() == FunctionType::Kind::BareCallCode)
|
if (type->kind() == FunctionType::Kind::BareCallCode)
|
||||||
m_errorReporter.typeError(
|
m_errorReporter.typeError(
|
||||||
_memberAccess.location(),
|
_memberAccess.location(),
|
||||||
@ -278,7 +278,7 @@ bool StaticAnalyzer::visit(BinaryOperation const& _operation)
|
|||||||
_operation.rightExpression().annotation().isPure &&
|
_operation.rightExpression().annotation().isPure &&
|
||||||
(_operation.getOperator() == Token::Div || _operation.getOperator() == Token::Mod)
|
(_operation.getOperator() == Token::Div || _operation.getOperator() == Token::Mod)
|
||||||
)
|
)
|
||||||
if (auto rhs = dynamic_pointer_cast<RationalNumberType const>(
|
if (auto rhs = dynamic_cast<RationalNumberType const*>(
|
||||||
ConstantEvaluator(m_errorReporter).evaluate(_operation.rightExpression())
|
ConstantEvaluator(m_errorReporter).evaluate(_operation.rightExpression())
|
||||||
))
|
))
|
||||||
if (rhs->isZero())
|
if (rhs->isZero())
|
||||||
@ -294,13 +294,13 @@ bool StaticAnalyzer::visit(FunctionCall const& _functionCall)
|
|||||||
{
|
{
|
||||||
if (_functionCall.annotation().kind == FunctionCallKind::FunctionCall)
|
if (_functionCall.annotation().kind == FunctionCallKind::FunctionCall)
|
||||||
{
|
{
|
||||||
auto functionType = dynamic_pointer_cast<FunctionType const>(_functionCall.expression().annotation().type);
|
auto functionType = dynamic_cast<FunctionType const*>(_functionCall.expression().annotation().type);
|
||||||
solAssert(functionType, "");
|
solAssert(functionType, "");
|
||||||
if (functionType->kind() == FunctionType::Kind::AddMod || functionType->kind() == FunctionType::Kind::MulMod)
|
if (functionType->kind() == FunctionType::Kind::AddMod || functionType->kind() == FunctionType::Kind::MulMod)
|
||||||
{
|
{
|
||||||
solAssert(_functionCall.arguments().size() == 3, "");
|
solAssert(_functionCall.arguments().size() == 3, "");
|
||||||
if (_functionCall.arguments()[2]->annotation().isPure)
|
if (_functionCall.arguments()[2]->annotation().isPure)
|
||||||
if (auto lastArg = dynamic_pointer_cast<RationalNumberType const>(
|
if (auto lastArg = dynamic_cast<RationalNumberType const*>(
|
||||||
ConstantEvaluator(m_errorReporter).evaluate(*(_functionCall.arguments())[2])
|
ConstantEvaluator(m_errorReporter).evaluate(*(_functionCall.arguments())[2])
|
||||||
))
|
))
|
||||||
if (lastArg->isZero())
|
if (lastArg->isZero())
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include <libsolidity/analysis/TypeChecker.h>
|
#include <libsolidity/analysis/TypeChecker.h>
|
||||||
#include <libsolidity/ast/AST.h>
|
#include <libsolidity/ast/AST.h>
|
||||||
|
#include <libsolidity/ast/TypeProvider.h>
|
||||||
|
|
||||||
#include <libyul/AsmAnalysis.h>
|
#include <libyul/AsmAnalysis.h>
|
||||||
#include <libyul/AsmAnalysisInfo.h>
|
#include <libyul/AsmAnalysisInfo.h>
|
||||||
@ -107,7 +108,7 @@ void TypeChecker::checkDoubleStorageAssignment(Assignment const& _assignment)
|
|||||||
size_t toStorageCopies = 0;
|
size_t toStorageCopies = 0;
|
||||||
for (size_t i = 0; i < lhs.components().size(); ++i)
|
for (size_t i = 0; i < lhs.components().size(); ++i)
|
||||||
{
|
{
|
||||||
ReferenceType const* ref = dynamic_cast<ReferenceType const*>(lhs.components()[i].get());
|
ReferenceType const* ref = dynamic_cast<ReferenceType const*>(lhs.components()[i]);
|
||||||
if (!ref || !ref->dataStoredIn(DataLocation::Storage) || ref->isPointer())
|
if (!ref || !ref->dataStoredIn(DataLocation::Storage) || ref->isPointer())
|
||||||
continue;
|
continue;
|
||||||
toStorageCopies++;
|
toStorageCopies++;
|
||||||
@ -137,7 +138,7 @@ TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall c
|
|||||||
|
|
||||||
if (arguments.size() >= 1)
|
if (arguments.size() >= 1)
|
||||||
{
|
{
|
||||||
BoolResult result = type(*arguments.front())->isImplicitlyConvertibleTo(ArrayType::bytesMemory());
|
BoolResult result = type(*arguments.front())->isImplicitlyConvertibleTo(*TypeProvider::bytesMemoryType());
|
||||||
|
|
||||||
if (!result)
|
if (!result)
|
||||||
m_errorReporter.typeErrorConcatenateDescriptions(
|
m_errorReporter.typeErrorConcatenateDescriptions(
|
||||||
@ -169,17 +170,17 @@ TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall c
|
|||||||
for (auto const& typeArgument: tupleExpression->components())
|
for (auto const& typeArgument: tupleExpression->components())
|
||||||
{
|
{
|
||||||
solAssert(typeArgument, "");
|
solAssert(typeArgument, "");
|
||||||
if (TypeType const* argTypeType = dynamic_cast<TypeType const*>(type(*typeArgument).get()))
|
if (TypeType const* argTypeType = dynamic_cast<TypeType const*>(type(*typeArgument)))
|
||||||
{
|
{
|
||||||
TypePointer actualType = argTypeType->actualType();
|
TypePointer actualType = argTypeType->actualType();
|
||||||
solAssert(actualType, "");
|
solAssert(actualType, "");
|
||||||
// We force memory because the parser currently cannot handle
|
// We force memory because the parser currently cannot handle
|
||||||
// data locations. Furthermore, storage can be a little dangerous and
|
// data locations. Furthermore, storage can be a little dangerous and
|
||||||
// calldata is not really implemented anyway.
|
// calldata is not really implemented anyway.
|
||||||
actualType = ReferenceType::copyForLocationIfReference(DataLocation::Memory, actualType);
|
actualType = TypeProvider::withLocationIfReference(DataLocation::Memory, actualType);
|
||||||
// We force address payable for address types.
|
// We force address payable for address types.
|
||||||
if (actualType->category() == Type::Category::Address)
|
if (actualType->category() == Type::Category::Address)
|
||||||
actualType = make_shared<AddressType>(StateMutability::Payable);
|
actualType = TypeProvider::payableAddressType();
|
||||||
solAssert(
|
solAssert(
|
||||||
!actualType->dataStoredIn(DataLocation::CallData) &&
|
!actualType->dataStoredIn(DataLocation::CallData) &&
|
||||||
!actualType->dataStoredIn(DataLocation::Storage),
|
!actualType->dataStoredIn(DataLocation::Storage),
|
||||||
@ -195,7 +196,7 @@ TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall c
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(typeArgument->location(), "Argument has to be a type name.");
|
m_errorReporter.typeError(typeArgument->location(), "Argument has to be a type name.");
|
||||||
components.push_back(make_shared<TupleType>());
|
components.push_back(TypeProvider::emptyTupleType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return components;
|
return components;
|
||||||
@ -303,12 +304,12 @@ bool TypeChecker::visit(StructDefinition const& _struct)
|
|||||||
|
|
||||||
for (ASTPointer<VariableDeclaration> const& member: _struct.members())
|
for (ASTPointer<VariableDeclaration> const& member: _struct.members())
|
||||||
{
|
{
|
||||||
Type const* memberType = type(*member).get();
|
Type const* memberType = type(*member);
|
||||||
while (auto arrayType = dynamic_cast<ArrayType const*>(memberType))
|
while (auto arrayType = dynamic_cast<ArrayType const*>(memberType))
|
||||||
{
|
{
|
||||||
if (arrayType->isDynamicallySized())
|
if (arrayType->isDynamicallySized())
|
||||||
break;
|
break;
|
||||||
memberType = arrayType->baseType().get();
|
memberType = arrayType->baseType();
|
||||||
}
|
}
|
||||||
if (auto structType = dynamic_cast<StructType const*>(memberType))
|
if (auto structType = dynamic_cast<StructType const*>(memberType))
|
||||||
if (_cycleDetector.run(structType->structDefinition()))
|
if (_cycleDetector.run(structType->structDefinition()))
|
||||||
@ -359,7 +360,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
|
|||||||
{
|
{
|
||||||
auto iType = type(var)->interfaceType(isLibraryFunction);
|
auto iType = type(var)->interfaceType(isLibraryFunction);
|
||||||
|
|
||||||
if (!iType.get())
|
if (!iType)
|
||||||
{
|
{
|
||||||
solAssert(!iType.message().empty(), "Expected detailed error message!");
|
solAssert(!iType.message().empty(), "Expected detailed error message!");
|
||||||
m_errorReporter.fatalTypeError(var.location(), iType.message());
|
m_errorReporter.fatalTypeError(var.location(), iType.message());
|
||||||
@ -455,7 +456,7 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
|
|||||||
if (!_variable.type()->isValueType())
|
if (!_variable.type()->isValueType())
|
||||||
{
|
{
|
||||||
bool allowed = false;
|
bool allowed = false;
|
||||||
if (auto arrayType = dynamic_cast<ArrayType const*>(_variable.type().get()))
|
if (auto arrayType = dynamic_cast<ArrayType const*>(_variable.type()))
|
||||||
allowed = arrayType->isByteArray();
|
allowed = arrayType->isByteArray();
|
||||||
if (!allowed)
|
if (!allowed)
|
||||||
m_errorReporter.typeError(_variable.location(), "Constants of non-value type not yet implemented.");
|
m_errorReporter.typeError(_variable.location(), "Constants of non-value type not yet implemented.");
|
||||||
@ -498,7 +499,7 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
|
|||||||
switch (varType->category())
|
switch (varType->category())
|
||||||
{
|
{
|
||||||
case Type::Category::Array:
|
case Type::Category::Array:
|
||||||
if (auto arrayType = dynamic_cast<ArrayType const*>(varType.get()))
|
if (auto arrayType = dynamic_cast<ArrayType const*>(varType))
|
||||||
if (
|
if (
|
||||||
((arrayType->location() == DataLocation::Memory) ||
|
((arrayType->location() == DataLocation::Memory) ||
|
||||||
(arrayType->location() == DataLocation::CallData)) &&
|
(arrayType->location() == DataLocation::CallData)) &&
|
||||||
@ -584,7 +585,7 @@ bool TypeChecker::visit(EventDefinition const& _eventDef)
|
|||||||
numIndexed++;
|
numIndexed++;
|
||||||
if (!type(*var)->canLiveOutsideStorage())
|
if (!type(*var)->canLiveOutsideStorage())
|
||||||
m_errorReporter.typeError(var->location(), "Type is required to live outside storage.");
|
m_errorReporter.typeError(var->location(), "Type is required to live outside storage.");
|
||||||
if (!type(*var)->interfaceType(false).get())
|
if (!type(*var)->interfaceType(false))
|
||||||
m_errorReporter.typeError(var->location(), "Internal or recursive type is not allowed as event parameter type.");
|
m_errorReporter.typeError(var->location(), "Internal or recursive type is not allowed as event parameter type.");
|
||||||
if (
|
if (
|
||||||
!_eventDef.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2) &&
|
!_eventDef.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2) &&
|
||||||
@ -607,7 +608,7 @@ void TypeChecker::endVisit(FunctionTypeName const& _funType)
|
|||||||
{
|
{
|
||||||
FunctionType const& fun = dynamic_cast<FunctionType const&>(*_funType.annotation().type);
|
FunctionType const& fun = dynamic_cast<FunctionType const&>(*_funType.annotation().type);
|
||||||
if (fun.kind() == FunctionType::Kind::External)
|
if (fun.kind() == FunctionType::Kind::External)
|
||||||
solAssert(fun.interfaceType(false).get(), "External function type uses internal types.");
|
solAssert(fun.interfaceType(false), "External function type uses internal types.");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||||
@ -716,7 +717,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
|
|
||||||
bool TypeChecker::visit(IfStatement const& _ifStatement)
|
bool TypeChecker::visit(IfStatement const& _ifStatement)
|
||||||
{
|
{
|
||||||
expectType(_ifStatement.condition(), BoolType());
|
expectType(_ifStatement.condition(), *TypeProvider::boolType());
|
||||||
_ifStatement.trueStatement().accept(*this);
|
_ifStatement.trueStatement().accept(*this);
|
||||||
if (_ifStatement.falseStatement())
|
if (_ifStatement.falseStatement())
|
||||||
_ifStatement.falseStatement()->accept(*this);
|
_ifStatement.falseStatement()->accept(*this);
|
||||||
@ -725,7 +726,7 @@ bool TypeChecker::visit(IfStatement const& _ifStatement)
|
|||||||
|
|
||||||
bool TypeChecker::visit(WhileStatement const& _whileStatement)
|
bool TypeChecker::visit(WhileStatement const& _whileStatement)
|
||||||
{
|
{
|
||||||
expectType(_whileStatement.condition(), BoolType());
|
expectType(_whileStatement.condition(), *TypeProvider::boolType());
|
||||||
_whileStatement.body().accept(*this);
|
_whileStatement.body().accept(*this);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -735,7 +736,7 @@ bool TypeChecker::visit(ForStatement const& _forStatement)
|
|||||||
if (_forStatement.initializationExpression())
|
if (_forStatement.initializationExpression())
|
||||||
_forStatement.initializationExpression()->accept(*this);
|
_forStatement.initializationExpression()->accept(*this);
|
||||||
if (_forStatement.condition())
|
if (_forStatement.condition())
|
||||||
expectType(*_forStatement.condition(), BoolType());
|
expectType(*_forStatement.condition(), *TypeProvider::boolType());
|
||||||
if (_forStatement.loopExpression())
|
if (_forStatement.loopExpression())
|
||||||
_forStatement.loopExpression()->accept(*this);
|
_forStatement.loopExpression()->accept(*this);
|
||||||
_forStatement.body().accept(*this);
|
_forStatement.body().accept(*this);
|
||||||
@ -759,7 +760,7 @@ void TypeChecker::endVisit(Return const& _return)
|
|||||||
TypePointers returnTypes;
|
TypePointers returnTypes;
|
||||||
for (auto const& var: params->parameters())
|
for (auto const& var: params->parameters())
|
||||||
returnTypes.push_back(type(*var));
|
returnTypes.push_back(type(*var));
|
||||||
if (auto tupleType = dynamic_cast<TupleType const*>(type(*_return.expression()).get()))
|
if (auto tupleType = dynamic_cast<TupleType const*>(type(*_return.expression())))
|
||||||
{
|
{
|
||||||
if (tupleType->components().size() != params->parameters().size())
|
if (tupleType->components().size() != params->parameters().size())
|
||||||
m_errorReporter.typeError(_return.location(), "Different number of arguments in return statement than in returns declaration.");
|
m_errorReporter.typeError(_return.location(), "Different number of arguments in return statement than in returns declaration.");
|
||||||
@ -841,7 +842,7 @@ bool typeCanBeExpressed(vector<ASTPointer<VariableDeclaration>> const& decls)
|
|||||||
if (!decl->annotation().type)
|
if (!decl->annotation().type)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (auto functionType = dynamic_cast<FunctionType const*>(decl->annotation().type.get()))
|
if (auto functionType = dynamic_cast<FunctionType const*>(decl->annotation().type))
|
||||||
if (
|
if (
|
||||||
functionType->kind() != FunctionType::Kind::Internal &&
|
functionType->kind() != FunctionType::Kind::Internal &&
|
||||||
functionType->kind() != FunctionType::Kind::External
|
functionType->kind() != FunctionType::Kind::External
|
||||||
@ -878,7 +879,7 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
|
|||||||
if (!varDecl.annotation().type)
|
if (!varDecl.annotation().type)
|
||||||
m_errorReporter.fatalTypeError(_statement.location(), "Use of the \"var\" keyword is disallowed.");
|
m_errorReporter.fatalTypeError(_statement.location(), "Use of the \"var\" keyword is disallowed.");
|
||||||
|
|
||||||
if (auto ref = dynamic_cast<ReferenceType const*>(type(varDecl).get()))
|
if (auto ref = dynamic_cast<ReferenceType const*>(type(varDecl)))
|
||||||
{
|
{
|
||||||
if (ref->dataStoredIn(DataLocation::Storage))
|
if (ref->dataStoredIn(DataLocation::Storage))
|
||||||
{
|
{
|
||||||
@ -888,7 +889,7 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
|
|||||||
m_errorReporter.declarationError(varDecl.location(), errorText);
|
m_errorReporter.declarationError(varDecl.location(), errorText);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (dynamic_cast<MappingType const*>(type(varDecl).get()))
|
else if (dynamic_cast<MappingType const*>(type(varDecl)))
|
||||||
m_errorReporter.typeError(
|
m_errorReporter.typeError(
|
||||||
varDecl.location(),
|
varDecl.location(),
|
||||||
"Uninitialized mapping. Mappings cannot be created dynamically, you have to assign them from a state variable."
|
"Uninitialized mapping. Mappings cannot be created dynamically, you have to assign them from a state variable."
|
||||||
@ -902,7 +903,7 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
|
|||||||
|
|
||||||
_statement.initialValue()->accept(*this);
|
_statement.initialValue()->accept(*this);
|
||||||
TypePointers valueTypes;
|
TypePointers valueTypes;
|
||||||
if (auto tupleType = dynamic_cast<TupleType const*>(type(*_statement.initialValue()).get()))
|
if (auto tupleType = dynamic_cast<TupleType const*>(type(*_statement.initialValue())))
|
||||||
valueTypes = tupleType->components();
|
valueTypes = tupleType->components();
|
||||||
else
|
else
|
||||||
valueTypes = TypePointers{type(*_statement.initialValue())};
|
valueTypes = TypePointers{type(*_statement.initialValue())};
|
||||||
@ -950,13 +951,13 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
|
|||||||
else
|
else
|
||||||
solAssert(false, "");
|
solAssert(false, "");
|
||||||
}
|
}
|
||||||
else if (*var.annotation().type == TupleType())
|
else if (*var.annotation().type == *TypeProvider::emptyTupleType())
|
||||||
solAssert(false, "Cannot declare variable with void (empty tuple) type.");
|
solAssert(false, "Cannot declare variable with void (empty tuple) type.");
|
||||||
else if (valueComponentType->category() == Type::Category::RationalNumber)
|
else if (valueComponentType->category() == Type::Category::RationalNumber)
|
||||||
{
|
{
|
||||||
string typeName = var.annotation().type->toString(true);
|
string typeName = var.annotation().type->toString(true);
|
||||||
string extension;
|
string extension;
|
||||||
if (auto type = dynamic_cast<IntegerType const*>(var.annotation().type.get()))
|
if (auto type = dynamic_cast<IntegerType const*>(var.annotation().type))
|
||||||
{
|
{
|
||||||
unsigned numBits = type->numBits();
|
unsigned numBits = type->numBits();
|
||||||
bool isSigned = type->isSigned();
|
bool isSigned = type->isSigned();
|
||||||
@ -974,7 +975,7 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
|
|||||||
extension = ", which can hold values between " + minValue + " and " + maxValue;
|
extension = ", which can hold values between " + minValue + " and " + maxValue;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
solAssert(dynamic_cast<FixedPointType const*>(var.annotation().type.get()), "Unknown type.");
|
solAssert(dynamic_cast<FixedPointType const*>(var.annotation().type), "Unknown type.");
|
||||||
}
|
}
|
||||||
|
|
||||||
var.accept(*this);
|
var.accept(*this);
|
||||||
@ -1054,7 +1055,7 @@ void TypeChecker::endVisit(ExpressionStatement const& _statement)
|
|||||||
|
|
||||||
if (auto call = dynamic_cast<FunctionCall const*>(&_statement.expression()))
|
if (auto call = dynamic_cast<FunctionCall const*>(&_statement.expression()))
|
||||||
{
|
{
|
||||||
if (auto callType = dynamic_cast<FunctionType const*>(type(call->expression()).get()))
|
if (auto callType = dynamic_cast<FunctionType const*>(type(call->expression())))
|
||||||
{
|
{
|
||||||
auto kind = callType->kind();
|
auto kind = callType->kind();
|
||||||
if (
|
if (
|
||||||
@ -1072,7 +1073,7 @@ void TypeChecker::endVisit(ExpressionStatement const& _statement)
|
|||||||
|
|
||||||
bool TypeChecker::visit(Conditional const& _conditional)
|
bool TypeChecker::visit(Conditional const& _conditional)
|
||||||
{
|
{
|
||||||
expectType(_conditional.condition(), BoolType());
|
expectType(_conditional.condition(), *TypeProvider::boolType());
|
||||||
|
|
||||||
_conditional.trueExpression().accept(*this);
|
_conditional.trueExpression().accept(*this);
|
||||||
_conditional.falseExpression().accept(*this);
|
_conditional.falseExpression().accept(*this);
|
||||||
@ -1080,7 +1081,7 @@ bool TypeChecker::visit(Conditional const& _conditional)
|
|||||||
TypePointer trueType = type(_conditional.trueExpression())->mobileType();
|
TypePointer trueType = type(_conditional.trueExpression())->mobileType();
|
||||||
TypePointer falseType = type(_conditional.falseExpression())->mobileType();
|
TypePointer falseType = type(_conditional.falseExpression())->mobileType();
|
||||||
|
|
||||||
TypePointer commonType;
|
TypePointer commonType = nullptr;
|
||||||
|
|
||||||
if (!trueType)
|
if (!trueType)
|
||||||
m_errorReporter.typeError(_conditional.trueExpression().location(), "Invalid mobile type in true expression.");
|
m_errorReporter.typeError(_conditional.trueExpression().location(), "Invalid mobile type in true expression.");
|
||||||
@ -1134,7 +1135,7 @@ void TypeChecker::checkExpressionAssignment(Type const& _type, Expression const&
|
|||||||
if (auto const* tupleExpression = dynamic_cast<TupleExpression const*>(&_expression))
|
if (auto const* tupleExpression = dynamic_cast<TupleExpression const*>(&_expression))
|
||||||
{
|
{
|
||||||
auto const* tupleType = dynamic_cast<TupleType const*>(&_type);
|
auto const* tupleType = dynamic_cast<TupleType const*>(&_type);
|
||||||
auto const& types = tupleType ? tupleType->components() : vector<TypePointer> { _type.shared_from_this() };
|
auto const& types = tupleType ? tupleType->components() : vector<TypePointer> { &_type };
|
||||||
|
|
||||||
solAssert(
|
solAssert(
|
||||||
tupleExpression->components().size() == types.size() || m_errorReporter.hasErrors(),
|
tupleExpression->components().size() == types.size() || m_errorReporter.hasErrors(),
|
||||||
@ -1168,7 +1169,7 @@ bool TypeChecker::visit(Assignment const& _assignment)
|
|||||||
|
|
||||||
checkExpressionAssignment(*t, _assignment.leftHandSide());
|
checkExpressionAssignment(*t, _assignment.leftHandSide());
|
||||||
|
|
||||||
if (TupleType const* tupleType = dynamic_cast<TupleType const*>(t.get()))
|
if (TupleType const* tupleType = dynamic_cast<TupleType const*>(t))
|
||||||
{
|
{
|
||||||
if (_assignment.assignmentOperator() != Token::Assign)
|
if (_assignment.assignmentOperator() != Token::Assign)
|
||||||
m_errorReporter.typeError(
|
m_errorReporter.typeError(
|
||||||
@ -1176,12 +1177,12 @@ bool TypeChecker::visit(Assignment const& _assignment)
|
|||||||
"Compound assignment is not allowed for tuple types."
|
"Compound assignment is not allowed for tuple types."
|
||||||
);
|
);
|
||||||
// Sequenced assignments of tuples is not valid, make the result a "void" type.
|
// Sequenced assignments of tuples is not valid, make the result a "void" type.
|
||||||
_assignment.annotation().type = make_shared<TupleType>();
|
_assignment.annotation().type = TypeProvider::emptyTupleType();
|
||||||
|
|
||||||
expectType(_assignment.rightHandSide(), *tupleType);
|
expectType(_assignment.rightHandSide(), *tupleType);
|
||||||
|
|
||||||
// expectType does not cause fatal errors, so we have to check again here.
|
// expectType does not cause fatal errors, so we have to check again here.
|
||||||
if (dynamic_cast<TupleType const*>(type(_assignment.rightHandSide()).get()))
|
if (dynamic_cast<TupleType const*>(type(_assignment.rightHandSide())))
|
||||||
checkDoubleStorageAssignment(_assignment);
|
checkDoubleStorageAssignment(_assignment);
|
||||||
}
|
}
|
||||||
else if (_assignment.assignmentOperator() == Token::Assign)
|
else if (_assignment.assignmentOperator() == Token::Assign)
|
||||||
@ -1228,14 +1229,14 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
|
|||||||
if (components.size() == 1)
|
if (components.size() == 1)
|
||||||
_tuple.annotation().type = type(*components[0]);
|
_tuple.annotation().type = type(*components[0]);
|
||||||
else
|
else
|
||||||
_tuple.annotation().type = make_shared<TupleType>(types);
|
_tuple.annotation().type = TypeProvider::tupleType(move(types));
|
||||||
// If some of the components are not LValues, the error is reported above.
|
// If some of the components are not LValues, the error is reported above.
|
||||||
_tuple.annotation().isLValue = true;
|
_tuple.annotation().isLValue = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bool isPure = true;
|
bool isPure = true;
|
||||||
TypePointer inlineArrayType;
|
TypePointer inlineArrayType = nullptr;
|
||||||
|
|
||||||
for (size_t i = 0; i < components.size(); ++i)
|
for (size_t i = 0; i < components.size(); ++i)
|
||||||
{
|
{
|
||||||
@ -1285,14 +1286,14 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
|
|||||||
else if (!inlineArrayType->canLiveOutsideStorage())
|
else if (!inlineArrayType->canLiveOutsideStorage())
|
||||||
m_errorReporter.fatalTypeError(_tuple.location(), "Type " + inlineArrayType->toString() + " is only valid in storage.");
|
m_errorReporter.fatalTypeError(_tuple.location(), "Type " + inlineArrayType->toString() + " is only valid in storage.");
|
||||||
|
|
||||||
_tuple.annotation().type = make_shared<ArrayType>(DataLocation::Memory, inlineArrayType, types.size());
|
_tuple.annotation().type = TypeProvider::arrayType(DataLocation::Memory, inlineArrayType, types.size());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (components.size() == 1)
|
if (components.size() == 1)
|
||||||
_tuple.annotation().type = type(*components[0]);
|
_tuple.annotation().type = type(*components[0]);
|
||||||
else
|
else
|
||||||
_tuple.annotation().type = make_shared<TupleType>(types);
|
_tuple.annotation().type = TypeProvider::tupleType(move(types));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1349,7 +1350,7 @@ void TypeChecker::endVisit(BinaryOperation const& _operation)
|
|||||||
_operation.annotation().commonType = commonType;
|
_operation.annotation().commonType = commonType;
|
||||||
_operation.annotation().type =
|
_operation.annotation().type =
|
||||||
TokenTraits::isCompareOp(_operation.getOperator()) ?
|
TokenTraits::isCompareOp(_operation.getOperator()) ?
|
||||||
make_shared<BoolType>() :
|
TypeProvider::boolType() :
|
||||||
commonType;
|
commonType;
|
||||||
_operation.annotation().isPure =
|
_operation.annotation().isPure =
|
||||||
_operation.leftExpression().annotation().isPure &&
|
_operation.leftExpression().annotation().isPure &&
|
||||||
@ -1401,20 +1402,20 @@ TypePointer TypeChecker::typeCheckTypeConversionAndRetrieveReturnType(
|
|||||||
);
|
);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TypePointer const& argType = type(*arguments.front());
|
Type const* argType = type(*arguments.front());
|
||||||
// Resulting data location is memory unless we are converting from a reference
|
// Resulting data location is memory unless we are converting from a reference
|
||||||
// type with a different data location.
|
// type with a different data location.
|
||||||
// (data location cannot yet be specified for type conversions)
|
// (data location cannot yet be specified for type conversions)
|
||||||
DataLocation dataLoc = DataLocation::Memory;
|
DataLocation dataLoc = DataLocation::Memory;
|
||||||
if (auto argRefType = dynamic_cast<ReferenceType const*>(argType.get()))
|
if (auto argRefType = dynamic_cast<ReferenceType const*>(argType))
|
||||||
dataLoc = argRefType->location();
|
dataLoc = argRefType->location();
|
||||||
if (auto type = dynamic_cast<ReferenceType const*>(resultType.get()))
|
if (auto type = dynamic_cast<ReferenceType const*>(resultType))
|
||||||
resultType = type->copyForLocation(dataLoc, type->isPointer());
|
resultType = TypeProvider::withLocation(type, dataLoc, type->isPointer());
|
||||||
if (argType->isExplicitlyConvertibleTo(*resultType))
|
if (argType->isExplicitlyConvertibleTo(*resultType))
|
||||||
{
|
{
|
||||||
if (auto argArrayType = dynamic_cast<ArrayType const*>(argType.get()))
|
if (auto argArrayType = dynamic_cast<ArrayType const*>(argType))
|
||||||
{
|
{
|
||||||
auto resultArrayType = dynamic_cast<ArrayType const*>(resultType.get());
|
auto resultArrayType = dynamic_cast<ArrayType const*>(resultType);
|
||||||
solAssert(!!resultArrayType, "");
|
solAssert(!!resultArrayType, "");
|
||||||
solAssert(
|
solAssert(
|
||||||
argArrayType->location() != DataLocation::Storage ||
|
argArrayType->location() != DataLocation::Storage ||
|
||||||
@ -1436,9 +1437,9 @@ TypePointer TypeChecker::typeCheckTypeConversionAndRetrieveReturnType(
|
|||||||
argType->category() == Type::Category::Address
|
argType->category() == Type::Category::Address
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
solAssert(dynamic_cast<ContractType const*>(resultType.get())->isPayable(), "");
|
solAssert(dynamic_cast<ContractType const*>(resultType)->isPayable(), "");
|
||||||
solAssert(
|
solAssert(
|
||||||
dynamic_cast<AddressType const*>(argType.get())->stateMutability() <
|
dynamic_cast<AddressType const*>(argType)->stateMutability() <
|
||||||
StateMutability::Payable,
|
StateMutability::Payable,
|
||||||
""
|
""
|
||||||
);
|
);
|
||||||
@ -1474,10 +1475,8 @@ TypePointer TypeChecker::typeCheckTypeConversionAndRetrieveReturnType(
|
|||||||
}
|
}
|
||||||
if (resultType->category() == Type::Category::Address)
|
if (resultType->category() == Type::Category::Address)
|
||||||
{
|
{
|
||||||
bool const payable = argType->isExplicitlyConvertibleTo(AddressType::addressPayable());
|
bool const payable = argType->isExplicitlyConvertibleTo(*TypeProvider::payableAddressType());
|
||||||
resultType = make_shared<AddressType>(
|
resultType = payable ? TypeProvider::payableAddressType() : TypeProvider::addressType();
|
||||||
payable ? StateMutability::Payable : StateMutability::NonPayable
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return resultType;
|
return resultType;
|
||||||
@ -1829,17 +1828,17 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
|
|||||||
|
|
||||||
_functionCall.expression().accept(*this);
|
_functionCall.expression().accept(*this);
|
||||||
|
|
||||||
TypePointer const& expressionType = type(_functionCall.expression());
|
Type const* expressionType = type(_functionCall.expression());
|
||||||
|
|
||||||
// Determine function call kind and function type for this FunctionCall node
|
// Determine function call kind and function type for this FunctionCall node
|
||||||
FunctionCallAnnotation& funcCallAnno = _functionCall.annotation();
|
FunctionCallAnnotation& funcCallAnno = _functionCall.annotation();
|
||||||
FunctionTypePointer functionType;
|
FunctionTypePointer functionType = nullptr;
|
||||||
|
|
||||||
// Determine and assign function call kind, purity and function type for this FunctionCall node
|
// Determine and assign function call kind, purity and function type for this FunctionCall node
|
||||||
switch (expressionType->category())
|
switch (expressionType->category())
|
||||||
{
|
{
|
||||||
case Type::Category::Function:
|
case Type::Category::Function:
|
||||||
functionType = dynamic_pointer_cast<FunctionType const>(expressionType);
|
functionType = dynamic_cast<FunctionType const*>(expressionType);
|
||||||
funcCallAnno.kind = FunctionCallKind::FunctionCall;
|
funcCallAnno.kind = FunctionCallKind::FunctionCall;
|
||||||
|
|
||||||
// Purity for function calls also depends upon the callee and its FunctionType
|
// Purity for function calls also depends upon the callee and its FunctionType
|
||||||
@ -1926,7 +1925,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
|
|||||||
|
|
||||||
funcCallAnno.type = returnTypes.size() == 1 ?
|
funcCallAnno.type = returnTypes.size() == 1 ?
|
||||||
move(returnTypes.front()) :
|
move(returnTypes.front()) :
|
||||||
make_shared<TupleType>(move(returnTypes));
|
TypeProvider::tupleType(move(returnTypes));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1936,7 +1935,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
|
|||||||
// for non-callables, ensure error reported and annotate node to void function
|
// for non-callables, ensure error reported and annotate node to void function
|
||||||
solAssert(m_errorReporter.hasErrors(), "");
|
solAssert(m_errorReporter.hasErrors(), "");
|
||||||
funcCallAnno.kind = FunctionCallKind::FunctionCall;
|
funcCallAnno.kind = FunctionCallKind::FunctionCall;
|
||||||
funcCallAnno.type = make_shared<TupleType>();
|
funcCallAnno.type = TypeProvider::emptyTupleType();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1999,8 +1998,8 @@ void TypeChecker::endVisit(NewExpression const& _newExpression)
|
|||||||
"Length has to be placed in parentheses after the array type for new expression."
|
"Length has to be placed in parentheses after the array type for new expression."
|
||||||
);
|
);
|
||||||
type = ReferenceType::copyForLocationIfReference(DataLocation::Memory, type);
|
type = ReferenceType::copyForLocationIfReference(DataLocation::Memory, type);
|
||||||
_newExpression.annotation().type = make_shared<FunctionType>(
|
_newExpression.annotation().type = TypeProvider::functionType(
|
||||||
TypePointers{make_shared<IntegerType>(256)},
|
TypePointers{TypeProvider::uint256()},
|
||||||
TypePointers{type},
|
TypePointers{type},
|
||||||
strings(1, ""),
|
strings(1, ""),
|
||||||
strings(1, ""),
|
strings(1, ""),
|
||||||
@ -2059,7 +2058,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
|||||||
string errorMsg = "Member \"" + memberName + "\" not found or not visible "
|
string errorMsg = "Member \"" + memberName + "\" not found or not visible "
|
||||||
"after argument-dependent lookup in " + exprType->toString() + ".";
|
"after argument-dependent lookup in " + exprType->toString() + ".";
|
||||||
|
|
||||||
if (auto const& funType = dynamic_pointer_cast<FunctionType const>(exprType))
|
if (auto const& funType = dynamic_cast<FunctionType const*>(exprType))
|
||||||
{
|
{
|
||||||
auto const& t = funType->returnParameterTypes();
|
auto const& t = funType->returnParameterTypes();
|
||||||
|
|
||||||
@ -2079,7 +2078,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
|||||||
}
|
}
|
||||||
else if (exprType->category() == Type::Category::Contract)
|
else if (exprType->category() == Type::Category::Contract)
|
||||||
{
|
{
|
||||||
for (auto const& addressMember: AddressType::addressPayable().nativeMembers(nullptr))
|
for (auto const& addressMember: TypeProvider::payableAddressType()->nativeMembers(nullptr))
|
||||||
if (addressMember.name == memberName)
|
if (addressMember.name == memberName)
|
||||||
{
|
{
|
||||||
Identifier const* var = dynamic_cast<Identifier const*>(&_memberAccess.expression());
|
Identifier const* var = dynamic_cast<Identifier const*>(&_memberAccess.expression());
|
||||||
@ -2088,7 +2087,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (auto addressType = dynamic_cast<AddressType const*>(exprType.get()))
|
else if (auto addressType = dynamic_cast<AddressType const*>(exprType))
|
||||||
{
|
{
|
||||||
// Trigger error when using send or transfer with a non-payable fallback function.
|
// Trigger error when using send or transfer with a non-payable fallback function.
|
||||||
if (memberName == "send" || memberName == "transfer")
|
if (memberName == "send" || memberName == "transfer")
|
||||||
@ -2118,14 +2117,14 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
|||||||
annotation.referencedDeclaration = possibleMembers.front().declaration;
|
annotation.referencedDeclaration = possibleMembers.front().declaration;
|
||||||
annotation.type = possibleMembers.front().type;
|
annotation.type = possibleMembers.front().type;
|
||||||
|
|
||||||
if (auto funType = dynamic_cast<FunctionType const*>(annotation.type.get()))
|
if (auto funType = dynamic_cast<FunctionType const*>(annotation.type))
|
||||||
solAssert(
|
solAssert(
|
||||||
!funType->bound() || exprType->isImplicitlyConvertibleTo(*funType->selfType()),
|
!funType->bound() || exprType->isImplicitlyConvertibleTo(*funType->selfType()),
|
||||||
"Function \"" + memberName + "\" cannot be called on an object of type " +
|
"Function \"" + memberName + "\" cannot be called on an object of type " +
|
||||||
exprType->toString() + " (expected " + funType->selfType()->toString() + ")."
|
exprType->toString() + " (expected " + funType->selfType()->toString() + ")."
|
||||||
);
|
);
|
||||||
|
|
||||||
if (auto const* structType = dynamic_cast<StructType const*>(exprType.get()))
|
if (auto const* structType = dynamic_cast<StructType const*>(exprType))
|
||||||
annotation.isLValue = !structType->dataStoredIn(DataLocation::CallData);
|
annotation.isLValue = !structType->dataStoredIn(DataLocation::CallData);
|
||||||
else if (exprType->category() == Type::Category::Array)
|
else if (exprType->category() == Type::Category::Array)
|
||||||
{
|
{
|
||||||
@ -2138,18 +2137,18 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
|||||||
}
|
}
|
||||||
else if (exprType->category() == Type::Category::FixedBytes)
|
else if (exprType->category() == Type::Category::FixedBytes)
|
||||||
annotation.isLValue = false;
|
annotation.isLValue = false;
|
||||||
else if (TypeType const* typeType = dynamic_cast<decltype(typeType)>(exprType.get()))
|
else if (TypeType const* typeType = dynamic_cast<decltype(typeType)>(exprType))
|
||||||
{
|
{
|
||||||
if (ContractType const* contractType = dynamic_cast<decltype(contractType)>(typeType->actualType().get()))
|
if (ContractType const* contractType = dynamic_cast<decltype(contractType)>(typeType->actualType()))
|
||||||
annotation.isLValue = annotation.referencedDeclaration->isLValue();
|
annotation.isLValue = annotation.referencedDeclaration->isLValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO some members might be pure, but for example `address(0x123).balance` is not pure
|
// TODO some members might be pure, but for example `address(0x123).balance` is not pure
|
||||||
// although every subexpression is, so leaving this limited for now.
|
// although every subexpression is, so leaving this limited for now.
|
||||||
if (auto tt = dynamic_cast<TypeType const*>(exprType.get()))
|
if (auto tt = dynamic_cast<TypeType const*>(exprType))
|
||||||
if (tt->actualType()->category() == Type::Category::Enum)
|
if (tt->actualType()->category() == Type::Category::Enum)
|
||||||
annotation.isPure = true;
|
annotation.isPure = true;
|
||||||
if (auto magicType = dynamic_cast<MagicType const*>(exprType.get()))
|
if (auto magicType = dynamic_cast<MagicType const*>(exprType))
|
||||||
{
|
{
|
||||||
if (magicType->kind() == MagicType::Kind::ABI)
|
if (magicType->kind() == MagicType::Kind::ABI)
|
||||||
annotation.isPure = true;
|
annotation.isPure = true;
|
||||||
@ -2178,7 +2177,7 @@ bool TypeChecker::visit(IndexAccess const& _access)
|
|||||||
{
|
{
|
||||||
_access.baseExpression().accept(*this);
|
_access.baseExpression().accept(*this);
|
||||||
TypePointer baseType = type(_access.baseExpression());
|
TypePointer baseType = type(_access.baseExpression());
|
||||||
TypePointer resultType;
|
TypePointer resultType = nullptr;
|
||||||
bool isLValue = false;
|
bool isLValue = false;
|
||||||
bool isPure = _access.baseExpression().annotation().isPure;
|
bool isPure = _access.baseExpression().annotation().isPure;
|
||||||
Expression const* index = _access.indexExpression();
|
Expression const* index = _access.indexExpression();
|
||||||
@ -2196,9 +2195,9 @@ bool TypeChecker::visit(IndexAccess const& _access)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
expectType(*index, IntegerType::uint256());
|
expectType(*index, *TypeProvider::uint256());
|
||||||
if (!m_errorReporter.hasErrors())
|
if (!m_errorReporter.hasErrors())
|
||||||
if (auto numberType = dynamic_cast<RationalNumberType const*>(type(*index).get()))
|
if (auto numberType = dynamic_cast<RationalNumberType const*>(type(*index)))
|
||||||
{
|
{
|
||||||
solAssert(!numberType->isFractional(), "");
|
solAssert(!numberType->isFractional(), "");
|
||||||
if (!actualType.isDynamicallySized() && actualType.length() <= numberType->literalValue(nullptr))
|
if (!actualType.isDynamicallySized() && actualType.length() <= numberType->literalValue(nullptr))
|
||||||
@ -2223,16 +2222,16 @@ bool TypeChecker::visit(IndexAccess const& _access)
|
|||||||
case Type::Category::TypeType:
|
case Type::Category::TypeType:
|
||||||
{
|
{
|
||||||
TypeType const& typeType = dynamic_cast<TypeType const&>(*baseType);
|
TypeType const& typeType = dynamic_cast<TypeType const&>(*baseType);
|
||||||
if (dynamic_cast<ContractType const*>(typeType.actualType().get()))
|
if (dynamic_cast<ContractType const*>(typeType.actualType()))
|
||||||
m_errorReporter.typeError(_access.location(), "Index access for contracts or libraries is not possible.");
|
m_errorReporter.typeError(_access.location(), "Index access for contracts or libraries is not possible.");
|
||||||
if (!index)
|
if (!index)
|
||||||
resultType = make_shared<TypeType>(make_shared<ArrayType>(DataLocation::Memory, typeType.actualType()));
|
resultType = TypeProvider::typeType(TypeProvider::arrayType(DataLocation::Memory, typeType.actualType()));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
u256 length = 1;
|
u256 length = 1;
|
||||||
if (expectType(*index, IntegerType::uint256()))
|
if (expectType(*index, *TypeProvider::uint256()))
|
||||||
{
|
{
|
||||||
if (auto indexValue = dynamic_cast<RationalNumberType const*>(type(*index).get()))
|
if (auto indexValue = dynamic_cast<RationalNumberType const*>(type(*index)))
|
||||||
length = indexValue->literalValue(nullptr);
|
length = indexValue->literalValue(nullptr);
|
||||||
else
|
else
|
||||||
m_errorReporter.fatalTypeError(index->location(), "Integer constant expected.");
|
m_errorReporter.fatalTypeError(index->location(), "Integer constant expected.");
|
||||||
@ -2240,7 +2239,7 @@ bool TypeChecker::visit(IndexAccess const& _access)
|
|||||||
else
|
else
|
||||||
solAssert(m_errorReporter.hasErrors(), "Expected errors as expectType returned false");
|
solAssert(m_errorReporter.hasErrors(), "Expected errors as expectType returned false");
|
||||||
|
|
||||||
resultType = make_shared<TypeType>(make_shared<ArrayType>(
|
resultType = TypeProvider::typeType(TypeProvider::arrayType(
|
||||||
DataLocation::Memory,
|
DataLocation::Memory,
|
||||||
typeType.actualType(),
|
typeType.actualType(),
|
||||||
length
|
length
|
||||||
@ -2255,13 +2254,13 @@ bool TypeChecker::visit(IndexAccess const& _access)
|
|||||||
m_errorReporter.typeError(_access.location(), "Index expression cannot be omitted.");
|
m_errorReporter.typeError(_access.location(), "Index expression cannot be omitted.");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!expectType(*index, IntegerType::uint256()))
|
if (!expectType(*index, *TypeProvider::uint256()))
|
||||||
m_errorReporter.fatalTypeError(_access.location(), "Index expression cannot be represented as an unsigned integer.");
|
m_errorReporter.fatalTypeError(_access.location(), "Index expression cannot be represented as an unsigned integer.");
|
||||||
if (auto integerType = dynamic_cast<RationalNumberType const*>(type(*index).get()))
|
if (auto integerType = dynamic_cast<RationalNumberType const*>(type(*index)))
|
||||||
if (bytesType.numBytes() <= integerType->literalValue(nullptr))
|
if (bytesType.numBytes() <= integerType->literalValue(nullptr))
|
||||||
m_errorReporter.typeError(_access.location(), "Out of bounds array access.");
|
m_errorReporter.typeError(_access.location(), "Out of bounds array access.");
|
||||||
}
|
}
|
||||||
resultType = make_shared<FixedBytesType>(1);
|
resultType = TypeProvider::fixedBytesType(1);
|
||||||
isLValue = false; // @todo this heavily depends on how it is embedded
|
isLValue = false; // @todo this heavily depends on how it is embedded
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2271,7 +2270,7 @@ bool TypeChecker::visit(IndexAccess const& _access)
|
|||||||
"Indexed expression has to be a type, mapping or array (is " + baseType->toString() + ")"
|
"Indexed expression has to be a type, mapping or array (is " + baseType->toString() + ")"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_access.annotation().type = move(resultType);
|
_access.annotation().type = resultType;
|
||||||
_access.annotation().isLValue = isLValue;
|
_access.annotation().isLValue = isLValue;
|
||||||
if (index && !index->annotation().isPure)
|
if (index && !index->annotation().isPure)
|
||||||
isPure = false;
|
isPure = false;
|
||||||
@ -2337,16 +2336,16 @@ bool TypeChecker::visit(Identifier const& _identifier)
|
|||||||
annotation.isPure = annotation.isConstant = variableDeclaration->isConstant();
|
annotation.isPure = annotation.isConstant = variableDeclaration->isConstant();
|
||||||
else if (dynamic_cast<MagicVariableDeclaration const*>(annotation.referencedDeclaration))
|
else if (dynamic_cast<MagicVariableDeclaration const*>(annotation.referencedDeclaration))
|
||||||
{
|
{
|
||||||
if (dynamic_cast<FunctionType const*>(annotation.type.get()))
|
if (dynamic_cast<FunctionType const*>(annotation.type))
|
||||||
annotation.isPure = true;
|
annotation.isPure = true;
|
||||||
}
|
}
|
||||||
else if (dynamic_cast<TypeType const*>(annotation.type.get()))
|
else if (dynamic_cast<TypeType const*>(annotation.type))
|
||||||
annotation.isPure = true;
|
annotation.isPure = true;
|
||||||
|
|
||||||
|
|
||||||
// Check for deprecated function names.
|
// Check for deprecated function names.
|
||||||
// The check is done here for the case without an actual function call.
|
// The check is done here for the case without an actual function call.
|
||||||
if (FunctionType const* fType = dynamic_cast<FunctionType const*>(_identifier.annotation().type.get()))
|
if (FunctionType const* fType = dynamic_cast<FunctionType const*>(_identifier.annotation().type))
|
||||||
{
|
{
|
||||||
if (_identifier.name() == "sha3" && fType->kind() == FunctionType::Kind::KECCAK256)
|
if (_identifier.name() == "sha3" && fType->kind() == FunctionType::Kind::KECCAK256)
|
||||||
m_errorReporter.typeError(
|
m_errorReporter.typeError(
|
||||||
@ -2365,7 +2364,7 @@ bool TypeChecker::visit(Identifier const& _identifier)
|
|||||||
|
|
||||||
void TypeChecker::endVisit(ElementaryTypeNameExpression const& _expr)
|
void TypeChecker::endVisit(ElementaryTypeNameExpression const& _expr)
|
||||||
{
|
{
|
||||||
_expr.annotation().type = make_shared<TypeType>(Type::fromElementaryTypeName(_expr.typeName()));
|
_expr.annotation().type = TypeProvider::typeType(TypeProvider::fromElementaryTypeName(_expr.typeName()));
|
||||||
_expr.annotation().isPure = true;
|
_expr.annotation().isPure = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2374,7 +2373,7 @@ void TypeChecker::endVisit(Literal const& _literal)
|
|||||||
if (_literal.looksLikeAddress())
|
if (_literal.looksLikeAddress())
|
||||||
{
|
{
|
||||||
// Assign type here if it even looks like an address. This prevents double errors for invalid addresses
|
// Assign type here if it even looks like an address. This prevents double errors for invalid addresses
|
||||||
_literal.annotation().type = make_shared<AddressType>(StateMutability::Payable);
|
_literal.annotation().type = TypeProvider::payableAddressType();
|
||||||
|
|
||||||
string msg;
|
string msg;
|
||||||
if (_literal.valueWithoutUnderscores().length() != 42) // "0x" + 40 hex digits
|
if (_literal.valueWithoutUnderscores().length() != 42) // "0x" + 40 hex digits
|
||||||
@ -2413,7 +2412,7 @@ void TypeChecker::endVisit(Literal const& _literal)
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (!_literal.annotation().type)
|
if (!_literal.annotation().type)
|
||||||
_literal.annotation().type = Type::forLiteral(_literal);
|
_literal.annotation().type = TypeProvider::forLiteral(_literal);
|
||||||
|
|
||||||
if (!_literal.annotation().type)
|
if (!_literal.annotation().type)
|
||||||
m_errorReporter.fatalTypeError(_literal.location(), "Invalid literal value.");
|
m_errorReporter.fatalTypeError(_literal.location(), "Invalid literal value.");
|
||||||
@ -2460,7 +2459,7 @@ bool TypeChecker::expectType(Expression const& _expression, Type const& _expecte
|
|||||||
_expectedType.toString();
|
_expectedType.toString();
|
||||||
if (
|
if (
|
||||||
type(_expression)->category() == Type::Category::RationalNumber &&
|
type(_expression)->category() == Type::Category::RationalNumber &&
|
||||||
dynamic_pointer_cast<RationalNumberType const>(type(_expression))->isFractional() &&
|
dynamic_cast<RationalNumberType const*>(type(_expression))->isFractional() &&
|
||||||
type(_expression)->mobileType()
|
type(_expression)->mobileType()
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include <libsolidity/ast/ASTVisitor.h>
|
#include <libsolidity/ast/ASTVisitor.h>
|
||||||
#include <libsolidity/ast/AST_accept.h>
|
#include <libsolidity/ast/AST_accept.h>
|
||||||
|
#include <libsolidity/ast/TypeProvider.h>
|
||||||
#include <libdevcore/Keccak256.h>
|
#include <libdevcore/Keccak256.h>
|
||||||
|
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
@ -105,7 +106,7 @@ ImportAnnotation& ImportDirective::annotation() const
|
|||||||
TypePointer ImportDirective::type() const
|
TypePointer ImportDirective::type() const
|
||||||
{
|
{
|
||||||
solAssert(!!annotation().sourceUnit, "");
|
solAssert(!!annotation().sourceUnit, "");
|
||||||
return make_shared<ModuleType>(*annotation().sourceUnit);
|
return TypeProvider::moduleType(*annotation().sourceUnit);
|
||||||
}
|
}
|
||||||
|
|
||||||
map<FixedHash<4>, FunctionTypePointer> ContractDefinition::interfaceFunctions() const
|
map<FixedHash<4>, FunctionTypePointer> ContractDefinition::interfaceFunctions() const
|
||||||
@ -188,10 +189,10 @@ vector<pair<FixedHash<4>, FunctionTypePointer>> const& ContractDefinition::inter
|
|||||||
vector<FunctionTypePointer> functions;
|
vector<FunctionTypePointer> functions;
|
||||||
for (FunctionDefinition const* f: contract->definedFunctions())
|
for (FunctionDefinition const* f: contract->definedFunctions())
|
||||||
if (f->isPartOfExternalInterface())
|
if (f->isPartOfExternalInterface())
|
||||||
functions.push_back(make_shared<FunctionType>(*f, false));
|
functions.push_back(TypeProvider::functionType(*f, false));
|
||||||
for (VariableDeclaration const* v: contract->stateVariables())
|
for (VariableDeclaration const* v: contract->stateVariables())
|
||||||
if (v->isPartOfExternalInterface())
|
if (v->isPartOfExternalInterface())
|
||||||
functions.push_back(make_shared<FunctionType>(*v));
|
functions.push_back(TypeProvider::functionType(*v));
|
||||||
for (FunctionTypePointer const& fun: functions)
|
for (FunctionTypePointer const& fun: functions)
|
||||||
{
|
{
|
||||||
if (!fun->interfaceFunctionType())
|
if (!fun->interfaceFunctionType())
|
||||||
@ -246,7 +247,7 @@ vector<Declaration const*> const& ContractDefinition::inheritableMembers() const
|
|||||||
|
|
||||||
TypePointer ContractDefinition::type() const
|
TypePointer ContractDefinition::type() const
|
||||||
{
|
{
|
||||||
return make_shared<TypeType>(make_shared<ContractType>(*this));
|
return TypeProvider::typeType(TypeProvider::contractType(*this));
|
||||||
}
|
}
|
||||||
|
|
||||||
ContractDefinitionAnnotation& ContractDefinition::annotation() const
|
ContractDefinitionAnnotation& ContractDefinition::annotation() const
|
||||||
@ -265,7 +266,7 @@ TypeNameAnnotation& TypeName::annotation() const
|
|||||||
|
|
||||||
TypePointer StructDefinition::type() const
|
TypePointer StructDefinition::type() const
|
||||||
{
|
{
|
||||||
return make_shared<TypeType>(make_shared<StructType>(*this));
|
return TypeProvider::typeType(TypeProvider::structType(*this, DataLocation::Storage));
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeDeclarationAnnotation& StructDefinition::annotation() const
|
TypeDeclarationAnnotation& StructDefinition::annotation() const
|
||||||
@ -279,12 +280,12 @@ TypePointer EnumValue::type() const
|
|||||||
{
|
{
|
||||||
auto parentDef = dynamic_cast<EnumDefinition const*>(scope());
|
auto parentDef = dynamic_cast<EnumDefinition const*>(scope());
|
||||||
solAssert(parentDef, "Enclosing Scope of EnumValue was not set");
|
solAssert(parentDef, "Enclosing Scope of EnumValue was not set");
|
||||||
return make_shared<EnumType>(*parentDef);
|
return TypeProvider::enumType(*parentDef);
|
||||||
}
|
}
|
||||||
|
|
||||||
TypePointer EnumDefinition::type() const
|
TypePointer EnumDefinition::type() const
|
||||||
{
|
{
|
||||||
return make_shared<TypeType>(make_shared<EnumType>(*this));
|
return TypeProvider::typeType(TypeProvider::enumType(*this));
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeDeclarationAnnotation& EnumDefinition::annotation() const
|
TypeDeclarationAnnotation& EnumDefinition::annotation() const
|
||||||
@ -312,7 +313,7 @@ FunctionTypePointer FunctionDefinition::functionType(bool _internal) const
|
|||||||
case Declaration::Visibility::Private:
|
case Declaration::Visibility::Private:
|
||||||
case Declaration::Visibility::Internal:
|
case Declaration::Visibility::Internal:
|
||||||
case Declaration::Visibility::Public:
|
case Declaration::Visibility::Public:
|
||||||
return make_shared<FunctionType>(*this, _internal);
|
return TypeProvider::functionType(*this, _internal);
|
||||||
case Declaration::Visibility::External:
|
case Declaration::Visibility::External:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -328,7 +329,7 @@ FunctionTypePointer FunctionDefinition::functionType(bool _internal) const
|
|||||||
return {};
|
return {};
|
||||||
case Declaration::Visibility::Public:
|
case Declaration::Visibility::Public:
|
||||||
case Declaration::Visibility::External:
|
case Declaration::Visibility::External:
|
||||||
return make_shared<FunctionType>(*this, _internal);
|
return TypeProvider::functionType(*this, _internal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,12 +340,12 @@ FunctionTypePointer FunctionDefinition::functionType(bool _internal) const
|
|||||||
TypePointer FunctionDefinition::type() const
|
TypePointer FunctionDefinition::type() const
|
||||||
{
|
{
|
||||||
solAssert(visibility() != Declaration::Visibility::External, "");
|
solAssert(visibility() != Declaration::Visibility::External, "");
|
||||||
return make_shared<FunctionType>(*this);
|
return TypeProvider::functionType(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
string FunctionDefinition::externalSignature() const
|
string FunctionDefinition::externalSignature() const
|
||||||
{
|
{
|
||||||
return FunctionType(*this).externalSignature();
|
return TypeProvider::functionType(*this)->externalSignature();
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionDefinitionAnnotation& FunctionDefinition::annotation() const
|
FunctionDefinitionAnnotation& FunctionDefinition::annotation() const
|
||||||
@ -356,7 +357,7 @@ FunctionDefinitionAnnotation& FunctionDefinition::annotation() const
|
|||||||
|
|
||||||
TypePointer ModifierDefinition::type() const
|
TypePointer ModifierDefinition::type() const
|
||||||
{
|
{
|
||||||
return make_shared<ModifierType>(*this);
|
return TypeProvider::modifierType(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
ModifierDefinitionAnnotation& ModifierDefinition::annotation() const
|
ModifierDefinitionAnnotation& ModifierDefinition::annotation() const
|
||||||
@ -368,15 +369,15 @@ ModifierDefinitionAnnotation& ModifierDefinition::annotation() const
|
|||||||
|
|
||||||
TypePointer EventDefinition::type() const
|
TypePointer EventDefinition::type() const
|
||||||
{
|
{
|
||||||
return make_shared<FunctionType>(*this);
|
return TypeProvider::functionType(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionTypePointer EventDefinition::functionType(bool _internal) const
|
FunctionTypePointer EventDefinition::functionType(bool _internal) const
|
||||||
{
|
{
|
||||||
if (_internal)
|
if (_internal)
|
||||||
return make_shared<FunctionType>(*this);
|
return TypeProvider::functionType(*this);
|
||||||
else
|
else
|
||||||
return {};
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
EventDefinitionAnnotation& EventDefinition::annotation() const
|
EventDefinitionAnnotation& EventDefinition::annotation() const
|
||||||
@ -508,8 +509,8 @@ bool VariableDeclaration::hasReferenceOrMappingType() const
|
|||||||
{
|
{
|
||||||
solAssert(typeName(), "");
|
solAssert(typeName(), "");
|
||||||
solAssert(typeName()->annotation().type, "Can only be called after reference resolution");
|
solAssert(typeName()->annotation().type, "Can only be called after reference resolution");
|
||||||
TypePointer const& type = typeName()->annotation().type;
|
Type const* type = typeName()->annotation().type;
|
||||||
return type->category() == Type::Category::Mapping || dynamic_cast<ReferenceType const*>(type.get());
|
return type->category() == Type::Category::Mapping || dynamic_cast<ReferenceType const*>(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
set<VariableDeclaration::Location> VariableDeclaration::allowedDataLocations() const
|
set<VariableDeclaration::Location> VariableDeclaration::allowedDataLocations() const
|
||||||
@ -557,21 +558,21 @@ TypePointer VariableDeclaration::type() const
|
|||||||
FunctionTypePointer VariableDeclaration::functionType(bool _internal) const
|
FunctionTypePointer VariableDeclaration::functionType(bool _internal) const
|
||||||
{
|
{
|
||||||
if (_internal)
|
if (_internal)
|
||||||
return {};
|
return nullptr;
|
||||||
switch (visibility())
|
switch (visibility())
|
||||||
{
|
{
|
||||||
case Declaration::Visibility::Default:
|
case Declaration::Visibility::Default:
|
||||||
solAssert(false, "visibility() should not return Default");
|
solAssert(false, "visibility() should not return Default");
|
||||||
case Declaration::Visibility::Private:
|
case Declaration::Visibility::Private:
|
||||||
case Declaration::Visibility::Internal:
|
case Declaration::Visibility::Internal:
|
||||||
return {};
|
return nullptr;
|
||||||
case Declaration::Visibility::Public:
|
case Declaration::Visibility::Public:
|
||||||
case Declaration::Visibility::External:
|
case Declaration::Visibility::External:
|
||||||
return make_shared<FunctionType>(*this);
|
return TypeProvider::functionType(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// To make the compiler happy
|
// To make the compiler happy
|
||||||
return {};
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
VariableDeclarationAnnotation& VariableDeclaration::annotation() const
|
VariableDeclarationAnnotation& VariableDeclaration::annotation() const
|
||||||
|
@ -848,8 +848,9 @@ private:
|
|||||||
class MagicVariableDeclaration: public Declaration
|
class MagicVariableDeclaration: public Declaration
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MagicVariableDeclaration(ASTString const& _name, std::shared_ptr<Type const> const& _type):
|
MagicVariableDeclaration(ASTString const& _name, Type const* _type):
|
||||||
Declaration(SourceLocation(), std::make_shared<ASTString>(_name)), m_type(_type) {}
|
Declaration(SourceLocation(), std::make_shared<ASTString>(_name)), m_type(_type) {}
|
||||||
|
|
||||||
void accept(ASTVisitor&) override
|
void accept(ASTVisitor&) override
|
||||||
{
|
{
|
||||||
solAssert(false, "MagicVariableDeclaration used inside real AST.");
|
solAssert(false, "MagicVariableDeclaration used inside real AST.");
|
||||||
@ -859,15 +860,15 @@ public:
|
|||||||
solAssert(false, "MagicVariableDeclaration used inside real AST.");
|
solAssert(false, "MagicVariableDeclaration used inside real AST.");
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionTypePointer functionType(bool) const override
|
FunctionType const* functionType(bool) const override
|
||||||
{
|
{
|
||||||
solAssert(m_type->category() == Type::Category::Function, "");
|
solAssert(m_type->category() == Type::Category::Function, "");
|
||||||
return std::dynamic_pointer_cast<FunctionType const>(m_type);
|
return dynamic_cast<FunctionType const*>(m_type);
|
||||||
}
|
}
|
||||||
TypePointer type() const override { return m_type; }
|
TypePointer type() const override { return m_type; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<Type const> m_type;
|
Type const* m_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Types
|
/// Types
|
||||||
|
@ -45,7 +45,7 @@ namespace solidity
|
|||||||
{
|
{
|
||||||
|
|
||||||
class Type;
|
class Type;
|
||||||
using TypePointer = std::shared_ptr<Type const>;
|
using TypePointer = Type const*;
|
||||||
|
|
||||||
struct ASTAnnotation
|
struct ASTAnnotation
|
||||||
{
|
{
|
||||||
@ -122,7 +122,7 @@ struct ModifierDefinitionAnnotation: ASTAnnotation, DocumentedAnnotation
|
|||||||
struct VariableDeclarationAnnotation: ASTAnnotation
|
struct VariableDeclarationAnnotation: ASTAnnotation
|
||||||
{
|
{
|
||||||
/// Type of variable (type of identifier referencing this variable).
|
/// Type of variable (type of identifier referencing this variable).
|
||||||
TypePointer type;
|
TypePointer type = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StatementAnnotation: ASTAnnotation, DocumentedAnnotation
|
struct StatementAnnotation: ASTAnnotation, DocumentedAnnotation
|
||||||
@ -155,7 +155,7 @@ struct TypeNameAnnotation: ASTAnnotation
|
|||||||
{
|
{
|
||||||
/// Type declared by this type name, i.e. type of a variable where this type name is used.
|
/// Type declared by this type name, i.e. type of a variable where this type name is used.
|
||||||
/// Set during reference resolution stage.
|
/// Set during reference resolution stage.
|
||||||
TypePointer type;
|
TypePointer type = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UserDefinedTypeNameAnnotation: TypeNameAnnotation
|
struct UserDefinedTypeNameAnnotation: TypeNameAnnotation
|
||||||
@ -170,7 +170,7 @@ struct UserDefinedTypeNameAnnotation: TypeNameAnnotation
|
|||||||
struct ExpressionAnnotation: ASTAnnotation
|
struct ExpressionAnnotation: ASTAnnotation
|
||||||
{
|
{
|
||||||
/// Inferred type of the expression.
|
/// Inferred type of the expression.
|
||||||
TypePointer type;
|
TypePointer type = nullptr;
|
||||||
/// Whether the expression is a constant variable
|
/// Whether the expression is a constant variable
|
||||||
bool isConstant = false;
|
bool isConstant = false;
|
||||||
/// Whether the expression is pure, i.e. compile-time constant.
|
/// Whether the expression is pure, i.e. compile-time constant.
|
||||||
@ -203,7 +203,7 @@ struct BinaryOperationAnnotation: ExpressionAnnotation
|
|||||||
{
|
{
|
||||||
/// The common type that is used for the operation, not necessarily the result type (which
|
/// The common type that is used for the operation, not necessarily the result type (which
|
||||||
/// e.g. for comparisons is bool).
|
/// e.g. for comparisons is bool).
|
||||||
TypePointer commonType;
|
TypePointer commonType = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class FunctionCallKind
|
enum class FunctionCallKind
|
||||||
|
@ -57,7 +57,7 @@ class Type;
|
|||||||
struct FuncCallArguments
|
struct FuncCallArguments
|
||||||
{
|
{
|
||||||
/// Types of arguments
|
/// Types of arguments
|
||||||
std::vector<std::shared_ptr<Type const>> types;
|
std::vector<Type const*> types;
|
||||||
/// Names of the arguments if given, otherwise unset
|
/// Names of the arguments if given, otherwise unset
|
||||||
std::vector<ASTPointer<ASTString>> names;
|
std::vector<ASTPointer<ASTString>> names;
|
||||||
|
|
||||||
|
541
libsolidity/ast/TypeProvider.cpp
Normal file
541
libsolidity/ast/TypeProvider.cpp
Normal file
@ -0,0 +1,541 @@
|
|||||||
|
/*
|
||||||
|
This file is part of solidity.
|
||||||
|
|
||||||
|
solidity 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.
|
||||||
|
|
||||||
|
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libsolidity/ast/AST.h>
|
||||||
|
#include <libsolidity/ast/TypeProvider.h>
|
||||||
|
#include <boost/algorithm/string.hpp>
|
||||||
|
#include <boost/algorithm/string/split.hpp>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace dev;
|
||||||
|
using namespace solidity;
|
||||||
|
|
||||||
|
BoolType const TypeProvider::m_boolType{};
|
||||||
|
InaccessibleDynamicType const TypeProvider::m_inaccessibleDynamicType{};
|
||||||
|
|
||||||
|
/// The string and bytes unique_ptrs are initialized when they are first used because
|
||||||
|
/// they rely on `byte` being available which we cannot guarantee in the static init context.
|
||||||
|
std::unique_ptr<ArrayType> TypeProvider::m_bytesStorageType;
|
||||||
|
std::unique_ptr<ArrayType> TypeProvider::m_bytesMemoryType;
|
||||||
|
std::unique_ptr<ArrayType> TypeProvider::m_stringStorageType;
|
||||||
|
std::unique_ptr<ArrayType> TypeProvider::m_stringMemoryType;
|
||||||
|
|
||||||
|
TupleType const TypeProvider::m_emptyTupleType{};
|
||||||
|
AddressType const TypeProvider::m_payableAddressType{StateMutability::Payable};
|
||||||
|
AddressType const TypeProvider::m_addressType{StateMutability::NonPayable};
|
||||||
|
|
||||||
|
array<unique_ptr<IntegerType>, 32> const TypeProvider::m_intM{{
|
||||||
|
{make_unique<IntegerType>(8 * 1, IntegerType::Modifier::Signed)},
|
||||||
|
{make_unique<IntegerType>(8 * 2, IntegerType::Modifier::Signed)},
|
||||||
|
{make_unique<IntegerType>(8 * 3, IntegerType::Modifier::Signed)},
|
||||||
|
{make_unique<IntegerType>(8 * 4, IntegerType::Modifier::Signed)},
|
||||||
|
{make_unique<IntegerType>(8 * 5, IntegerType::Modifier::Signed)},
|
||||||
|
{make_unique<IntegerType>(8 * 6, IntegerType::Modifier::Signed)},
|
||||||
|
{make_unique<IntegerType>(8 * 7, IntegerType::Modifier::Signed)},
|
||||||
|
{make_unique<IntegerType>(8 * 8, IntegerType::Modifier::Signed)},
|
||||||
|
{make_unique<IntegerType>(8 * 9, IntegerType::Modifier::Signed)},
|
||||||
|
{make_unique<IntegerType>(8 * 10, IntegerType::Modifier::Signed)},
|
||||||
|
{make_unique<IntegerType>(8 * 11, IntegerType::Modifier::Signed)},
|
||||||
|
{make_unique<IntegerType>(8 * 12, IntegerType::Modifier::Signed)},
|
||||||
|
{make_unique<IntegerType>(8 * 13, IntegerType::Modifier::Signed)},
|
||||||
|
{make_unique<IntegerType>(8 * 14, IntegerType::Modifier::Signed)},
|
||||||
|
{make_unique<IntegerType>(8 * 15, IntegerType::Modifier::Signed)},
|
||||||
|
{make_unique<IntegerType>(8 * 16, IntegerType::Modifier::Signed)},
|
||||||
|
{make_unique<IntegerType>(8 * 17, IntegerType::Modifier::Signed)},
|
||||||
|
{make_unique<IntegerType>(8 * 18, IntegerType::Modifier::Signed)},
|
||||||
|
{make_unique<IntegerType>(8 * 19, IntegerType::Modifier::Signed)},
|
||||||
|
{make_unique<IntegerType>(8 * 20, IntegerType::Modifier::Signed)},
|
||||||
|
{make_unique<IntegerType>(8 * 21, IntegerType::Modifier::Signed)},
|
||||||
|
{make_unique<IntegerType>(8 * 22, IntegerType::Modifier::Signed)},
|
||||||
|
{make_unique<IntegerType>(8 * 23, IntegerType::Modifier::Signed)},
|
||||||
|
{make_unique<IntegerType>(8 * 24, IntegerType::Modifier::Signed)},
|
||||||
|
{make_unique<IntegerType>(8 * 25, IntegerType::Modifier::Signed)},
|
||||||
|
{make_unique<IntegerType>(8 * 26, IntegerType::Modifier::Signed)},
|
||||||
|
{make_unique<IntegerType>(8 * 27, IntegerType::Modifier::Signed)},
|
||||||
|
{make_unique<IntegerType>(8 * 28, IntegerType::Modifier::Signed)},
|
||||||
|
{make_unique<IntegerType>(8 * 29, IntegerType::Modifier::Signed)},
|
||||||
|
{make_unique<IntegerType>(8 * 30, IntegerType::Modifier::Signed)},
|
||||||
|
{make_unique<IntegerType>(8 * 31, IntegerType::Modifier::Signed)},
|
||||||
|
{make_unique<IntegerType>(8 * 32, IntegerType::Modifier::Signed)}
|
||||||
|
}};
|
||||||
|
|
||||||
|
array<unique_ptr<IntegerType>, 32> const TypeProvider::m_uintM{{
|
||||||
|
{make_unique<IntegerType>(8 * 1, IntegerType::Modifier::Unsigned)},
|
||||||
|
{make_unique<IntegerType>(8 * 2, IntegerType::Modifier::Unsigned)},
|
||||||
|
{make_unique<IntegerType>(8 * 3, IntegerType::Modifier::Unsigned)},
|
||||||
|
{make_unique<IntegerType>(8 * 4, IntegerType::Modifier::Unsigned)},
|
||||||
|
{make_unique<IntegerType>(8 * 5, IntegerType::Modifier::Unsigned)},
|
||||||
|
{make_unique<IntegerType>(8 * 6, IntegerType::Modifier::Unsigned)},
|
||||||
|
{make_unique<IntegerType>(8 * 7, IntegerType::Modifier::Unsigned)},
|
||||||
|
{make_unique<IntegerType>(8 * 8, IntegerType::Modifier::Unsigned)},
|
||||||
|
{make_unique<IntegerType>(8 * 9, IntegerType::Modifier::Unsigned)},
|
||||||
|
{make_unique<IntegerType>(8 * 10, IntegerType::Modifier::Unsigned)},
|
||||||
|
{make_unique<IntegerType>(8 * 11, IntegerType::Modifier::Unsigned)},
|
||||||
|
{make_unique<IntegerType>(8 * 12, IntegerType::Modifier::Unsigned)},
|
||||||
|
{make_unique<IntegerType>(8 * 13, IntegerType::Modifier::Unsigned)},
|
||||||
|
{make_unique<IntegerType>(8 * 14, IntegerType::Modifier::Unsigned)},
|
||||||
|
{make_unique<IntegerType>(8 * 15, IntegerType::Modifier::Unsigned)},
|
||||||
|
{make_unique<IntegerType>(8 * 16, IntegerType::Modifier::Unsigned)},
|
||||||
|
{make_unique<IntegerType>(8 * 17, IntegerType::Modifier::Unsigned)},
|
||||||
|
{make_unique<IntegerType>(8 * 18, IntegerType::Modifier::Unsigned)},
|
||||||
|
{make_unique<IntegerType>(8 * 19, IntegerType::Modifier::Unsigned)},
|
||||||
|
{make_unique<IntegerType>(8 * 20, IntegerType::Modifier::Unsigned)},
|
||||||
|
{make_unique<IntegerType>(8 * 21, IntegerType::Modifier::Unsigned)},
|
||||||
|
{make_unique<IntegerType>(8 * 22, IntegerType::Modifier::Unsigned)},
|
||||||
|
{make_unique<IntegerType>(8 * 23, IntegerType::Modifier::Unsigned)},
|
||||||
|
{make_unique<IntegerType>(8 * 24, IntegerType::Modifier::Unsigned)},
|
||||||
|
{make_unique<IntegerType>(8 * 25, IntegerType::Modifier::Unsigned)},
|
||||||
|
{make_unique<IntegerType>(8 * 26, IntegerType::Modifier::Unsigned)},
|
||||||
|
{make_unique<IntegerType>(8 * 27, IntegerType::Modifier::Unsigned)},
|
||||||
|
{make_unique<IntegerType>(8 * 28, IntegerType::Modifier::Unsigned)},
|
||||||
|
{make_unique<IntegerType>(8 * 29, IntegerType::Modifier::Unsigned)},
|
||||||
|
{make_unique<IntegerType>(8 * 30, IntegerType::Modifier::Unsigned)},
|
||||||
|
{make_unique<IntegerType>(8 * 31, IntegerType::Modifier::Unsigned)},
|
||||||
|
{make_unique<IntegerType>(8 * 32, IntegerType::Modifier::Unsigned)}
|
||||||
|
}};
|
||||||
|
|
||||||
|
array<unique_ptr<FixedBytesType>, 32> const TypeProvider::m_bytesM{{
|
||||||
|
{make_unique<FixedBytesType>(1)},
|
||||||
|
{make_unique<FixedBytesType>(2)},
|
||||||
|
{make_unique<FixedBytesType>(3)},
|
||||||
|
{make_unique<FixedBytesType>(4)},
|
||||||
|
{make_unique<FixedBytesType>(5)},
|
||||||
|
{make_unique<FixedBytesType>(6)},
|
||||||
|
{make_unique<FixedBytesType>(7)},
|
||||||
|
{make_unique<FixedBytesType>(8)},
|
||||||
|
{make_unique<FixedBytesType>(9)},
|
||||||
|
{make_unique<FixedBytesType>(10)},
|
||||||
|
{make_unique<FixedBytesType>(11)},
|
||||||
|
{make_unique<FixedBytesType>(12)},
|
||||||
|
{make_unique<FixedBytesType>(13)},
|
||||||
|
{make_unique<FixedBytesType>(14)},
|
||||||
|
{make_unique<FixedBytesType>(15)},
|
||||||
|
{make_unique<FixedBytesType>(16)},
|
||||||
|
{make_unique<FixedBytesType>(17)},
|
||||||
|
{make_unique<FixedBytesType>(18)},
|
||||||
|
{make_unique<FixedBytesType>(19)},
|
||||||
|
{make_unique<FixedBytesType>(20)},
|
||||||
|
{make_unique<FixedBytesType>(21)},
|
||||||
|
{make_unique<FixedBytesType>(22)},
|
||||||
|
{make_unique<FixedBytesType>(23)},
|
||||||
|
{make_unique<FixedBytesType>(24)},
|
||||||
|
{make_unique<FixedBytesType>(25)},
|
||||||
|
{make_unique<FixedBytesType>(26)},
|
||||||
|
{make_unique<FixedBytesType>(27)},
|
||||||
|
{make_unique<FixedBytesType>(28)},
|
||||||
|
{make_unique<FixedBytesType>(29)},
|
||||||
|
{make_unique<FixedBytesType>(30)},
|
||||||
|
{make_unique<FixedBytesType>(31)},
|
||||||
|
{make_unique<FixedBytesType>(32)}
|
||||||
|
}};
|
||||||
|
|
||||||
|
array<unique_ptr<MagicType>, 4> const TypeProvider::m_magicTypes{{
|
||||||
|
{make_unique<MagicType>(MagicType::Kind::Block)},
|
||||||
|
{make_unique<MagicType>(MagicType::Kind::Message)},
|
||||||
|
{make_unique<MagicType>(MagicType::Kind::Transaction)},
|
||||||
|
{make_unique<MagicType>(MagicType::Kind::ABI)}
|
||||||
|
// MetaType is stored separately
|
||||||
|
}};
|
||||||
|
|
||||||
|
inline void clearCache(Type const& type)
|
||||||
|
{
|
||||||
|
type.clearCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline void clearCache(unique_ptr<T> const& type)
|
||||||
|
{
|
||||||
|
// Some lazy-initialized types might not exist yet.
|
||||||
|
if (type)
|
||||||
|
type->clearCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Container>
|
||||||
|
inline void clearCaches(Container& container)
|
||||||
|
{
|
||||||
|
for (auto const& e: container)
|
||||||
|
clearCache(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TypeProvider::reset()
|
||||||
|
{
|
||||||
|
clearCache(m_boolType);
|
||||||
|
clearCache(m_inaccessibleDynamicType);
|
||||||
|
clearCache(m_bytesStorageType);
|
||||||
|
clearCache(m_bytesMemoryType);
|
||||||
|
clearCache(m_stringStorageType);
|
||||||
|
clearCache(m_stringMemoryType);
|
||||||
|
clearCache(m_emptyTupleType);
|
||||||
|
clearCache(m_payableAddressType);
|
||||||
|
clearCache(m_addressType);
|
||||||
|
clearCaches(instance().m_intM);
|
||||||
|
clearCaches(instance().m_uintM);
|
||||||
|
clearCaches(instance().m_bytesM);
|
||||||
|
clearCaches(instance().m_magicTypes);
|
||||||
|
|
||||||
|
instance().m_generalTypes.clear();
|
||||||
|
instance().m_stringLiteralTypes.clear();
|
||||||
|
instance().m_ufixedMxN.clear();
|
||||||
|
instance().m_fixedMxN.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename... Args>
|
||||||
|
inline T const* TypeProvider::createAndGet(Args&& ... _args)
|
||||||
|
{
|
||||||
|
instance().m_generalTypes.emplace_back(make_unique<T>(std::forward<Args>(_args)...));
|
||||||
|
return static_cast<T const*>(instance().m_generalTypes.back().get());
|
||||||
|
}
|
||||||
|
|
||||||
|
Type const* TypeProvider::fromElementaryTypeName(ElementaryTypeNameToken const& _type)
|
||||||
|
{
|
||||||
|
solAssert(
|
||||||
|
TokenTraits::isElementaryTypeName(_type.token()),
|
||||||
|
"Expected an elementary type name but got " + _type.toString()
|
||||||
|
);
|
||||||
|
|
||||||
|
unsigned const m = _type.firstNumber();
|
||||||
|
unsigned const n = _type.secondNumber();
|
||||||
|
|
||||||
|
switch (_type.token())
|
||||||
|
{
|
||||||
|
case Token::IntM:
|
||||||
|
return integerType(m, IntegerType::Modifier::Signed);
|
||||||
|
case Token::UIntM:
|
||||||
|
return integerType(m, IntegerType::Modifier::Unsigned);
|
||||||
|
case Token::Byte:
|
||||||
|
return byteType();
|
||||||
|
case Token::BytesM:
|
||||||
|
return fixedBytesType(m);
|
||||||
|
case Token::FixedMxN:
|
||||||
|
return fixedPointType(m, n, FixedPointType::Modifier::Signed);
|
||||||
|
case Token::UFixedMxN:
|
||||||
|
return fixedPointType(m, n, FixedPointType::Modifier::Unsigned);
|
||||||
|
case Token::Int:
|
||||||
|
return integerType(256, IntegerType::Modifier::Signed);
|
||||||
|
case Token::UInt:
|
||||||
|
return integerType(256, IntegerType::Modifier::Unsigned);
|
||||||
|
case Token::Fixed:
|
||||||
|
return fixedPointType(128, 18, FixedPointType::Modifier::Signed);
|
||||||
|
case Token::UFixed:
|
||||||
|
return fixedPointType(128, 18, FixedPointType::Modifier::Unsigned);
|
||||||
|
case Token::Address:
|
||||||
|
return addressType();
|
||||||
|
case Token::Bool:
|
||||||
|
return boolType();
|
||||||
|
case Token::Bytes:
|
||||||
|
return bytesStorageType();
|
||||||
|
case Token::String:
|
||||||
|
return stringStorageType();
|
||||||
|
default:
|
||||||
|
solAssert(
|
||||||
|
false,
|
||||||
|
"Unable to convert elementary typename " + _type.toString() + " to type."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TypePointer TypeProvider::fromElementaryTypeName(string const& _name)
|
||||||
|
{
|
||||||
|
vector<string> nameParts;
|
||||||
|
boost::split(nameParts, _name, boost::is_any_of(" "));
|
||||||
|
solAssert(nameParts.size() == 1 || nameParts.size() == 2, "Cannot parse elementary type: " + _name);
|
||||||
|
|
||||||
|
Token token;
|
||||||
|
unsigned short firstNum, secondNum;
|
||||||
|
tie(token, firstNum, secondNum) = TokenTraits::fromIdentifierOrKeyword(nameParts[0]);
|
||||||
|
|
||||||
|
auto t = fromElementaryTypeName(ElementaryTypeNameToken(token, firstNum, secondNum));
|
||||||
|
if (auto* ref = dynamic_cast<ReferenceType const*>(t))
|
||||||
|
{
|
||||||
|
DataLocation location = DataLocation::Storage;
|
||||||
|
if (nameParts.size() == 2)
|
||||||
|
{
|
||||||
|
if (nameParts[1] == "storage")
|
||||||
|
location = DataLocation::Storage;
|
||||||
|
else if (nameParts[1] == "calldata")
|
||||||
|
location = DataLocation::CallData;
|
||||||
|
else if (nameParts[1] == "memory")
|
||||||
|
location = DataLocation::Memory;
|
||||||
|
else
|
||||||
|
solAssert(false, "Unknown data location: " + nameParts[1]);
|
||||||
|
}
|
||||||
|
return withLocation(ref, location, true);
|
||||||
|
}
|
||||||
|
else if (t->category() == Type::Category::Address)
|
||||||
|
{
|
||||||
|
if (nameParts.size() == 2)
|
||||||
|
{
|
||||||
|
if (nameParts[1] == "payable")
|
||||||
|
return payableAddressType();
|
||||||
|
else
|
||||||
|
solAssert(false, "Invalid state mutability for address type: " + nameParts[1]);
|
||||||
|
}
|
||||||
|
return addressType();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
solAssert(nameParts.size() == 1, "Storage location suffix only allowed for reference types");
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayType const* TypeProvider::bytesStorageType()
|
||||||
|
{
|
||||||
|
if (!m_bytesStorageType)
|
||||||
|
m_bytesStorageType = make_unique<ArrayType>(DataLocation::Storage, false);
|
||||||
|
return m_bytesStorageType.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayType const* TypeProvider::bytesMemoryType()
|
||||||
|
{
|
||||||
|
if (!m_bytesMemoryType)
|
||||||
|
m_bytesMemoryType = make_unique<ArrayType>(DataLocation::Memory, false);
|
||||||
|
return m_bytesMemoryType.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayType const* TypeProvider::stringStorageType()
|
||||||
|
{
|
||||||
|
if (!m_stringStorageType)
|
||||||
|
m_stringStorageType = make_unique<ArrayType>(DataLocation::Storage, true);
|
||||||
|
return m_stringStorageType.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayType const* TypeProvider::stringMemoryType()
|
||||||
|
{
|
||||||
|
if (!m_stringMemoryType)
|
||||||
|
m_stringMemoryType = make_unique<ArrayType>(DataLocation::Memory, true);
|
||||||
|
return m_stringMemoryType.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
TypePointer TypeProvider::forLiteral(Literal const& _literal)
|
||||||
|
{
|
||||||
|
switch (_literal.token())
|
||||||
|
{
|
||||||
|
case Token::TrueLiteral:
|
||||||
|
case Token::FalseLiteral:
|
||||||
|
return boolType();
|
||||||
|
case Token::Number:
|
||||||
|
return rationalNumberType(_literal);
|
||||||
|
case Token::StringLiteral:
|
||||||
|
return stringLiteralType(_literal.value());
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RationalNumberType const* TypeProvider::rationalNumberType(Literal const& _literal)
|
||||||
|
{
|
||||||
|
solAssert(_literal.token() == Token::Number, "");
|
||||||
|
std::tuple<bool, rational> validLiteral = RationalNumberType::isValidLiteral(_literal);
|
||||||
|
if (std::get<0>(validLiteral))
|
||||||
|
{
|
||||||
|
TypePointer compatibleBytesType = nullptr;
|
||||||
|
if (_literal.isHexNumber())
|
||||||
|
{
|
||||||
|
size_t const digitCount = _literal.valueWithoutUnderscores().length() - 2;
|
||||||
|
if (digitCount % 2 == 0 && (digitCount / 2) <= 32)
|
||||||
|
compatibleBytesType = fixedBytesType(digitCount / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rationalNumberType(std::get<1>(validLiteral), compatibleBytesType);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringLiteralType const* TypeProvider::stringLiteralType(string const& literal)
|
||||||
|
{
|
||||||
|
auto i = instance().m_stringLiteralTypes.find(literal);
|
||||||
|
if (i != instance().m_stringLiteralTypes.end())
|
||||||
|
return i->second.get();
|
||||||
|
else
|
||||||
|
return instance().m_stringLiteralTypes.emplace(literal, make_unique<StringLiteralType>(literal)).first->second.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
FixedPointType const* TypeProvider::fixedPointType(unsigned m, unsigned n, FixedPointType::Modifier _modifier)
|
||||||
|
{
|
||||||
|
auto& map = _modifier == FixedPointType::Modifier::Unsigned ? instance().m_ufixedMxN : instance().m_fixedMxN;
|
||||||
|
|
||||||
|
auto i = map.find(make_pair(m, n));
|
||||||
|
if (i != map.end())
|
||||||
|
return i->second.get();
|
||||||
|
|
||||||
|
return map.emplace(
|
||||||
|
make_pair(m, n),
|
||||||
|
make_unique<FixedPointType>(m, n, _modifier)
|
||||||
|
).first->second.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
TupleType const* TypeProvider::tupleType(vector<Type const*> members)
|
||||||
|
{
|
||||||
|
if (members.empty())
|
||||||
|
return &m_emptyTupleType;
|
||||||
|
|
||||||
|
return createAndGet<TupleType>(move(members));
|
||||||
|
}
|
||||||
|
|
||||||
|
ReferenceType const* TypeProvider::withLocation(ReferenceType const* _type, DataLocation _location, bool _isPointer)
|
||||||
|
{
|
||||||
|
if (_type->location() == _location && _type->isPointer() == _isPointer)
|
||||||
|
return _type;
|
||||||
|
|
||||||
|
instance().m_generalTypes.emplace_back(_type->copyForLocation(_location, _isPointer));
|
||||||
|
return static_cast<ReferenceType const*>(instance().m_generalTypes.back().get());
|
||||||
|
}
|
||||||
|
|
||||||
|
FunctionType const* TypeProvider::functionType(FunctionDefinition const& _function, bool _isInternal)
|
||||||
|
{
|
||||||
|
return createAndGet<FunctionType>(_function, _isInternal);
|
||||||
|
}
|
||||||
|
|
||||||
|
FunctionType const* TypeProvider::functionType(VariableDeclaration const& _varDecl)
|
||||||
|
{
|
||||||
|
return createAndGet<FunctionType>(_varDecl);
|
||||||
|
}
|
||||||
|
|
||||||
|
FunctionType const* TypeProvider::functionType(EventDefinition const& _def)
|
||||||
|
{
|
||||||
|
return createAndGet<FunctionType>(_def);
|
||||||
|
}
|
||||||
|
|
||||||
|
FunctionType const* TypeProvider::functionType(FunctionTypeName const& _typeName)
|
||||||
|
{
|
||||||
|
return createAndGet<FunctionType>(_typeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
FunctionType const* TypeProvider::functionType(
|
||||||
|
strings const& _parameterTypes,
|
||||||
|
strings const& _returnParameterTypes,
|
||||||
|
FunctionType::Kind _kind,
|
||||||
|
bool _arbitraryParameters,
|
||||||
|
StateMutability _stateMutability
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return createAndGet<FunctionType>(
|
||||||
|
_parameterTypes, _returnParameterTypes,
|
||||||
|
_kind, _arbitraryParameters, _stateMutability
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
FunctionType const* TypeProvider::functionType(
|
||||||
|
TypePointers const& _parameterTypes,
|
||||||
|
TypePointers const& _returnParameterTypes,
|
||||||
|
strings _parameterNames,
|
||||||
|
strings _returnParameterNames,
|
||||||
|
FunctionType::Kind _kind,
|
||||||
|
bool _arbitraryParameters,
|
||||||
|
StateMutability _stateMutability,
|
||||||
|
Declaration const* _declaration,
|
||||||
|
bool _gasSet,
|
||||||
|
bool _valueSet,
|
||||||
|
bool _bound
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return createAndGet<FunctionType>(
|
||||||
|
_parameterTypes,
|
||||||
|
_returnParameterTypes,
|
||||||
|
_parameterNames,
|
||||||
|
_returnParameterNames,
|
||||||
|
_kind,
|
||||||
|
_arbitraryParameters,
|
||||||
|
_stateMutability,
|
||||||
|
_declaration,
|
||||||
|
_gasSet,
|
||||||
|
_valueSet,
|
||||||
|
_bound
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
RationalNumberType const* TypeProvider::rationalNumberType(rational const& _value, Type const* _compatibleBytesType)
|
||||||
|
{
|
||||||
|
return createAndGet<RationalNumberType>(_value, _compatibleBytesType);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayType const* TypeProvider::arrayType(DataLocation _location, bool _isString)
|
||||||
|
{
|
||||||
|
if (_isString)
|
||||||
|
{
|
||||||
|
if (_location == DataLocation::Storage)
|
||||||
|
return stringStorageType();
|
||||||
|
if (_location == DataLocation::Memory)
|
||||||
|
return stringMemoryType();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_location == DataLocation::Storage)
|
||||||
|
return bytesStorageType();
|
||||||
|
if (_location == DataLocation::Memory)
|
||||||
|
return bytesMemoryType();
|
||||||
|
}
|
||||||
|
return createAndGet<ArrayType>(_location, _isString);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayType const* TypeProvider::arrayType(DataLocation _location, Type const* _baseType)
|
||||||
|
{
|
||||||
|
return createAndGet<ArrayType>(_location, _baseType);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayType const* TypeProvider::arrayType(DataLocation _location, Type const* _baseType, u256 const& _length)
|
||||||
|
{
|
||||||
|
return createAndGet<ArrayType>(_location, _baseType, _length);
|
||||||
|
}
|
||||||
|
|
||||||
|
ContractType const* TypeProvider::contractType(ContractDefinition const& _contractDef, bool _isSuper)
|
||||||
|
{
|
||||||
|
return createAndGet<ContractType>(_contractDef, _isSuper);
|
||||||
|
}
|
||||||
|
|
||||||
|
EnumType const* TypeProvider::enumType(EnumDefinition const& _enumDef)
|
||||||
|
{
|
||||||
|
return createAndGet<EnumType>(_enumDef);
|
||||||
|
}
|
||||||
|
|
||||||
|
ModuleType const* TypeProvider::moduleType(SourceUnit const& _source)
|
||||||
|
{
|
||||||
|
return createAndGet<ModuleType>(_source);
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeType const* TypeProvider::typeType(Type const* _actualType)
|
||||||
|
{
|
||||||
|
return createAndGet<TypeType>(_actualType);
|
||||||
|
}
|
||||||
|
|
||||||
|
StructType const* TypeProvider::structType(StructDefinition const& _struct, DataLocation _location)
|
||||||
|
{
|
||||||
|
return createAndGet<StructType>(_struct, _location);
|
||||||
|
}
|
||||||
|
|
||||||
|
ModifierType const* TypeProvider::modifierType(ModifierDefinition const& _def)
|
||||||
|
{
|
||||||
|
return createAndGet<ModifierType>(_def);
|
||||||
|
}
|
||||||
|
|
||||||
|
MagicType const* TypeProvider::magicType(MagicType::Kind _kind)
|
||||||
|
{
|
||||||
|
solAssert(_kind != MagicType::Kind::MetaType, "MetaType is handled separately");
|
||||||
|
return m_magicTypes.at(static_cast<size_t>(_kind)).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
MagicType const* TypeProvider::metaType(Type const* _type)
|
||||||
|
{
|
||||||
|
solAssert(_type && _type->category() == Type::Category::Contract, "Only contracts supported for now.");
|
||||||
|
return createAndGet<MagicType>(_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
MappingType const* TypeProvider::mappingType(Type const* _keyType, Type const* _valueType)
|
||||||
|
{
|
||||||
|
return createAndGet<MappingType>(_keyType, _valueType);
|
||||||
|
}
|
224
libsolidity/ast/TypeProvider.h
Normal file
224
libsolidity/ast/TypeProvider.h
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
/*
|
||||||
|
This file is part of solidity.
|
||||||
|
|
||||||
|
solidity 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.
|
||||||
|
|
||||||
|
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <libsolidity/ast/Types.h>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace dev
|
||||||
|
{
|
||||||
|
namespace solidity
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API for accessing the Solidity Type System.
|
||||||
|
*
|
||||||
|
* This is the Solidity Compiler's type provider. Use it to request for types. The caller does
|
||||||
|
* <b>not</b> own the types.
|
||||||
|
*
|
||||||
|
* It is not recommended to explicitly instantiate types unless you really know what and why
|
||||||
|
* you are doing it.
|
||||||
|
*/
|
||||||
|
class TypeProvider
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TypeProvider() = default;
|
||||||
|
TypeProvider(TypeProvider&&) = default;
|
||||||
|
TypeProvider(TypeProvider const&) = delete;
|
||||||
|
TypeProvider& operator=(TypeProvider&&) = default;
|
||||||
|
TypeProvider& operator=(TypeProvider const&) = delete;
|
||||||
|
~TypeProvider() = default;
|
||||||
|
|
||||||
|
/// Resets state of this TypeProvider to initial state, wiping all mutable types.
|
||||||
|
/// This invalidates all dangling pointers to types provided by this TypeProvider.
|
||||||
|
static void reset();
|
||||||
|
|
||||||
|
/// @name Factory functions
|
||||||
|
/// Factory functions that convert an AST @ref TypeName to a Type.
|
||||||
|
static Type const* fromElementaryTypeName(ElementaryTypeNameToken const& _type);
|
||||||
|
|
||||||
|
/// Converts a given elementary type name with optional data location
|
||||||
|
/// suffix " storage", " calldata" or " memory" to a type pointer. If suffix not given, defaults to " storage".
|
||||||
|
static TypePointer fromElementaryTypeName(std::string const& _name);
|
||||||
|
|
||||||
|
/// @returns boolean type.
|
||||||
|
static BoolType const* boolType() noexcept { return &m_boolType; }
|
||||||
|
|
||||||
|
static FixedBytesType const* byteType() { return fixedBytesType(1); }
|
||||||
|
static FixedBytesType const* fixedBytesType(unsigned m) { return m_bytesM.at(m - 1).get(); }
|
||||||
|
|
||||||
|
static ArrayType const* bytesStorageType();
|
||||||
|
static ArrayType const* bytesMemoryType();
|
||||||
|
static ArrayType const* stringStorageType();
|
||||||
|
static ArrayType const* stringMemoryType();
|
||||||
|
|
||||||
|
/// Constructor for a byte array ("bytes") and string.
|
||||||
|
static ArrayType const* arrayType(DataLocation _location, bool _isString = false);
|
||||||
|
|
||||||
|
/// Constructor for a dynamically sized array type ("type[]")
|
||||||
|
static ArrayType const* arrayType(DataLocation _location, Type const* _baseType);
|
||||||
|
|
||||||
|
/// Constructor for a fixed-size array type ("type[20]")
|
||||||
|
static ArrayType const* arrayType(DataLocation _location, Type const* _baseType, u256 const& _length);
|
||||||
|
|
||||||
|
static AddressType const* payableAddressType() noexcept { return &m_payableAddressType; }
|
||||||
|
static AddressType const* addressType() noexcept { return &m_addressType; }
|
||||||
|
|
||||||
|
static IntegerType const* integerType(unsigned _bits, IntegerType::Modifier _modifier)
|
||||||
|
{
|
||||||
|
solAssert((_bits % 8) == 0, "");
|
||||||
|
if (_modifier == IntegerType::Modifier::Unsigned)
|
||||||
|
return m_uintM.at(_bits / 8 - 1).get();
|
||||||
|
else
|
||||||
|
return m_intM.at(_bits / 8 - 1).get();
|
||||||
|
}
|
||||||
|
static IntegerType const* uint(unsigned _bits) { return integerType(_bits, IntegerType::Modifier::Unsigned); }
|
||||||
|
|
||||||
|
static IntegerType const* uint256() { return uint(256); }
|
||||||
|
|
||||||
|
static FixedPointType const* fixedPointType(unsigned m, unsigned n, FixedPointType::Modifier _modifier);
|
||||||
|
|
||||||
|
static StringLiteralType const* stringLiteralType(std::string const& literal);
|
||||||
|
|
||||||
|
/// @param members the member types the tuple type must contain. This is passed by value on purspose.
|
||||||
|
/// @returns a tuple type with the given members.
|
||||||
|
static TupleType const* tupleType(std::vector<Type const*> members);
|
||||||
|
|
||||||
|
static TupleType const* emptyTupleType() noexcept { return &m_emptyTupleType; }
|
||||||
|
|
||||||
|
static ReferenceType const* withLocation(ReferenceType const* _type, DataLocation _location, bool _isPointer);
|
||||||
|
|
||||||
|
/// @returns a copy of @a _type having the same location as this (and is not a pointer type)
|
||||||
|
/// if _type is a reference type and an unmodified copy of _type otherwise.
|
||||||
|
/// This function is mostly useful to modify inner types appropriately.
|
||||||
|
static Type const* withLocationIfReference(DataLocation _location, Type const* _type)
|
||||||
|
{
|
||||||
|
if (auto refType = dynamic_cast<ReferenceType const*>(_type))
|
||||||
|
return withLocation(refType, _location, false);
|
||||||
|
|
||||||
|
return _type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @returns the internally-facing or externally-facing type of a function.
|
||||||
|
static FunctionType const* functionType(FunctionDefinition const& _function, bool _isInternal = true);
|
||||||
|
|
||||||
|
/// @returns the accessor function type of a state variable.
|
||||||
|
static FunctionType const* functionType(VariableDeclaration const& _varDecl);
|
||||||
|
|
||||||
|
/// @returns the function type of an event.
|
||||||
|
static FunctionType const* functionType(EventDefinition const& _event);
|
||||||
|
|
||||||
|
/// @returns the type of a function type name.
|
||||||
|
static FunctionType const* functionType(FunctionTypeName const& _typeName);
|
||||||
|
|
||||||
|
/// @returns the function type to be used for a plain type (not derived from a declaration).
|
||||||
|
static FunctionType const* functionType(
|
||||||
|
strings const& _parameterTypes,
|
||||||
|
strings const& _returnParameterTypes,
|
||||||
|
FunctionType::Kind _kind = FunctionType::Kind::Internal,
|
||||||
|
bool _arbitraryParameters = false,
|
||||||
|
StateMutability _stateMutability = StateMutability::NonPayable
|
||||||
|
);
|
||||||
|
|
||||||
|
/// @returns a highly customized FunctionType, use with care.
|
||||||
|
static FunctionType const* functionType(
|
||||||
|
TypePointers const& _parameterTypes,
|
||||||
|
TypePointers const& _returnParameterTypes,
|
||||||
|
strings _parameterNames = strings{},
|
||||||
|
strings _returnParameterNames = strings{},
|
||||||
|
FunctionType::Kind _kind = FunctionType::Kind::Internal,
|
||||||
|
bool _arbitraryParameters = false,
|
||||||
|
StateMutability _stateMutability = StateMutability::NonPayable,
|
||||||
|
Declaration const* _declaration = nullptr,
|
||||||
|
bool _gasSet = false,
|
||||||
|
bool _valueSet = false,
|
||||||
|
bool _bound = false
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Auto-detect the proper type for a literal. @returns an empty pointer if the literal does
|
||||||
|
/// not fit any type.
|
||||||
|
static TypePointer forLiteral(Literal const& _literal);
|
||||||
|
static RationalNumberType const* rationalNumberType(Literal const& _literal);
|
||||||
|
|
||||||
|
static RationalNumberType const* rationalNumberType(
|
||||||
|
rational const& _value,
|
||||||
|
Type const* _compatibleBytesType = nullptr
|
||||||
|
);
|
||||||
|
|
||||||
|
static ContractType const* contractType(ContractDefinition const& _contract, bool _isSuper = false);
|
||||||
|
|
||||||
|
static InaccessibleDynamicType const* inaccessibleDynamicType() noexcept { return &m_inaccessibleDynamicType; }
|
||||||
|
|
||||||
|
/// @returns the type of an enum instance for given definition, there is one distinct type per enum definition.
|
||||||
|
static EnumType const* enumType(EnumDefinition const& _enum);
|
||||||
|
|
||||||
|
/// @returns special type for imported modules. These mainly give access to their scope via members.
|
||||||
|
static ModuleType const* moduleType(SourceUnit const& _source);
|
||||||
|
|
||||||
|
static TypeType const* typeType(Type const* _actualType);
|
||||||
|
|
||||||
|
static StructType const* structType(StructDefinition const& _struct, DataLocation _location);
|
||||||
|
|
||||||
|
static ModifierType const* modifierType(ModifierDefinition const& _modifierDef);
|
||||||
|
|
||||||
|
static MagicType const* magicType(MagicType::Kind _kind);
|
||||||
|
|
||||||
|
static MagicType const* metaType(Type const* _type);
|
||||||
|
|
||||||
|
static MappingType const* mappingType(Type const* _keyType, Type const* _valueType);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// Global TypeProvider instance.
|
||||||
|
static TypeProvider& instance()
|
||||||
|
{
|
||||||
|
static TypeProvider _provider;
|
||||||
|
return _provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename... Args>
|
||||||
|
static inline T const* createAndGet(Args&& ... _args);
|
||||||
|
|
||||||
|
static BoolType const m_boolType;
|
||||||
|
static InaccessibleDynamicType const m_inaccessibleDynamicType;
|
||||||
|
|
||||||
|
/// These are lazy-initialized because they depend on `byte` being available.
|
||||||
|
static std::unique_ptr<ArrayType> m_bytesStorageType;
|
||||||
|
static std::unique_ptr<ArrayType> m_bytesMemoryType;
|
||||||
|
static std::unique_ptr<ArrayType> m_stringStorageType;
|
||||||
|
static std::unique_ptr<ArrayType> m_stringMemoryType;
|
||||||
|
|
||||||
|
static TupleType const m_emptyTupleType;
|
||||||
|
static AddressType const m_payableAddressType;
|
||||||
|
static AddressType const m_addressType;
|
||||||
|
static std::array<std::unique_ptr<IntegerType>, 32> const m_intM;
|
||||||
|
static std::array<std::unique_ptr<IntegerType>, 32> const m_uintM;
|
||||||
|
static std::array<std::unique_ptr<FixedBytesType>, 32> const m_bytesM;
|
||||||
|
static std::array<std::unique_ptr<MagicType>, 4> const m_magicTypes; ///< MagicType's except MetaType
|
||||||
|
|
||||||
|
std::map<std::pair<unsigned, unsigned>, std::unique_ptr<FixedPointType>> m_ufixedMxN{};
|
||||||
|
std::map<std::pair<unsigned, unsigned>, std::unique_ptr<FixedPointType>> m_fixedMxN{};
|
||||||
|
std::map<std::string, std::unique_ptr<StringLiteralType>> m_stringLiteralTypes{};
|
||||||
|
std::vector<std::unique_ptr<Type>> m_generalTypes{};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace solidity
|
||||||
|
} // namespace dev
|
File diff suppressed because it is too large
Load Diff
@ -32,7 +32,6 @@
|
|||||||
#include <libdevcore/Result.h>
|
#include <libdevcore/Result.h>
|
||||||
|
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
#include <boost/noncopyable.hpp>
|
|
||||||
#include <boost/rational.hpp>
|
#include <boost/rational.hpp>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
@ -45,10 +44,11 @@ namespace dev
|
|||||||
namespace solidity
|
namespace solidity
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class TypeProvider;
|
||||||
class Type; // forward
|
class Type; // forward
|
||||||
class FunctionType; // forward
|
class FunctionType; // forward
|
||||||
using TypePointer = std::shared_ptr<Type const>;
|
using TypePointer = Type const*;
|
||||||
using FunctionTypePointer = std::shared_ptr<FunctionType const>;
|
using FunctionTypePointer = FunctionType const*;
|
||||||
using TypePointers = std::vector<TypePointer>;
|
using TypePointers = std::vector<TypePointer>;
|
||||||
using rational = boost::rational<dev::bigint>;
|
using rational = boost::rational<dev::bigint>;
|
||||||
using TypeResult = Result<TypePointer>;
|
using TypeResult = Result<TypePointer>;
|
||||||
@ -94,7 +94,7 @@ class MemberList
|
|||||||
public:
|
public:
|
||||||
struct Member
|
struct Member
|
||||||
{
|
{
|
||||||
Member(std::string const& _name, TypePointer const& _type, Declaration const* _declaration = nullptr):
|
Member(std::string const& _name, Type const* _type, Declaration const* _declaration = nullptr):
|
||||||
name(_name),
|
name(_name),
|
||||||
type(_type),
|
type(_type),
|
||||||
declaration(_declaration)
|
declaration(_declaration)
|
||||||
@ -102,17 +102,18 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
TypePointer type;
|
Type const* type;
|
||||||
Declaration const* declaration = nullptr;
|
Declaration const* declaration = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
using MemberMap = std::vector<Member>;
|
using MemberMap = std::vector<Member>;
|
||||||
|
|
||||||
explicit MemberList(MemberMap const& _members): m_memberTypes(_members) {}
|
explicit MemberList(MemberMap const& _members): m_memberTypes(_members) {}
|
||||||
|
|
||||||
void combine(MemberList const& _other);
|
void combine(MemberList const& _other);
|
||||||
TypePointer memberType(std::string const& _name) const
|
TypePointer memberType(std::string const& _name) const
|
||||||
{
|
{
|
||||||
TypePointer type;
|
TypePointer type = nullptr;
|
||||||
for (auto const& it: m_memberTypes)
|
for (auto const& it: m_memberTypes)
|
||||||
if (it.name == _name)
|
if (it.name == _name)
|
||||||
{
|
{
|
||||||
@ -148,10 +149,16 @@ static_assert(std::is_nothrow_move_constructible<MemberList>::value, "MemberList
|
|||||||
/**
|
/**
|
||||||
* Abstract base class that forms the root of the type hierarchy.
|
* Abstract base class that forms the root of the type hierarchy.
|
||||||
*/
|
*/
|
||||||
class Type: private boost::noncopyable, public std::enable_shared_from_this<Type>
|
class Type
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
Type() = default;
|
||||||
|
Type(Type const&) = delete;
|
||||||
|
Type(Type&&) = delete;
|
||||||
|
Type& operator=(Type const&) = delete;
|
||||||
|
Type& operator=(Type&&) = delete;
|
||||||
virtual ~Type() = default;
|
virtual ~Type() = default;
|
||||||
|
|
||||||
enum class Category
|
enum class Category
|
||||||
{
|
{
|
||||||
Address, Integer, RationalNumber, StringLiteral, Bool, FixedPoint, Array,
|
Address, Integer, RationalNumber, StringLiteral, Bool, FixedPoint, Array,
|
||||||
@ -160,20 +167,8 @@ public:
|
|||||||
InaccessibleDynamic
|
InaccessibleDynamic
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @{
|
|
||||||
/// @name Factory functions
|
|
||||||
/// Factory functions that convert an AST @ref TypeName to a Type.
|
|
||||||
static TypePointer fromElementaryTypeName(ElementaryTypeNameToken const& _type);
|
|
||||||
/// Converts a given elementary type name with optional data location
|
|
||||||
/// suffix " storage", " calldata" or " memory" to a type pointer. If suffix not given, defaults to " storage".
|
|
||||||
static TypePointer fromElementaryTypeName(std::string const& _name);
|
|
||||||
/// @}
|
|
||||||
|
|
||||||
/// Auto-detect the proper type for a literal. @returns an empty pointer if the literal does
|
|
||||||
/// not fit any type.
|
|
||||||
static TypePointer forLiteral(Literal const& _literal);
|
|
||||||
/// @returns a pointer to _a or _b if the other is implicitly convertible to it or nullptr otherwise
|
/// @returns a pointer to _a or _b if the other is implicitly convertible to it or nullptr otherwise
|
||||||
static TypePointer commonType(TypePointer const& _a, TypePointer const& _b);
|
static TypePointer commonType(Type const* _a, Type const* _b);
|
||||||
|
|
||||||
virtual Category category() const = 0;
|
virtual Category category() const = 0;
|
||||||
/// @returns a valid solidity identifier such that two types should compare equal if and
|
/// @returns a valid solidity identifier such that two types should compare equal if and
|
||||||
@ -201,13 +196,13 @@ public:
|
|||||||
/// @returns the resulting type of applying the given unary operator or an empty pointer if
|
/// @returns the resulting type of applying the given unary operator or an empty pointer if
|
||||||
/// this is not possible.
|
/// this is not possible.
|
||||||
/// The default implementation does not allow any unary operator.
|
/// The default implementation does not allow any unary operator.
|
||||||
virtual TypeResult unaryOperatorResult(Token) const { return TypePointer(); }
|
virtual TypeResult unaryOperatorResult(Token) const { return nullptr; }
|
||||||
/// @returns the resulting type of applying the given binary operator or an empty pointer if
|
/// @returns the resulting type of applying the given binary operator or an empty pointer if
|
||||||
/// this is not possible.
|
/// this is not possible.
|
||||||
/// The default implementation allows comparison operators if a common type exists
|
/// The default implementation allows comparison operators if a common type exists
|
||||||
virtual TypeResult binaryOperatorResult(Token _operator, TypePointer const& _other) const
|
virtual TypeResult binaryOperatorResult(Token _operator, Type const* _other) const
|
||||||
{
|
{
|
||||||
return TokenTraits::isCompareOp(_operator) ? commonType(shared_from_this(), _other) : TypePointer();
|
return TokenTraits::isCompareOp(_operator) ? commonType(this, _other) : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool operator==(Type const& _other) const { return category() == _other.category(); }
|
virtual bool operator==(Type const& _other) const { return category() == _other.category(); }
|
||||||
@ -258,14 +253,14 @@ public:
|
|||||||
/// This returns the corresponding IntegerType or FixedPointType for RationalNumberType
|
/// This returns the corresponding IntegerType or FixedPointType for RationalNumberType
|
||||||
/// and the pointer type for storage reference types.
|
/// and the pointer type for storage reference types.
|
||||||
/// Might return a null pointer if there is no fitting type.
|
/// Might return a null pointer if there is no fitting type.
|
||||||
virtual TypePointer mobileType() const { return shared_from_this(); }
|
virtual TypePointer mobileType() const { return this; }
|
||||||
/// @returns true if this is a non-value type and the data of this type is stored at the
|
/// @returns true if this is a non-value type and the data of this type is stored at the
|
||||||
/// given location.
|
/// given location.
|
||||||
virtual bool dataStoredIn(DataLocation) const { return false; }
|
virtual bool dataStoredIn(DataLocation) const { return false; }
|
||||||
/// @returns the type of a temporary during assignment to a variable of the given type.
|
/// @returns the type of a temporary during assignment to a variable of the given type.
|
||||||
/// Specifically, returns the requested itself if it can be dynamically allocated (or is a value type)
|
/// Specifically, returns the requested itself if it can be dynamically allocated (or is a value type)
|
||||||
/// and the mobile type otherwise.
|
/// and the mobile type otherwise.
|
||||||
virtual TypePointer closestTemporaryType(TypePointer const& _targetType) const
|
virtual TypePointer closestTemporaryType(Type const* _targetType) const
|
||||||
{
|
{
|
||||||
return _targetType->dataStoredIn(DataLocation::Storage) ? mobileType() : _targetType;
|
return _targetType->dataStoredIn(DataLocation::Storage) ? mobileType() : _targetType;
|
||||||
}
|
}
|
||||||
@ -298,7 +293,7 @@ public:
|
|||||||
/// @returns a (simpler) type that is encoded in the same way for external function calls.
|
/// @returns a (simpler) type that is encoded in the same way for external function calls.
|
||||||
/// This for example returns address for contract types.
|
/// This for example returns address for contract types.
|
||||||
/// If there is no such type, returns an empty shared pointer.
|
/// If there is no such type, returns an empty shared pointer.
|
||||||
virtual TypePointer encodingType() const { return TypePointer(); }
|
virtual TypePointer encodingType() const { return nullptr; }
|
||||||
/// @returns the encoding type used under the given circumstances for the type of an expression
|
/// @returns the encoding type used under the given circumstances for the type of an expression
|
||||||
/// when used for e.g. abi.encode(...) or the empty pointer if the object
|
/// when used for e.g. abi.encode(...) or the empty pointer if the object
|
||||||
/// cannot be encoded.
|
/// cannot be encoded.
|
||||||
@ -311,7 +306,10 @@ public:
|
|||||||
/// If there is no such type, returns an empty shared pointer.
|
/// If there is no such type, returns an empty shared pointer.
|
||||||
/// @param _inLibrary if set, returns types as used in a library, e.g. struct and contract types
|
/// @param _inLibrary if set, returns types as used in a library, e.g. struct and contract types
|
||||||
/// are returned without modification.
|
/// are returned without modification.
|
||||||
virtual TypeResult interfaceType(bool /*_inLibrary*/) const { return TypePointer(); }
|
virtual TypeResult interfaceType(bool /*_inLibrary*/) const { return nullptr; }
|
||||||
|
|
||||||
|
/// Clears all internally cached values (if any).
|
||||||
|
virtual void clearCache() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// @returns a member list containing all members added to this type by `using for` directives.
|
/// @returns a member list containing all members added to this type by `using for` directives.
|
||||||
@ -335,18 +333,15 @@ protected:
|
|||||||
class AddressType: public Type
|
class AddressType: public Type
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static AddressType& address() { static std::shared_ptr<AddressType> addr(std::make_shared<AddressType>(StateMutability::NonPayable)); return *addr; }
|
explicit AddressType(StateMutability _stateMutability);
|
||||||
static AddressType& addressPayable() { static std::shared_ptr<AddressType> addr(std::make_shared<AddressType>(StateMutability::Payable)); return *addr; }
|
|
||||||
|
|
||||||
Category category() const override { return Category::Address; }
|
Category category() const override { return Category::Address; }
|
||||||
|
|
||||||
explicit AddressType(StateMutability _stateMutability);
|
|
||||||
|
|
||||||
std::string richIdentifier() const override;
|
std::string richIdentifier() const override;
|
||||||
BoolResult isImplicitlyConvertibleTo(Type const& _other) const override;
|
BoolResult isImplicitlyConvertibleTo(Type const& _other) const override;
|
||||||
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||||
TypeResult unaryOperatorResult(Token _operator) const override;
|
TypeResult unaryOperatorResult(Token _operator) const override;
|
||||||
TypeResult binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
|
TypeResult binaryOperatorResult(Token _operator, Type const* _other) const override;
|
||||||
|
|
||||||
bool operator==(Type const& _other) const override;
|
bool operator==(Type const& _other) const override;
|
||||||
|
|
||||||
@ -362,8 +357,8 @@ public:
|
|||||||
|
|
||||||
u256 literalValue(Literal const* _literal) const override;
|
u256 literalValue(Literal const* _literal) const override;
|
||||||
|
|
||||||
TypePointer encodingType() const override { return shared_from_this(); }
|
TypePointer encodingType() const override { return this; }
|
||||||
TypeResult interfaceType(bool) const override { return shared_from_this(); }
|
TypeResult interfaceType(bool) const override { return this; }
|
||||||
|
|
||||||
StateMutability stateMutability(void) const { return m_stateMutability; }
|
StateMutability stateMutability(void) const { return m_stateMutability; }
|
||||||
|
|
||||||
@ -382,17 +377,15 @@ public:
|
|||||||
Unsigned, Signed
|
Unsigned, Signed
|
||||||
};
|
};
|
||||||
|
|
||||||
static IntegerType& uint256() { static std::shared_ptr<IntegerType> uint256(std::make_shared<IntegerType>(256)); return *uint256; }
|
explicit IntegerType(unsigned _bits, Modifier _modifier = Modifier::Unsigned);
|
||||||
|
|
||||||
Category category() const override { return Category::Integer; }
|
Category category() const override { return Category::Integer; }
|
||||||
|
|
||||||
explicit IntegerType(unsigned _bits, Modifier _modifier = Modifier::Unsigned);
|
|
||||||
|
|
||||||
std::string richIdentifier() const override;
|
std::string richIdentifier() const override;
|
||||||
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
|
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||||
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||||
TypeResult unaryOperatorResult(Token _operator) const override;
|
TypeResult unaryOperatorResult(Token _operator) const override;
|
||||||
TypeResult binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
|
TypeResult binaryOperatorResult(Token _operator, Type const* _other) const override;
|
||||||
|
|
||||||
bool operator==(Type const& _other) const override;
|
bool operator==(Type const& _other) const override;
|
||||||
|
|
||||||
@ -403,8 +396,8 @@ public:
|
|||||||
|
|
||||||
std::string toString(bool _short) const override;
|
std::string toString(bool _short) const override;
|
||||||
|
|
||||||
TypePointer encodingType() const override { return shared_from_this(); }
|
TypePointer encodingType() const override { return this; }
|
||||||
TypeResult interfaceType(bool) const override { return shared_from_this(); }
|
TypeResult interfaceType(bool) const override { return this; }
|
||||||
|
|
||||||
unsigned numBits() const { return m_bits; }
|
unsigned numBits() const { return m_bits; }
|
||||||
bool isSigned() const { return m_modifier == Modifier::Signed; }
|
bool isSigned() const { return m_modifier == Modifier::Signed; }
|
||||||
@ -413,8 +406,8 @@ public:
|
|||||||
bigint maxValue() const;
|
bigint maxValue() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned m_bits;
|
unsigned const m_bits;
|
||||||
Modifier m_modifier;
|
Modifier const m_modifier;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -427,15 +420,15 @@ public:
|
|||||||
{
|
{
|
||||||
Unsigned, Signed
|
Unsigned, Signed
|
||||||
};
|
};
|
||||||
Category category() const override { return Category::FixedPoint; }
|
|
||||||
|
|
||||||
explicit FixedPointType(unsigned _totalBits, unsigned _fractionalDigits, Modifier _modifier = Modifier::Unsigned);
|
explicit FixedPointType(unsigned _totalBits, unsigned _fractionalDigits, Modifier _modifier = Modifier::Unsigned);
|
||||||
|
Category category() const override { return Category::FixedPoint; }
|
||||||
|
|
||||||
std::string richIdentifier() const override;
|
std::string richIdentifier() const override;
|
||||||
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
|
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||||
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||||
TypeResult unaryOperatorResult(Token _operator) const override;
|
TypeResult unaryOperatorResult(Token _operator) const override;
|
||||||
TypeResult binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
|
TypeResult binaryOperatorResult(Token _operator, Type const* _other) const override;
|
||||||
|
|
||||||
bool operator==(Type const& _other) const override;
|
bool operator==(Type const& _other) const override;
|
||||||
|
|
||||||
@ -446,8 +439,8 @@ public:
|
|||||||
|
|
||||||
std::string toString(bool _short) const override;
|
std::string toString(bool _short) const override;
|
||||||
|
|
||||||
TypePointer encodingType() const override { return shared_from_this(); }
|
TypePointer encodingType() const override { return this; }
|
||||||
TypeResult interfaceType(bool) const override { return shared_from_this(); }
|
TypeResult interfaceType(bool) const override { return this; }
|
||||||
|
|
||||||
/// Number of bits used for this type in total.
|
/// Number of bits used for this type in total.
|
||||||
unsigned numBits() const { return m_totalBits; }
|
unsigned numBits() const { return m_totalBits; }
|
||||||
@ -462,7 +455,7 @@ public:
|
|||||||
bigint minIntegerValue() const;
|
bigint minIntegerValue() const;
|
||||||
|
|
||||||
/// @returns the smallest integer type that can hold this type with fractional parts shifted to integers.
|
/// @returns the smallest integer type that can hold this type with fractional parts shifted to integers.
|
||||||
std::shared_ptr<IntegerType> asIntegerType() const;
|
IntegerType const* asIntegerType() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned m_totalBits;
|
unsigned m_totalBits;
|
||||||
@ -478,18 +471,16 @@ private:
|
|||||||
class RationalNumberType: public Type
|
class RationalNumberType: public Type
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
explicit RationalNumberType(rational const& _value, Type const* _compatibleBytesType = nullptr):
|
||||||
|
m_value(_value), m_compatibleBytesType(_compatibleBytesType)
|
||||||
|
{}
|
||||||
|
|
||||||
Category category() const override { return Category::RationalNumber; }
|
Category category() const override { return Category::RationalNumber; }
|
||||||
|
|
||||||
static TypePointer forLiteral(Literal const& _literal);
|
|
||||||
|
|
||||||
explicit RationalNumberType(rational const& _value, TypePointer const& _compatibleBytesType = TypePointer()):
|
|
||||||
m_value(_value), m_compatibleBytesType(_compatibleBytesType)
|
|
||||||
{}
|
|
||||||
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
|
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||||
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||||
TypeResult unaryOperatorResult(Token _operator) const override;
|
TypeResult unaryOperatorResult(Token _operator) const override;
|
||||||
TypeResult binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
|
TypeResult binaryOperatorResult(Token _operator, Type const* _other) const override;
|
||||||
|
|
||||||
std::string richIdentifier() const override;
|
std::string richIdentifier() const override;
|
||||||
bool operator==(Type const& _other) const override;
|
bool operator==(Type const& _other) const override;
|
||||||
@ -502,11 +493,11 @@ public:
|
|||||||
TypePointer mobileType() const override;
|
TypePointer mobileType() const override;
|
||||||
|
|
||||||
/// @returns the smallest integer type that can hold the value or an empty pointer if not possible.
|
/// @returns the smallest integer type that can hold the value or an empty pointer if not possible.
|
||||||
std::shared_ptr<IntegerType const> integerType() const;
|
IntegerType const* integerType() const;
|
||||||
/// @returns the smallest fixed type that can hold the value or incurs the least precision loss,
|
/// @returns the smallest fixed type that can hold the value or incurs the least precision loss,
|
||||||
/// unless the value was truncated, then a suitable type will be chosen to indicate such event.
|
/// unless the value was truncated, then a suitable type will be chosen to indicate such event.
|
||||||
/// If the integer part does not fit, returns an empty pointer.
|
/// If the integer part does not fit, returns an empty pointer.
|
||||||
std::shared_ptr<FixedPointType const> fixedPointType() const;
|
FixedPointType const* fixedPointType() const;
|
||||||
|
|
||||||
/// @returns true if the value is not an integer.
|
/// @returns true if the value is not an integer.
|
||||||
bool isFractional() const { return m_value.denominator() != 1; }
|
bool isFractional() const { return m_value.denominator() != 1; }
|
||||||
@ -517,6 +508,9 @@ public:
|
|||||||
/// @returns true if the value is zero.
|
/// @returns true if the value is zero.
|
||||||
bool isZero() const { return m_value == 0; }
|
bool isZero() const { return m_value == 0; }
|
||||||
|
|
||||||
|
/// @returns true if the literal is a valid integer.
|
||||||
|
static std::tuple<bool, rational> isValidLiteral(Literal const& _literal);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
rational m_value;
|
rational m_value;
|
||||||
|
|
||||||
@ -524,9 +518,6 @@ private:
|
|||||||
/// Empty for all rationals that are not directly parsed from hex literals.
|
/// Empty for all rationals that are not directly parsed from hex literals.
|
||||||
TypePointer m_compatibleBytesType;
|
TypePointer m_compatibleBytesType;
|
||||||
|
|
||||||
/// @returns true if the literal is a valid integer.
|
|
||||||
static std::tuple<bool, rational> isValidLiteral(Literal const& _literal);
|
|
||||||
|
|
||||||
/// @returns true if the literal is a valid rational number.
|
/// @returns true if the literal is a valid rational number.
|
||||||
static std::tuple<bool, rational> parseRational(std::string const& _value);
|
static std::tuple<bool, rational> parseRational(std::string const& _value);
|
||||||
|
|
||||||
@ -541,14 +532,15 @@ private:
|
|||||||
class StringLiteralType: public Type
|
class StringLiteralType: public Type
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
explicit StringLiteralType(Literal const& _literal);
|
||||||
|
explicit StringLiteralType(std::string const& _value);
|
||||||
|
|
||||||
Category category() const override { return Category::StringLiteral; }
|
Category category() const override { return Category::StringLiteral; }
|
||||||
|
|
||||||
explicit StringLiteralType(Literal const& _literal);
|
|
||||||
|
|
||||||
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
|
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||||
TypeResult binaryOperatorResult(Token, TypePointer const&) const override
|
TypeResult binaryOperatorResult(Token, Type const*) const override
|
||||||
{
|
{
|
||||||
return TypePointer();
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string richIdentifier() const override;
|
std::string richIdentifier() const override;
|
||||||
@ -575,16 +567,16 @@ private:
|
|||||||
class FixedBytesType: public Type
|
class FixedBytesType: public Type
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Category category() const override { return Category::FixedBytes; }
|
|
||||||
|
|
||||||
explicit FixedBytesType(unsigned _bytes);
|
explicit FixedBytesType(unsigned _bytes);
|
||||||
|
|
||||||
|
Category category() const override { return Category::FixedBytes; }
|
||||||
|
|
||||||
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
|
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||||
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||||
std::string richIdentifier() const override;
|
std::string richIdentifier() const override;
|
||||||
bool operator==(Type const& _other) const override;
|
bool operator==(Type const& _other) const override;
|
||||||
TypeResult unaryOperatorResult(Token _operator) const override;
|
TypeResult unaryOperatorResult(Token _operator) const override;
|
||||||
TypeResult binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
|
TypeResult binaryOperatorResult(Token _operator, Type const* _other) const override;
|
||||||
|
|
||||||
unsigned calldataEncodedSize(bool _padded) const override { return _padded && m_bytes > 0 ? 32 : m_bytes; }
|
unsigned calldataEncodedSize(bool _padded) const override { return _padded && m_bytes > 0 ? 32 : m_bytes; }
|
||||||
unsigned storageBytes() const override { return m_bytes; }
|
unsigned storageBytes() const override { return m_bytes; }
|
||||||
@ -593,8 +585,8 @@ public:
|
|||||||
|
|
||||||
std::string toString(bool) const override { return "bytes" + dev::toString(m_bytes); }
|
std::string toString(bool) const override { return "bytes" + dev::toString(m_bytes); }
|
||||||
MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
|
MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
|
||||||
TypePointer encodingType() const override { return shared_from_this(); }
|
TypePointer encodingType() const override { return this; }
|
||||||
TypeResult interfaceType(bool) const override { return shared_from_this(); }
|
TypeResult interfaceType(bool) const override { return this; }
|
||||||
|
|
||||||
unsigned numBytes() const { return m_bytes; }
|
unsigned numBytes() const { return m_bytes; }
|
||||||
|
|
||||||
@ -611,7 +603,7 @@ public:
|
|||||||
Category category() const override { return Category::Bool; }
|
Category category() const override { return Category::Bool; }
|
||||||
std::string richIdentifier() const override { return "t_bool"; }
|
std::string richIdentifier() const override { return "t_bool"; }
|
||||||
TypeResult unaryOperatorResult(Token _operator) const override;
|
TypeResult unaryOperatorResult(Token _operator) const override;
|
||||||
TypeResult binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
|
TypeResult binaryOperatorResult(Token _operator, Type const* _other) const override;
|
||||||
|
|
||||||
unsigned calldataEncodedSize(bool _padded) const override{ return _padded ? 32 : 1; }
|
unsigned calldataEncodedSize(bool _padded) const override{ return _padded ? 32 : 1; }
|
||||||
unsigned storageBytes() const override { return 1; }
|
unsigned storageBytes() const override { return 1; }
|
||||||
@ -620,8 +612,8 @@ public:
|
|||||||
|
|
||||||
std::string toString(bool) const override { return "bool"; }
|
std::string toString(bool) const override { return "bool"; }
|
||||||
u256 literalValue(Literal const* _literal) const override;
|
u256 literalValue(Literal const* _literal) const override;
|
||||||
TypePointer encodingType() const override { return shared_from_this(); }
|
TypePointer encodingType() const override { return this; }
|
||||||
TypeResult interfaceType(bool) const override { return shared_from_this(); }
|
TypeResult interfaceType(bool) const override { return this; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -630,22 +622,24 @@ public:
|
|||||||
*/
|
*/
|
||||||
class ReferenceType: public Type
|
class ReferenceType: public Type
|
||||||
{
|
{
|
||||||
public:
|
protected:
|
||||||
explicit ReferenceType(DataLocation _location): m_location(_location) {}
|
explicit ReferenceType(DataLocation _location): m_location(_location) {}
|
||||||
|
|
||||||
|
public:
|
||||||
DataLocation location() const { return m_location; }
|
DataLocation location() const { return m_location; }
|
||||||
|
|
||||||
TypeResult unaryOperatorResult(Token _operator) const override;
|
TypeResult unaryOperatorResult(Token _operator) const override;
|
||||||
TypeResult binaryOperatorResult(Token, TypePointer const&) const override
|
TypeResult binaryOperatorResult(Token, Type const*) const override
|
||||||
{
|
{
|
||||||
return TypePointer();
|
return nullptr;
|
||||||
}
|
}
|
||||||
unsigned memoryHeadSize() const override { return 32; }
|
unsigned memoryHeadSize() const override { return 32; }
|
||||||
|
|
||||||
/// @returns a copy of this type with location (recursively) changed to @a _location,
|
/// @returns a copy of this type with location (recursively) changed to @a _location,
|
||||||
/// whereas isPointer is only shallowly changed - the deep copy is always a bound reference.
|
/// whereas isPointer is only shallowly changed - the deep copy is always a bound reference.
|
||||||
virtual TypePointer copyForLocation(DataLocation _location, bool _isPointer) const = 0;
|
virtual std::unique_ptr<ReferenceType> copyForLocation(DataLocation _location, bool _isPointer) const = 0;
|
||||||
|
|
||||||
TypePointer mobileType() const override { return copyForLocation(m_location, true); }
|
TypePointer mobileType() const override { return withLocation(m_location, true); }
|
||||||
bool dataStoredIn(DataLocation _location) const override { return m_location == _location; }
|
bool dataStoredIn(DataLocation _location) const override { return m_location == _location; }
|
||||||
bool hasSimpleZeroValueInMemory() const override { return false; }
|
bool hasSimpleZeroValueInMemory() const override { return false; }
|
||||||
|
|
||||||
@ -663,10 +657,12 @@ public:
|
|||||||
/// @returns a copy of @a _type having the same location as this (and is not a pointer type)
|
/// @returns a copy of @a _type having the same location as this (and is not a pointer type)
|
||||||
/// if _type is a reference type and an unmodified copy of _type otherwise.
|
/// if _type is a reference type and an unmodified copy of _type otherwise.
|
||||||
/// This function is mostly useful to modify inner types appropriately.
|
/// This function is mostly useful to modify inner types appropriately.
|
||||||
static TypePointer copyForLocationIfReference(DataLocation _location, TypePointer const& _type);
|
static Type const* copyForLocationIfReference(DataLocation _location, Type const* _type);
|
||||||
|
|
||||||
|
Type const* withLocation(DataLocation _location, bool _isPointer) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
TypePointer copyForLocationIfReference(TypePointer const& _type) const;
|
Type const* copyForLocationIfReference(Type const* _type) const;
|
||||||
/// @returns a human-readable description of the reference part of the type.
|
/// @returns a human-readable description of the reference part of the type.
|
||||||
std::string stringForReferencePart() const;
|
std::string stringForReferencePart() const;
|
||||||
/// @returns the suffix computed from the reference part to be used by identifier();
|
/// @returns the suffix computed from the reference part to be used by identifier();
|
||||||
@ -686,32 +682,26 @@ protected:
|
|||||||
class ArrayType: public ReferenceType
|
class ArrayType: public ReferenceType
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static ArrayType& bytesMemory() { static std::shared_ptr<ArrayType> addr(std::make_shared<ArrayType>(DataLocation::Memory)); return *addr; }
|
|
||||||
static ArrayType& stringMemory() { static std::shared_ptr<ArrayType> addr(std::make_shared<ArrayType>(DataLocation::Memory, true)); return *addr; }
|
|
||||||
|
|
||||||
Category category() const override { return Category::Array; }
|
|
||||||
|
|
||||||
/// Constructor for a byte array ("bytes") and string.
|
/// Constructor for a byte array ("bytes") and string.
|
||||||
explicit ArrayType(DataLocation _location, bool _isString = false):
|
explicit ArrayType(DataLocation _location, bool _isString = false);
|
||||||
ReferenceType(_location),
|
|
||||||
m_arrayKind(_isString ? ArrayKind::String : ArrayKind::Bytes),
|
|
||||||
m_baseType(std::make_shared<FixedBytesType>(1))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
/// Constructor for a dynamically sized array type ("type[]")
|
/// Constructor for a dynamically sized array type ("type[]")
|
||||||
ArrayType(DataLocation _location, TypePointer const& _baseType):
|
ArrayType(DataLocation _location, Type const* _baseType):
|
||||||
ReferenceType(_location),
|
ReferenceType(_location),
|
||||||
m_baseType(copyForLocationIfReference(_baseType))
|
m_baseType(copyForLocationIfReference(_baseType))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructor for a fixed-size array type ("type[20]")
|
/// Constructor for a fixed-size array type ("type[20]")
|
||||||
ArrayType(DataLocation _location, TypePointer const& _baseType, u256 const& _length):
|
ArrayType(DataLocation _location, Type const* _baseType, u256 const& _length):
|
||||||
ReferenceType(_location),
|
ReferenceType(_location),
|
||||||
m_baseType(copyForLocationIfReference(_baseType)),
|
m_baseType(copyForLocationIfReference(_baseType)),
|
||||||
m_hasDynamicLength(false),
|
m_hasDynamicLength(false),
|
||||||
m_length(_length)
|
m_length(_length)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
Category category() const override { return Category::Array; }
|
||||||
|
|
||||||
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
|
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||||
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||||
std::string richIdentifier() const override;
|
std::string richIdentifier() const override;
|
||||||
@ -737,11 +727,11 @@ public:
|
|||||||
bool isByteArray() const { return m_arrayKind != ArrayKind::Ordinary; }
|
bool isByteArray() const { return m_arrayKind != ArrayKind::Ordinary; }
|
||||||
/// @returns true if this is a string
|
/// @returns true if this is a string
|
||||||
bool isString() const { return m_arrayKind == ArrayKind::String; }
|
bool isString() const { return m_arrayKind == ArrayKind::String; }
|
||||||
TypePointer const& baseType() const { solAssert(!!m_baseType, ""); return m_baseType;}
|
Type const* baseType() const { solAssert(!!m_baseType, ""); return m_baseType; }
|
||||||
u256 const& length() const { return m_length; }
|
u256 const& length() const { return m_length; }
|
||||||
u256 memorySize() const;
|
u256 memorySize() const;
|
||||||
|
|
||||||
TypePointer copyForLocation(DataLocation _location, bool _isPointer) const override;
|
std::unique_ptr<ReferenceType> copyForLocation(DataLocation _location, bool _isPointer) const override;
|
||||||
|
|
||||||
/// The offset to advance in calldata to move from one array element to the next.
|
/// The offset to advance in calldata to move from one array element to the next.
|
||||||
unsigned calldataStride() const { return isByteArray() ? 1 : m_baseType->calldataEncodedSize(); }
|
unsigned calldataStride() const { return isByteArray() ? 1 : m_baseType->calldataEncodedSize(); }
|
||||||
@ -750,6 +740,8 @@ public:
|
|||||||
/// The offset to advance in storage to move from one array element to the next.
|
/// The offset to advance in storage to move from one array element to the next.
|
||||||
unsigned storageStride() const { return isByteArray() ? 1 : m_baseType->storageBytes(); }
|
unsigned storageStride() const { return isByteArray() ? 1 : m_baseType->storageBytes(); }
|
||||||
|
|
||||||
|
void clearCache() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// String is interpreted as a subtype of Bytes.
|
/// String is interpreted as a subtype of Bytes.
|
||||||
enum class ArrayKind { Ordinary, Bytes, String };
|
enum class ArrayKind { Ordinary, Bytes, String };
|
||||||
@ -758,7 +750,7 @@ private:
|
|||||||
|
|
||||||
///< Byte arrays ("bytes") and strings have different semantics from ordinary arrays.
|
///< Byte arrays ("bytes") and strings have different semantics from ordinary arrays.
|
||||||
ArrayKind m_arrayKind = ArrayKind::Ordinary;
|
ArrayKind m_arrayKind = ArrayKind::Ordinary;
|
||||||
TypePointer m_baseType;
|
Type const* m_baseType;
|
||||||
bool m_hasDynamicLength = true;
|
bool m_hasDynamicLength = true;
|
||||||
u256 m_length;
|
u256 m_length;
|
||||||
mutable boost::optional<TypeResult> m_interfaceType;
|
mutable boost::optional<TypeResult> m_interfaceType;
|
||||||
@ -771,9 +763,10 @@ private:
|
|||||||
class ContractType: public Type
|
class ContractType: public Type
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Category category() const override { return Category::Contract; }
|
|
||||||
explicit ContractType(ContractDefinition const& _contract, bool _super = false):
|
explicit ContractType(ContractDefinition const& _contract, bool _super = false):
|
||||||
m_contract(_contract), m_super(_super) {}
|
m_contract(_contract), m_super(_super) {}
|
||||||
|
|
||||||
|
Category category() const override { return Category::Contract; }
|
||||||
/// Contracts can be implicitly converted only to base contracts.
|
/// Contracts can be implicitly converted only to base contracts.
|
||||||
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
|
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||||
/// Contracts can only be explicitly converted to address types and base contracts.
|
/// Contracts can only be explicitly converted to address types and base contracts.
|
||||||
@ -795,17 +788,14 @@ public:
|
|||||||
std::string canonicalName() const override;
|
std::string canonicalName() const override;
|
||||||
|
|
||||||
MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
|
MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
|
||||||
TypePointer encodingType() const override
|
|
||||||
{
|
Type const* encodingType() const override;
|
||||||
if (isSuper())
|
|
||||||
return TypePointer{};
|
|
||||||
return std::make_shared<AddressType>(isPayable() ? StateMutability::Payable : StateMutability::NonPayable);
|
|
||||||
}
|
|
||||||
TypeResult interfaceType(bool _inLibrary) const override
|
TypeResult interfaceType(bool _inLibrary) const override
|
||||||
{
|
{
|
||||||
if (isSuper())
|
if (isSuper())
|
||||||
return TypePointer{};
|
return nullptr;
|
||||||
return _inLibrary ? shared_from_this() : encodingType();
|
return _inLibrary ? this : encodingType();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See documentation of m_super
|
/// See documentation of m_super
|
||||||
@ -817,7 +807,7 @@ public:
|
|||||||
ContractDefinition const& contractDefinition() const { return m_contract; }
|
ContractDefinition const& contractDefinition() const { return m_contract; }
|
||||||
|
|
||||||
/// Returns the function type of the constructor modified to return an object of the contract's type.
|
/// Returns the function type of the constructor modified to return an object of the contract's type.
|
||||||
FunctionTypePointer const& newExpressionType() const;
|
FunctionType const* newExpressionType() const;
|
||||||
|
|
||||||
/// @returns a list of all state variables (including inherited) of the contract and their
|
/// @returns a list of all state variables (including inherited) of the contract and their
|
||||||
/// offsets in storage.
|
/// offsets in storage.
|
||||||
@ -828,7 +818,7 @@ private:
|
|||||||
/// If true, this is a special "super" type of m_contract containing only members that m_contract inherited
|
/// If true, this is a special "super" type of m_contract containing only members that m_contract inherited
|
||||||
bool m_super = false;
|
bool m_super = false;
|
||||||
/// Type of the constructor, @see constructorType. Lazily initialized.
|
/// Type of the constructor, @see constructorType. Lazily initialized.
|
||||||
mutable FunctionTypePointer m_constructorType;
|
mutable FunctionType const* m_constructorType = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -837,9 +827,10 @@ private:
|
|||||||
class StructType: public ReferenceType
|
class StructType: public ReferenceType
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Category category() const override { return Category::Struct; }
|
|
||||||
explicit StructType(StructDefinition const& _struct, DataLocation _location = DataLocation::Storage):
|
explicit StructType(StructDefinition const& _struct, DataLocation _location = DataLocation::Storage):
|
||||||
ReferenceType(_location), m_struct(_struct) {}
|
ReferenceType(_location), m_struct(_struct) {}
|
||||||
|
|
||||||
|
Category category() const override { return Category::Struct; }
|
||||||
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
|
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||||
std::string richIdentifier() const override;
|
std::string richIdentifier() const override;
|
||||||
bool operator==(Type const& _other) const override;
|
bool operator==(Type const& _other) const override;
|
||||||
@ -851,10 +842,8 @@ public:
|
|||||||
std::string toString(bool _short) const override;
|
std::string toString(bool _short) const override;
|
||||||
|
|
||||||
MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
|
MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
|
||||||
TypePointer encodingType() const override
|
|
||||||
{
|
Type const* encodingType() const override;
|
||||||
return location() == DataLocation::Storage ? std::make_shared<IntegerType>(256) : shared_from_this();
|
|
||||||
}
|
|
||||||
TypeResult interfaceType(bool _inLibrary) const override;
|
TypeResult interfaceType(bool _inLibrary) const override;
|
||||||
|
|
||||||
bool recursive() const
|
bool recursive() const
|
||||||
@ -867,14 +856,14 @@ public:
|
|||||||
return m_recursive.get();
|
return m_recursive.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
TypePointer copyForLocation(DataLocation _location, bool _isPointer) const override;
|
std::unique_ptr<ReferenceType> copyForLocation(DataLocation _location, bool _isPointer) const override;
|
||||||
|
|
||||||
std::string canonicalName() const override;
|
std::string canonicalName() const override;
|
||||||
std::string signatureInExternalFunction(bool _structsByName) const override;
|
std::string signatureInExternalFunction(bool _structsByName) const override;
|
||||||
|
|
||||||
/// @returns a function that performs the type conversion between a list of struct members
|
/// @returns a function that performs the type conversion between a list of struct members
|
||||||
/// and a memory struct of this type.
|
/// and a memory struct of this type.
|
||||||
FunctionTypePointer constructorType() const;
|
FunctionType const* constructorType() const;
|
||||||
|
|
||||||
std::pair<u256, unsigned> const& storageOffsetsOfMember(std::string const& _name) const;
|
std::pair<u256, unsigned> const& storageOffsetsOfMember(std::string const& _name) const;
|
||||||
u256 memoryOffsetOfMember(std::string const& _name) const;
|
u256 memoryOffsetOfMember(std::string const& _name) const;
|
||||||
@ -886,6 +875,9 @@ public:
|
|||||||
TypePointers memoryMemberTypes() const;
|
TypePointers memoryMemberTypes() const;
|
||||||
/// @returns the set of all members that are removed in the memory version (typically mappings).
|
/// @returns the set of all members that are removed in the memory version (typically mappings).
|
||||||
std::set<std::string> membersMissingInMemory() const;
|
std::set<std::string> membersMissingInMemory() const;
|
||||||
|
|
||||||
|
void clearCache() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
StructDefinition const& m_struct;
|
StructDefinition const& m_struct;
|
||||||
// Caches for interfaceType(bool)
|
// Caches for interfaceType(bool)
|
||||||
@ -900,8 +892,9 @@ private:
|
|||||||
class EnumType: public Type
|
class EnumType: public Type
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Category category() const override { return Category::Enum; }
|
|
||||||
explicit EnumType(EnumDefinition const& _enum): m_enum(_enum) {}
|
explicit EnumType(EnumDefinition const& _enum): m_enum(_enum) {}
|
||||||
|
|
||||||
|
Category category() const override { return Category::Enum; }
|
||||||
TypeResult unaryOperatorResult(Token _operator) const override;
|
TypeResult unaryOperatorResult(Token _operator) const override;
|
||||||
std::string richIdentifier() const override;
|
std::string richIdentifier() const override;
|
||||||
bool operator==(Type const& _other) const override;
|
bool operator==(Type const& _other) const override;
|
||||||
@ -917,13 +910,10 @@ public:
|
|||||||
bool isValueType() const override { return true; }
|
bool isValueType() const override { return true; }
|
||||||
|
|
||||||
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||||
TypePointer encodingType() const override
|
TypePointer encodingType() const override;
|
||||||
{
|
|
||||||
return std::make_shared<IntegerType>(8 * int(storageBytes()));
|
|
||||||
}
|
|
||||||
TypeResult interfaceType(bool _inLibrary) const override
|
TypeResult interfaceType(bool _inLibrary) const override
|
||||||
{
|
{
|
||||||
return _inLibrary ? shared_from_this() : encodingType();
|
return _inLibrary ? this : encodingType();
|
||||||
}
|
}
|
||||||
|
|
||||||
EnumDefinition const& enumDefinition() const { return m_enum; }
|
EnumDefinition const& enumDefinition() const { return m_enum; }
|
||||||
@ -942,12 +932,14 @@ private:
|
|||||||
class TupleType: public Type
|
class TupleType: public Type
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
explicit TupleType(std::vector<TypePointer> _types = {}): m_components(std::move(_types)) {}
|
||||||
|
|
||||||
Category category() const override { return Category::Tuple; }
|
Category category() const override { return Category::Tuple; }
|
||||||
explicit TupleType(std::vector<TypePointer> const& _types = std::vector<TypePointer>()): m_components(_types) {}
|
|
||||||
BoolResult isImplicitlyConvertibleTo(Type const& _other) const override;
|
BoolResult isImplicitlyConvertibleTo(Type const& _other) const override;
|
||||||
std::string richIdentifier() const override;
|
std::string richIdentifier() const override;
|
||||||
bool operator==(Type const& _other) const override;
|
bool operator==(Type const& _other) const override;
|
||||||
TypeResult binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
|
TypeResult binaryOperatorResult(Token, Type const*) const override { return nullptr; }
|
||||||
std::string toString(bool) const override;
|
std::string toString(bool) const override;
|
||||||
bool canBeStored() const override { return false; }
|
bool canBeStored() const override { return false; }
|
||||||
u256 storageSize() const override;
|
u256 storageSize() const override;
|
||||||
@ -956,7 +948,7 @@ public:
|
|||||||
bool hasSimpleZeroValueInMemory() const override { return false; }
|
bool hasSimpleZeroValueInMemory() const override { return false; }
|
||||||
TypePointer mobileType() const override;
|
TypePointer mobileType() const override;
|
||||||
/// Converts components to their temporary types and performs some wildcard matching.
|
/// Converts components to their temporary types and performs some wildcard matching.
|
||||||
TypePointer closestTemporaryType(TypePointer const& _targetType) const override;
|
TypePointer closestTemporaryType(Type const* _targetType) const override;
|
||||||
|
|
||||||
std::vector<TypePointer> const& components() const { return m_components; }
|
std::vector<TypePointer> const& components() const { return m_components; }
|
||||||
|
|
||||||
@ -1017,8 +1009,6 @@ public:
|
|||||||
MetaType ///< type(...)
|
MetaType ///< type(...)
|
||||||
};
|
};
|
||||||
|
|
||||||
Category category() const override { return Category::Function; }
|
|
||||||
|
|
||||||
/// Creates the type of a function.
|
/// Creates the type of a function.
|
||||||
explicit FunctionType(FunctionDefinition const& _function, bool _isInternal = true);
|
explicit FunctionType(FunctionDefinition const& _function, bool _isInternal = true);
|
||||||
/// Creates the accessor function type of a state variable.
|
/// Creates the accessor function type of a state variable.
|
||||||
@ -1046,9 +1036,6 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @returns the type of the "new Contract" function, i.e. basically the constructor.
|
|
||||||
static FunctionTypePointer newExpressionType(ContractDefinition const& _contract);
|
|
||||||
|
|
||||||
/// Detailed constructor, use with care.
|
/// Detailed constructor, use with care.
|
||||||
FunctionType(
|
FunctionType(
|
||||||
TypePointers const& _parameterTypes,
|
TypePointers const& _parameterTypes,
|
||||||
@ -1089,6 +1076,11 @@ public:
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Category category() const override { return Category::Function; }
|
||||||
|
|
||||||
|
/// @returns the type of the "new Contract" function, i.e. basically the constructor.
|
||||||
|
static FunctionTypePointer newExpressionType(ContractDefinition const& _contract);
|
||||||
|
|
||||||
TypePointers parameterTypes() const;
|
TypePointers parameterTypes() const;
|
||||||
std::vector<std::string> parameterNames() const;
|
std::vector<std::string> parameterNames() const;
|
||||||
TypePointers const& returnParameterTypes() const { return m_returnParameterTypes; }
|
TypePointers const& returnParameterTypes() const { return m_returnParameterTypes; }
|
||||||
@ -1097,14 +1089,14 @@ public:
|
|||||||
TypePointers returnParameterTypesWithoutDynamicTypes() const;
|
TypePointers returnParameterTypesWithoutDynamicTypes() const;
|
||||||
std::vector<std::string> const& returnParameterNames() const { return m_returnParameterNames; }
|
std::vector<std::string> const& returnParameterNames() const { return m_returnParameterNames; }
|
||||||
/// @returns the "self" parameter type for a bound function
|
/// @returns the "self" parameter type for a bound function
|
||||||
TypePointer const& selfType() const;
|
Type const* selfType() const;
|
||||||
|
|
||||||
std::string richIdentifier() const override;
|
std::string richIdentifier() const override;
|
||||||
bool operator==(Type const& _other) const override;
|
bool operator==(Type const& _other) const override;
|
||||||
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
|
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||||
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||||
TypeResult unaryOperatorResult(Token _operator) const override;
|
TypeResult unaryOperatorResult(Token _operator) const override;
|
||||||
TypeResult binaryOperatorResult(Token, TypePointer const&) const override;
|
TypeResult binaryOperatorResult(Token, Type const*) const override;
|
||||||
std::string canonicalName() const override;
|
std::string canonicalName() const override;
|
||||||
std::string toString(bool _short) const override;
|
std::string toString(bool _short) const override;
|
||||||
unsigned calldataEncodedSize(bool _padded) const override;
|
unsigned calldataEncodedSize(bool _padded) const override;
|
||||||
@ -1133,7 +1125,7 @@ public:
|
|||||||
/// expression the function is called on.
|
/// expression the function is called on.
|
||||||
bool canTakeArguments(
|
bool canTakeArguments(
|
||||||
FuncCallArguments const& _arguments,
|
FuncCallArguments const& _arguments,
|
||||||
TypePointer const& _selfType = TypePointer()
|
Type const* _selfType = nullptr
|
||||||
) const;
|
) const;
|
||||||
|
|
||||||
/// @returns true if the types of parameters are equal (does not check return parameter types)
|
/// @returns true if the types of parameters are equal (does not check return parameter types)
|
||||||
@ -1229,27 +1221,25 @@ private:
|
|||||||
class MappingType: public Type
|
class MappingType: public Type
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Category category() const override { return Category::Mapping; }
|
MappingType(Type const* _keyType, Type const* _valueType):
|
||||||
MappingType(TypePointer const& _keyType, TypePointer const& _valueType):
|
|
||||||
m_keyType(_keyType), m_valueType(_valueType) {}
|
m_keyType(_keyType), m_valueType(_valueType) {}
|
||||||
|
|
||||||
|
Category category() const override { return Category::Mapping; }
|
||||||
|
|
||||||
std::string richIdentifier() const override;
|
std::string richIdentifier() const override;
|
||||||
bool operator==(Type const& _other) const override;
|
bool operator==(Type const& _other) const override;
|
||||||
std::string toString(bool _short) const override;
|
std::string toString(bool _short) const override;
|
||||||
std::string canonicalName() const override;
|
std::string canonicalName() const override;
|
||||||
bool canLiveOutsideStorage() const override { return false; }
|
bool canLiveOutsideStorage() const override { return false; }
|
||||||
TypeResult binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
|
TypeResult binaryOperatorResult(Token, Type const*) const override { return nullptr; }
|
||||||
TypePointer encodingType() const override
|
Type const* encodingType() const override;
|
||||||
{
|
|
||||||
return std::make_shared<IntegerType>(256);
|
|
||||||
}
|
|
||||||
TypeResult interfaceType(bool _inLibrary) const override;
|
TypeResult interfaceType(bool _inLibrary) const override;
|
||||||
bool dataStoredIn(DataLocation _location) const override { return _location == DataLocation::Storage; }
|
bool dataStoredIn(DataLocation _location) const override { return _location == DataLocation::Storage; }
|
||||||
/// Cannot be stored in memory, but just in case.
|
/// Cannot be stored in memory, but just in case.
|
||||||
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
|
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
|
||||||
|
|
||||||
TypePointer const& keyType() const { return m_keyType; }
|
Type const* keyType() const { return m_keyType; }
|
||||||
TypePointer const& valueType() const { return m_valueType; }
|
Type const* valueType() const { return m_valueType; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TypePointer m_keyType;
|
TypePointer m_keyType;
|
||||||
@ -1264,11 +1254,12 @@ private:
|
|||||||
class TypeType: public Type
|
class TypeType: public Type
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Category category() const override { return Category::TypeType; }
|
explicit TypeType(Type const* _actualType): m_actualType(_actualType) {}
|
||||||
explicit TypeType(TypePointer const& _actualType): m_actualType(_actualType) {}
|
|
||||||
TypePointer const& actualType() const { return m_actualType; }
|
|
||||||
|
|
||||||
TypeResult binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
|
Category category() const override { return Category::TypeType; }
|
||||||
|
Type const* actualType() const { return m_actualType; }
|
||||||
|
|
||||||
|
TypeResult binaryOperatorResult(Token, Type const*) const override { return nullptr; }
|
||||||
std::string richIdentifier() const override;
|
std::string richIdentifier() const override;
|
||||||
bool operator==(Type const& _other) const override;
|
bool operator==(Type const& _other) const override;
|
||||||
bool canBeStored() const override { return false; }
|
bool canBeStored() const override { return false; }
|
||||||
@ -1290,10 +1281,11 @@ private:
|
|||||||
class ModifierType: public Type
|
class ModifierType: public Type
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Category category() const override { return Category::Modifier; }
|
|
||||||
explicit ModifierType(ModifierDefinition const& _modifier);
|
explicit ModifierType(ModifierDefinition const& _modifier);
|
||||||
|
|
||||||
TypeResult binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
|
Category category() const override { return Category::Modifier; }
|
||||||
|
|
||||||
|
TypeResult binaryOperatorResult(Token, Type const*) const override { return nullptr; }
|
||||||
bool canBeStored() const override { return false; }
|
bool canBeStored() const override { return false; }
|
||||||
u256 storageSize() const override;
|
u256 storageSize() const override;
|
||||||
bool canLiveOutsideStorage() const override { return false; }
|
bool canLiveOutsideStorage() const override { return false; }
|
||||||
@ -1315,11 +1307,11 @@ private:
|
|||||||
class ModuleType: public Type
|
class ModuleType: public Type
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Category category() const override { return Category::Module; }
|
|
||||||
|
|
||||||
explicit ModuleType(SourceUnit const& _source): m_sourceUnit(_source) {}
|
explicit ModuleType(SourceUnit const& _source): m_sourceUnit(_source) {}
|
||||||
|
|
||||||
TypeResult binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
|
Category category() const override { return Category::Module; }
|
||||||
|
|
||||||
|
TypeResult binaryOperatorResult(Token, Type const*) const override { return nullptr; }
|
||||||
std::string richIdentifier() const override;
|
std::string richIdentifier() const override;
|
||||||
bool operator==(Type const& _other) const override;
|
bool operator==(Type const& _other) const override;
|
||||||
bool canBeStored() const override { return false; }
|
bool canBeStored() const override { return false; }
|
||||||
@ -1347,15 +1339,19 @@ public:
|
|||||||
ABI, ///< "abi"
|
ABI, ///< "abi"
|
||||||
MetaType ///< "type(...)"
|
MetaType ///< "type(...)"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit MagicType(Kind _kind): m_kind(_kind) {}
|
||||||
|
explicit MagicType(Type const* _metaTypeArg): m_kind{Kind::MetaType}, m_typeArgument{_metaTypeArg} {}
|
||||||
|
|
||||||
Category category() const override { return Category::Magic; }
|
Category category() const override { return Category::Magic; }
|
||||||
|
|
||||||
explicit MagicType(Kind _kind): m_kind(_kind) {}
|
|
||||||
/// Factory function for meta type
|
/// Factory function for meta type
|
||||||
static std::shared_ptr<MagicType> metaType(TypePointer _type);
|
static MagicType const* metaType(TypePointer _type);
|
||||||
|
|
||||||
TypeResult binaryOperatorResult(Token, TypePointer const&) const override
|
TypeResult binaryOperatorResult(Token, Type const*) const override
|
||||||
{
|
{
|
||||||
return TypePointer();
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string richIdentifier() const override;
|
std::string richIdentifier() const override;
|
||||||
@ -1376,7 +1372,6 @@ private:
|
|||||||
Kind m_kind;
|
Kind m_kind;
|
||||||
/// Contract type used for contract metadata magic.
|
/// Contract type used for contract metadata magic.
|
||||||
TypePointer m_typeArgument;
|
TypePointer m_typeArgument;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1391,7 +1386,7 @@ public:
|
|||||||
std::string richIdentifier() const override { return "t_inaccessible"; }
|
std::string richIdentifier() const override { return "t_inaccessible"; }
|
||||||
BoolResult isImplicitlyConvertibleTo(Type const&) const override { return false; }
|
BoolResult isImplicitlyConvertibleTo(Type const&) const override { return false; }
|
||||||
BoolResult isExplicitlyConvertibleTo(Type const&) const override { return false; }
|
BoolResult isExplicitlyConvertibleTo(Type const&) const override { return false; }
|
||||||
TypeResult binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
|
TypeResult binaryOperatorResult(Token, Type const*) const override { return nullptr; }
|
||||||
unsigned calldataEncodedSize(bool _padded) const override { (void)_padded; return 32; }
|
unsigned calldataEncodedSize(bool _padded) const override { (void)_padded; return 32; }
|
||||||
bool canBeStored() const override { return false; }
|
bool canBeStored() const override { return false; }
|
||||||
bool canLiveOutsideStorage() const override { return false; }
|
bool canLiveOutsideStorage() const override { return false; }
|
||||||
@ -1399,7 +1394,7 @@ public:
|
|||||||
unsigned sizeOnStack() const override { return 1; }
|
unsigned sizeOnStack() const override { return 1; }
|
||||||
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
|
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
|
||||||
std::string toString(bool) const override { return "inaccessible dynamic type"; }
|
std::string toString(bool) const override { return "inaccessible dynamic type"; }
|
||||||
TypePointer decodingType() const override { return std::make_shared<IntegerType>(256); }
|
TypePointer decodingType() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -311,7 +311,7 @@ string ABIFunctions::abiEncodingFunction(
|
|||||||
case DataLocation::CallData:
|
case DataLocation::CallData:
|
||||||
if (
|
if (
|
||||||
fromArray.isByteArray() ||
|
fromArray.isByteArray() ||
|
||||||
*fromArray.baseType() == IntegerType::uint256() ||
|
*fromArray.baseType() == *TypeProvider::uint256() ||
|
||||||
*fromArray.baseType() == FixedBytesType(32)
|
*fromArray.baseType() == FixedBytesType(32)
|
||||||
)
|
)
|
||||||
return abiEncodingFunctionCalldataArrayWithoutCleanup(fromArray, *toArray, _options);
|
return abiEncodingFunctionCalldataArrayWithoutCleanup(fromArray, *toArray, _options);
|
||||||
@ -369,7 +369,7 @@ string ABIFunctions::abiEncodingFunction(
|
|||||||
// possible for library calls where we just forward the storage reference
|
// possible for library calls where we just forward the storage reference
|
||||||
solAssert(_options.encodeAsLibraryTypes, "");
|
solAssert(_options.encodeAsLibraryTypes, "");
|
||||||
solAssert(_options.padded && !_options.dynamicInplace, "Non-padded / inplace encoding for library call requested.");
|
solAssert(_options.padded && !_options.dynamicInplace, "Non-padded / inplace encoding for library call requested.");
|
||||||
solAssert(to == IntegerType::uint256(), "");
|
solAssert(to == *TypeProvider::uint256(), "");
|
||||||
templ("cleanupConvert", "value");
|
templ("cleanupConvert", "value");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -445,7 +445,7 @@ string ABIFunctions::abiEncodingFunctionCalldataArrayWithoutCleanup(
|
|||||||
solAssert(fromArrayType.location() == DataLocation::CallData, "");
|
solAssert(fromArrayType.location() == DataLocation::CallData, "");
|
||||||
solAssert(
|
solAssert(
|
||||||
fromArrayType.isByteArray() ||
|
fromArrayType.isByteArray() ||
|
||||||
*fromArrayType.baseType() == IntegerType::uint256() ||
|
*fromArrayType.baseType() == *TypeProvider::uint256() ||
|
||||||
*fromArrayType.baseType() == FixedBytesType(32),
|
*fromArrayType.baseType() == FixedBytesType(32),
|
||||||
"");
|
"");
|
||||||
solAssert(fromArrayType.calldataStride() == toArrayType.memoryStride(), "");
|
solAssert(fromArrayType.calldataStride() == toArrayType.memoryStride(), "");
|
||||||
@ -1077,7 +1077,7 @@ string ABIFunctions::abiDecodingFunction(Type const& _type, bool _fromMemory, bo
|
|||||||
TypePointer decodingType = _type.decodingType();
|
TypePointer decodingType = _type.decodingType();
|
||||||
solAssert(decodingType, "");
|
solAssert(decodingType, "");
|
||||||
|
|
||||||
if (auto arrayType = dynamic_cast<ArrayType const*>(decodingType.get()))
|
if (auto arrayType = dynamic_cast<ArrayType const*>(decodingType))
|
||||||
{
|
{
|
||||||
if (arrayType->dataStoredIn(DataLocation::CallData))
|
if (arrayType->dataStoredIn(DataLocation::CallData))
|
||||||
{
|
{
|
||||||
@ -1089,7 +1089,7 @@ string ABIFunctions::abiDecodingFunction(Type const& _type, bool _fromMemory, bo
|
|||||||
else
|
else
|
||||||
return abiDecodingFunctionArray(*arrayType, _fromMemory);
|
return abiDecodingFunctionArray(*arrayType, _fromMemory);
|
||||||
}
|
}
|
||||||
else if (auto const* structType = dynamic_cast<StructType const*>(decodingType.get()))
|
else if (auto const* structType = dynamic_cast<StructType const*>(decodingType))
|
||||||
{
|
{
|
||||||
if (structType->dataStoredIn(DataLocation::CallData))
|
if (structType->dataStoredIn(DataLocation::CallData))
|
||||||
{
|
{
|
||||||
@ -1099,7 +1099,7 @@ string ABIFunctions::abiDecodingFunction(Type const& _type, bool _fromMemory, bo
|
|||||||
else
|
else
|
||||||
return abiDecodingFunctionStruct(*structType, _fromMemory);
|
return abiDecodingFunctionStruct(*structType, _fromMemory);
|
||||||
}
|
}
|
||||||
else if (auto const* functionType = dynamic_cast<FunctionType const*>(decodingType.get()))
|
else if (auto const* functionType = dynamic_cast<FunctionType const*>(decodingType))
|
||||||
return abiDecodingFunctionFunctionType(*functionType, _fromMemory, _forUseOnStack);
|
return abiDecodingFunctionFunctionType(*functionType, _fromMemory, _forUseOnStack);
|
||||||
else
|
else
|
||||||
return abiDecodingFunctionValueType(_type, _fromMemory);
|
return abiDecodingFunctionValueType(_type, _fromMemory);
|
||||||
|
@ -41,7 +41,7 @@ class Type;
|
|||||||
class ArrayType;
|
class ArrayType;
|
||||||
class StructType;
|
class StructType;
|
||||||
class FunctionType;
|
class FunctionType;
|
||||||
using TypePointer = std::shared_ptr<Type const>;
|
using TypePointer = Type const*;
|
||||||
using TypePointers = std::vector<TypePointer>;
|
using TypePointers = std::vector<TypePointer>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include <libsolidity/codegen/ArrayUtils.h>
|
#include <libsolidity/codegen/ArrayUtils.h>
|
||||||
|
|
||||||
#include <libsolidity/ast/Types.h>
|
#include <libsolidity/ast/Types.h>
|
||||||
|
#include <libsolidity/ast/TypeProvider.h>
|
||||||
#include <libsolidity/codegen/CompilerContext.h>
|
#include <libsolidity/codegen/CompilerContext.h>
|
||||||
#include <libsolidity/codegen/CompilerUtils.h>
|
#include <libsolidity/codegen/CompilerUtils.h>
|
||||||
#include <libsolidity/codegen/LValue.h>
|
#include <libsolidity/codegen/LValue.h>
|
||||||
@ -44,7 +45,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
|||||||
// stack layout: [source_ref] [source length] target_ref (top)
|
// stack layout: [source_ref] [source length] target_ref (top)
|
||||||
solAssert(_targetType.location() == DataLocation::Storage, "");
|
solAssert(_targetType.location() == DataLocation::Storage, "");
|
||||||
|
|
||||||
TypePointer uint256 = make_shared<IntegerType>(256);
|
TypePointer uint256 = TypeProvider::uint256();
|
||||||
TypePointer targetBaseType = _targetType.isByteArray() ? uint256 : _targetType.baseType();
|
TypePointer targetBaseType = _targetType.isByteArray() ? uint256 : _targetType.baseType();
|
||||||
TypePointer sourceBaseType = _sourceType.isByteArray() ? uint256 : _sourceType.baseType();
|
TypePointer sourceBaseType = _sourceType.isByteArray() ? uint256 : _sourceType.baseType();
|
||||||
|
|
||||||
@ -74,8 +75,8 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
|||||||
}
|
}
|
||||||
|
|
||||||
// stack: target_ref source_ref source_length
|
// stack: target_ref source_ref source_length
|
||||||
TypePointer targetType = _targetType.shared_from_this();
|
TypePointer targetType = &_targetType;
|
||||||
TypePointer sourceType = _sourceType.shared_from_this();
|
TypePointer sourceType = &_sourceType;
|
||||||
m_context.callLowLevelFunction(
|
m_context.callLowLevelFunction(
|
||||||
"$copyArrayToStorage_" + sourceType->identifier() + "_to_" + targetType->identifier(),
|
"$copyArrayToStorage_" + sourceType->identifier() + "_to_" + targetType->identifier(),
|
||||||
3,
|
3,
|
||||||
@ -336,7 +337,7 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
|
|||||||
m_context << Instruction::DUP3 << Instruction::DUP5;
|
m_context << Instruction::DUP3 << Instruction::DUP5;
|
||||||
accessIndex(_sourceType, false);
|
accessIndex(_sourceType, false);
|
||||||
MemoryItem(m_context, *_sourceType.baseType(), true).retrieveValue(SourceLocation(), true);
|
MemoryItem(m_context, *_sourceType.baseType(), true).retrieveValue(SourceLocation(), true);
|
||||||
if (auto baseArray = dynamic_cast<ArrayType const*>(_sourceType.baseType().get()))
|
if (auto baseArray = dynamic_cast<ArrayType const*>(_sourceType.baseType()))
|
||||||
copyArrayToMemory(*baseArray, _padToWordBoundaries);
|
copyArrayToMemory(*baseArray, _padToWordBoundaries);
|
||||||
else
|
else
|
||||||
utils.storeInMemoryDynamic(*_sourceType.baseType());
|
utils.storeInMemoryDynamic(*_sourceType.baseType());
|
||||||
@ -493,7 +494,7 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
|
|||||||
else
|
else
|
||||||
m_context << Instruction::DUP2 << u256(0);
|
m_context << Instruction::DUP2 << u256(0);
|
||||||
StorageItem(m_context, *_sourceType.baseType()).retrieveValue(SourceLocation(), true);
|
StorageItem(m_context, *_sourceType.baseType()).retrieveValue(SourceLocation(), true);
|
||||||
if (auto baseArray = dynamic_cast<ArrayType const*>(_sourceType.baseType().get()))
|
if (auto baseArray = dynamic_cast<ArrayType const*>(_sourceType.baseType()))
|
||||||
copyArrayToMemory(*baseArray, _padToWordBoundaries);
|
copyArrayToMemory(*baseArray, _padToWordBoundaries);
|
||||||
else
|
else
|
||||||
utils.storeInMemoryDynamic(*_sourceType.baseType());
|
utils.storeInMemoryDynamic(*_sourceType.baseType());
|
||||||
@ -530,7 +531,7 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
|
|||||||
|
|
||||||
void ArrayUtils::clearArray(ArrayType const& _typeIn) const
|
void ArrayUtils::clearArray(ArrayType const& _typeIn) const
|
||||||
{
|
{
|
||||||
TypePointer type = _typeIn.shared_from_this();
|
TypePointer type = &_typeIn;
|
||||||
m_context.callLowLevelFunction(
|
m_context.callLowLevelFunction(
|
||||||
"$clearArray_" + _typeIn.identifier(),
|
"$clearArray_" + _typeIn.identifier(),
|
||||||
2,
|
2,
|
||||||
@ -584,7 +585,7 @@ void ArrayUtils::clearArray(ArrayType const& _typeIn) const
|
|||||||
ArrayUtils(_context).convertLengthToSize(_type);
|
ArrayUtils(_context).convertLengthToSize(_type);
|
||||||
_context << Instruction::ADD << Instruction::SWAP1;
|
_context << Instruction::ADD << Instruction::SWAP1;
|
||||||
if (_type.baseType()->storageBytes() < 32)
|
if (_type.baseType()->storageBytes() < 32)
|
||||||
ArrayUtils(_context).clearStorageLoop(make_shared<IntegerType>(256));
|
ArrayUtils(_context).clearStorageLoop(TypeProvider::uint256());
|
||||||
else
|
else
|
||||||
ArrayUtils(_context).clearStorageLoop(_type.baseType());
|
ArrayUtils(_context).clearStorageLoop(_type.baseType());
|
||||||
_context << Instruction::POP;
|
_context << Instruction::POP;
|
||||||
@ -625,7 +626,7 @@ void ArrayUtils::clearDynamicArray(ArrayType const& _type) const
|
|||||||
<< Instruction::SWAP1;
|
<< Instruction::SWAP1;
|
||||||
// stack: data_pos_end data_pos
|
// stack: data_pos_end data_pos
|
||||||
if (_type.storageStride() < 32)
|
if (_type.storageStride() < 32)
|
||||||
clearStorageLoop(make_shared<IntegerType>(256));
|
clearStorageLoop(TypeProvider::uint256());
|
||||||
else
|
else
|
||||||
clearStorageLoop(_type.baseType());
|
clearStorageLoop(_type.baseType());
|
||||||
// cleanup
|
// cleanup
|
||||||
@ -635,7 +636,7 @@ void ArrayUtils::clearDynamicArray(ArrayType const& _type) const
|
|||||||
|
|
||||||
void ArrayUtils::resizeDynamicArray(ArrayType const& _typeIn) const
|
void ArrayUtils::resizeDynamicArray(ArrayType const& _typeIn) const
|
||||||
{
|
{
|
||||||
TypePointer type = _typeIn.shared_from_this();
|
TypePointer type = &_typeIn;
|
||||||
m_context.callLowLevelFunction(
|
m_context.callLowLevelFunction(
|
||||||
"$resizeDynamicArray_" + _typeIn.identifier(),
|
"$resizeDynamicArray_" + _typeIn.identifier(),
|
||||||
2,
|
2,
|
||||||
@ -732,7 +733,7 @@ void ArrayUtils::resizeDynamicArray(ArrayType const& _typeIn) const
|
|||||||
ArrayUtils(_context).convertLengthToSize(_type);
|
ArrayUtils(_context).convertLengthToSize(_type);
|
||||||
_context << Instruction::DUP2 << Instruction::ADD << Instruction::SWAP1;
|
_context << Instruction::DUP2 << Instruction::ADD << Instruction::SWAP1;
|
||||||
// stack: ref new_length current_length first_word data_location_end data_location
|
// stack: ref new_length current_length first_word data_location_end data_location
|
||||||
ArrayUtils(_context).clearStorageLoop(make_shared<IntegerType>(256));
|
ArrayUtils(_context).clearStorageLoop(TypeProvider::uint256());
|
||||||
_context << Instruction::POP;
|
_context << Instruction::POP;
|
||||||
// stack: ref new_length current_length first_word
|
// stack: ref new_length current_length first_word
|
||||||
solAssert(_context.stackHeight() - stackHeightStart == 4 - 2, "3");
|
solAssert(_context.stackHeight() - stackHeightStart == 4 - 2, "3");
|
||||||
@ -771,7 +772,7 @@ void ArrayUtils::resizeDynamicArray(ArrayType const& _typeIn) const
|
|||||||
_context << Instruction::SWAP2 << Instruction::ADD;
|
_context << Instruction::SWAP2 << Instruction::ADD;
|
||||||
// stack: ref new_length delete_end delete_start
|
// stack: ref new_length delete_end delete_start
|
||||||
if (_type.storageStride() < 32)
|
if (_type.storageStride() < 32)
|
||||||
ArrayUtils(_context).clearStorageLoop(make_shared<IntegerType>(256));
|
ArrayUtils(_context).clearStorageLoop(TypeProvider::uint256());
|
||||||
else
|
else
|
||||||
ArrayUtils(_context).clearStorageLoop(_type.baseType());
|
ArrayUtils(_context).clearStorageLoop(_type.baseType());
|
||||||
|
|
||||||
@ -911,7 +912,7 @@ void ArrayUtils::popStorageArrayElement(ArrayType const& _type) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArrayUtils::clearStorageLoop(TypePointer const& _type) const
|
void ArrayUtils::clearStorageLoop(TypePointer _type) const
|
||||||
{
|
{
|
||||||
m_context.callLowLevelFunction(
|
m_context.callLowLevelFunction(
|
||||||
"$clearStorageLoop_" + _type->identifier(),
|
"$clearStorageLoop_" + _type->identifier(),
|
||||||
|
@ -32,7 +32,7 @@ namespace solidity
|
|||||||
class CompilerContext;
|
class CompilerContext;
|
||||||
class Type;
|
class Type;
|
||||||
class ArrayType;
|
class ArrayType;
|
||||||
using TypePointer = std::shared_ptr<Type const>;
|
using TypePointer = Type const*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class that provides code generation for handling arrays.
|
* Class that provides code generation for handling arrays.
|
||||||
@ -81,7 +81,7 @@ public:
|
|||||||
/// Appends a loop that clears a sequence of storage slots of the given type (excluding end).
|
/// Appends a loop that clears a sequence of storage slots of the given type (excluding end).
|
||||||
/// Stack pre: end_ref start_ref
|
/// Stack pre: end_ref start_ref
|
||||||
/// Stack post: end_ref
|
/// Stack post: end_ref
|
||||||
void clearStorageLoop(TypePointer const& _type) const;
|
void clearStorageLoop(TypePointer _type) const;
|
||||||
/// Converts length to size (number of storage slots or calldata/memory bytes).
|
/// Converts length to size (number of storage slots or calldata/memory bytes).
|
||||||
/// if @a _pad then add padding to multiples of 32 bytes for calldata/memory.
|
/// if @a _pad then add padding to multiples of 32 bytes for calldata/memory.
|
||||||
/// Stack pre: length
|
/// Stack pre: length
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include <libsolidity/codegen/CompilerUtils.h>
|
#include <libsolidity/codegen/CompilerUtils.h>
|
||||||
|
|
||||||
#include <libsolidity/ast/AST.h>
|
#include <libsolidity/ast/AST.h>
|
||||||
|
#include <libsolidity/ast/TypeProvider.h>
|
||||||
#include <libsolidity/codegen/ABIFunctions.h>
|
#include <libsolidity/codegen/ABIFunctions.h>
|
||||||
#include <libsolidity/codegen/ArrayUtils.h>
|
#include <libsolidity/codegen/ArrayUtils.h>
|
||||||
#include <libsolidity/codegen/LValue.h>
|
#include <libsolidity/codegen/LValue.h>
|
||||||
@ -83,13 +84,13 @@ void CompilerUtils::toSizeAfterFreeMemoryPointer()
|
|||||||
|
|
||||||
void CompilerUtils::revertWithStringData(Type const& _argumentType)
|
void CompilerUtils::revertWithStringData(Type const& _argumentType)
|
||||||
{
|
{
|
||||||
solAssert(_argumentType.isImplicitlyConvertibleTo(*Type::fromElementaryTypeName("string memory")), "");
|
solAssert(_argumentType.isImplicitlyConvertibleTo(*TypeProvider::fromElementaryTypeName("string memory")), "");
|
||||||
fetchFreeMemoryPointer();
|
fetchFreeMemoryPointer();
|
||||||
m_context << (u256(FixedHash<4>::Arith(FixedHash<4>(dev::keccak256("Error(string)")))) << (256 - 32));
|
m_context << (u256(FixedHash<4>::Arith(FixedHash<4>(dev::keccak256("Error(string)")))) << (256 - 32));
|
||||||
m_context << Instruction::DUP2 << Instruction::MSTORE;
|
m_context << Instruction::DUP2 << Instruction::MSTORE;
|
||||||
m_context << u256(4) << Instruction::ADD;
|
m_context << u256(4) << Instruction::ADD;
|
||||||
// Stack: <string data> <mem pos of encoding start>
|
// Stack: <string data> <mem pos of encoding start>
|
||||||
abiEncode({_argumentType.shared_from_this()}, {make_shared<ArrayType>(DataLocation::Memory, true)});
|
abiEncode({&_argumentType}, {TypeProvider::arrayType(DataLocation::Memory, true)});
|
||||||
toSizeAfterFreeMemoryPointer();
|
toSizeAfterFreeMemoryPointer();
|
||||||
m_context << Instruction::REVERT;
|
m_context << Instruction::REVERT;
|
||||||
}
|
}
|
||||||
@ -185,7 +186,7 @@ void CompilerUtils::loadFromMemoryDynamic(
|
|||||||
|
|
||||||
void CompilerUtils::storeInMemory(unsigned _offset)
|
void CompilerUtils::storeInMemory(unsigned _offset)
|
||||||
{
|
{
|
||||||
unsigned numBytes = prepareMemoryStore(IntegerType::uint256(), true);
|
unsigned numBytes = prepareMemoryStore(*TypeProvider::uint256(), true);
|
||||||
if (numBytes > 0)
|
if (numBytes > 0)
|
||||||
m_context << u256(_offset) << Instruction::MSTORE;
|
m_context << u256(_offset) << Instruction::MSTORE;
|
||||||
}
|
}
|
||||||
@ -199,7 +200,7 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound
|
|||||||
ref->location() == DataLocation::Memory,
|
ref->location() == DataLocation::Memory,
|
||||||
"Only in-memory reference type can be stored."
|
"Only in-memory reference type can be stored."
|
||||||
);
|
);
|
||||||
storeInMemoryDynamic(IntegerType::uint256(), _padToWordBoundaries);
|
storeInMemoryDynamic(*TypeProvider::uint256(), _padToWordBoundaries);
|
||||||
}
|
}
|
||||||
else if (auto str = dynamic_cast<StringLiteralType const*>(&_type))
|
else if (auto str = dynamic_cast<StringLiteralType const*>(&_type))
|
||||||
{
|
{
|
||||||
@ -311,11 +312,11 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// first load from calldata and potentially convert to memory if arrayType is memory
|
// first load from calldata and potentially convert to memory if arrayType is memory
|
||||||
TypePointer calldataType = arrayType.copyForLocation(DataLocation::CallData, false);
|
TypePointer calldataType = TypeProvider::withLocation(&arrayType, DataLocation::CallData, false);
|
||||||
if (calldataType->isDynamicallySized())
|
if (calldataType->isDynamicallySized())
|
||||||
{
|
{
|
||||||
// put on stack: data_pointer length
|
// put on stack: data_pointer length
|
||||||
loadFromMemoryDynamic(IntegerType::uint256(), !_fromMemory);
|
loadFromMemoryDynamic(*TypeProvider::uint256(), !_fromMemory);
|
||||||
m_context << Instruction::SWAP1;
|
m_context << Instruction::SWAP1;
|
||||||
// stack: input_end base_offset next_pointer data_offset
|
// stack: input_end base_offset next_pointer data_offset
|
||||||
m_context.appendInlineAssembly("{ if gt(data_offset, 0x100000000) { revert(0, 0) } }", {"data_offset"});
|
m_context.appendInlineAssembly("{ if gt(data_offset, 0x100000000) { revert(0, 0) } }", {"data_offset"});
|
||||||
@ -326,7 +327,7 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem
|
|||||||
{"input_end", "base_offset", "next_ptr", "array_head_ptr"}
|
{"input_end", "base_offset", "next_ptr", "array_head_ptr"}
|
||||||
);
|
);
|
||||||
// retrieve length
|
// retrieve length
|
||||||
loadFromMemoryDynamic(IntegerType::uint256(), !_fromMemory, true);
|
loadFromMemoryDynamic(*TypeProvider::uint256(), !_fromMemory, true);
|
||||||
// stack: input_end base_offset next_pointer array_length data_pointer
|
// stack: input_end base_offset next_pointer array_length data_pointer
|
||||||
m_context << Instruction::SWAP2;
|
m_context << Instruction::SWAP2;
|
||||||
// stack: input_end base_offset data_pointer array_length next_pointer
|
// stack: input_end base_offset data_pointer array_length next_pointer
|
||||||
@ -454,7 +455,7 @@ void CompilerUtils::encodeToMemory(
|
|||||||
type = _givenTypes[i]; // delay conversion
|
type = _givenTypes[i]; // delay conversion
|
||||||
else
|
else
|
||||||
convertType(*_givenTypes[i], *targetType, true);
|
convertType(*_givenTypes[i], *targetType, true);
|
||||||
if (auto arrayType = dynamic_cast<ArrayType const*>(type.get()))
|
if (auto arrayType = dynamic_cast<ArrayType const*>(type))
|
||||||
ArrayUtils(m_context).copyArrayToMemory(*arrayType, _padToWordBoundaries);
|
ArrayUtils(m_context).copyArrayToMemory(*arrayType, _padToWordBoundaries);
|
||||||
else
|
else
|
||||||
storeInMemoryDynamic(*type, _padToWordBoundaries);
|
storeInMemoryDynamic(*type, _padToWordBoundaries);
|
||||||
@ -482,7 +483,7 @@ void CompilerUtils::encodeToMemory(
|
|||||||
{
|
{
|
||||||
auto const& strType = dynamic_cast<StringLiteralType const&>(*_givenTypes[i]);
|
auto const& strType = dynamic_cast<StringLiteralType const&>(*_givenTypes[i]);
|
||||||
m_context << u256(strType.value().size());
|
m_context << u256(strType.value().size());
|
||||||
storeInMemoryDynamic(IntegerType::uint256(), true);
|
storeInMemoryDynamic(*TypeProvider::uint256(), true);
|
||||||
// stack: ... <end_of_mem'>
|
// stack: ... <end_of_mem'>
|
||||||
storeInMemoryDynamic(strType, _padToWordBoundaries);
|
storeInMemoryDynamic(strType, _padToWordBoundaries);
|
||||||
}
|
}
|
||||||
@ -497,7 +498,7 @@ void CompilerUtils::encodeToMemory(
|
|||||||
m_context << dupInstruction(1 + arrayType.sizeOnStack());
|
m_context << dupInstruction(1 + arrayType.sizeOnStack());
|
||||||
ArrayUtils(m_context).retrieveLength(arrayType, 1);
|
ArrayUtils(m_context).retrieveLength(arrayType, 1);
|
||||||
// stack: ... <end_of_mem> <value...> <end_of_mem'> <length>
|
// stack: ... <end_of_mem> <value...> <end_of_mem'> <length>
|
||||||
storeInMemoryDynamic(IntegerType::uint256(), true);
|
storeInMemoryDynamic(*TypeProvider::uint256(), true);
|
||||||
// stack: ... <end_of_mem> <value...> <end_of_mem''>
|
// stack: ... <end_of_mem> <value...> <end_of_mem''>
|
||||||
// copy the new memory pointer
|
// copy the new memory pointer
|
||||||
m_context << swapInstruction(arrayType.sizeOnStack() + 1) << Instruction::POP;
|
m_context << swapInstruction(arrayType.sizeOnStack() + 1) << Instruction::POP;
|
||||||
@ -868,7 +869,7 @@ void CompilerUtils::convertType(
|
|||||||
allocateMemory(storageSize);
|
allocateMemory(storageSize);
|
||||||
// stack: mempos
|
// stack: mempos
|
||||||
m_context << Instruction::DUP1 << u256(data.size());
|
m_context << Instruction::DUP1 << u256(data.size());
|
||||||
storeInMemoryDynamic(IntegerType::uint256());
|
storeInMemoryDynamic(*TypeProvider::uint256());
|
||||||
// stack: mempos datapos
|
// stack: mempos datapos
|
||||||
storeStringData(data);
|
storeStringData(data);
|
||||||
}
|
}
|
||||||
@ -917,7 +918,7 @@ void CompilerUtils::convertType(
|
|||||||
if (targetType.isDynamicallySized())
|
if (targetType.isDynamicallySized())
|
||||||
{
|
{
|
||||||
m_context << Instruction::DUP2;
|
m_context << Instruction::DUP2;
|
||||||
storeInMemoryDynamic(IntegerType::uint256());
|
storeInMemoryDynamic(*TypeProvider::uint256());
|
||||||
}
|
}
|
||||||
// stack: <mem start> <source ref> (variably sized) <length> <mem data pos>
|
// stack: <mem start> <source ref> (variably sized) <length> <mem data pos>
|
||||||
if (targetType.baseType()->isValueType())
|
if (targetType.baseType()->isValueType())
|
||||||
@ -988,10 +989,9 @@ void CompilerUtils::convertType(
|
|||||||
{
|
{
|
||||||
case DataLocation::Storage:
|
case DataLocation::Storage:
|
||||||
{
|
{
|
||||||
auto conversionImpl = [
|
auto conversionImpl =
|
||||||
typeOnStack = dynamic_pointer_cast<StructType const>(_typeOnStack.shared_from_this()),
|
[typeOnStack = &typeOnStack, targetType = &targetType](CompilerContext& _context)
|
||||||
targetType = dynamic_pointer_cast<StructType const>(targetType.shared_from_this())
|
{
|
||||||
](CompilerContext& _context) {
|
|
||||||
CompilerUtils utils(_context);
|
CompilerUtils utils(_context);
|
||||||
// stack: <source ref>
|
// stack: <source ref>
|
||||||
utils.allocateMemory(typeOnStack->memorySize());
|
utils.allocateMemory(typeOnStack->memorySize());
|
||||||
@ -1029,7 +1029,7 @@ void CompilerUtils::convertType(
|
|||||||
m_context << Instruction::DUP1;
|
m_context << Instruction::DUP1;
|
||||||
m_context << Instruction::CALLDATASIZE;
|
m_context << Instruction::CALLDATASIZE;
|
||||||
m_context << Instruction::SUB;
|
m_context << Instruction::SUB;
|
||||||
abiDecode({targetType.shared_from_this()}, false);
|
abiDecode({&targetType}, false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DataLocation::Memory:
|
case DataLocation::Memory:
|
||||||
@ -1162,7 +1162,7 @@ void CompilerUtils::pushZeroValue(Type const& _type)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TypePointer type = _type.shared_from_this();
|
TypePointer type = &_type;
|
||||||
m_context.callLowLevelFunction(
|
m_context.callLowLevelFunction(
|
||||||
"$pushZeroValue_" + referenceType->identifier(),
|
"$pushZeroValue_" + referenceType->identifier(),
|
||||||
0,
|
0,
|
||||||
@ -1172,13 +1172,13 @@ void CompilerUtils::pushZeroValue(Type const& _type)
|
|||||||
utils.allocateMemory(max(32u, type->calldataEncodedSize()));
|
utils.allocateMemory(max(32u, type->calldataEncodedSize()));
|
||||||
_context << Instruction::DUP1;
|
_context << Instruction::DUP1;
|
||||||
|
|
||||||
if (auto structType = dynamic_cast<StructType const*>(type.get()))
|
if (auto structType = dynamic_cast<StructType const*>(type))
|
||||||
for (auto const& member: structType->members(nullptr))
|
for (auto const& member: structType->members(nullptr))
|
||||||
{
|
{
|
||||||
utils.pushZeroValue(*member.type);
|
utils.pushZeroValue(*member.type);
|
||||||
utils.storeInMemoryDynamic(*member.type);
|
utils.storeInMemoryDynamic(*member.type);
|
||||||
}
|
}
|
||||||
else if (auto arrayType = dynamic_cast<ArrayType const*>(type.get()))
|
else if (auto arrayType = dynamic_cast<ArrayType const*>(type))
|
||||||
{
|
{
|
||||||
solAssert(!arrayType->isDynamicallySized(), "");
|
solAssert(!arrayType->isDynamicallySized(), "");
|
||||||
if (arrayType->length() > 0)
|
if (arrayType->length() > 0)
|
||||||
@ -1275,10 +1275,10 @@ void CompilerUtils::popAndJump(unsigned _toHeight, eth::AssemblyItem const& _jum
|
|||||||
m_context.adjustStackOffset(amount);
|
m_context.adjustStackOffset(amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned CompilerUtils::sizeOnStack(vector<shared_ptr<Type const>> const& _variableTypes)
|
unsigned CompilerUtils::sizeOnStack(vector<Type const*> const& _variableTypes)
|
||||||
{
|
{
|
||||||
unsigned size = 0;
|
unsigned size = 0;
|
||||||
for (shared_ptr<Type const> const& type: _variableTypes)
|
for (Type const* const& type: _variableTypes)
|
||||||
size += type->sizeOnStack();
|
size += type->sizeOnStack();
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
@ -1321,7 +1321,7 @@ void CompilerUtils::storeStringData(bytesConstRef _data)
|
|||||||
for (unsigned i = 0; i < _data.size(); i += 32)
|
for (unsigned i = 0; i < _data.size(); i += 32)
|
||||||
{
|
{
|
||||||
m_context << h256::Arith(h256(_data.cropped(i), h256::AlignLeft));
|
m_context << h256::Arith(h256(_data.cropped(i), h256::AlignLeft));
|
||||||
storeInMemoryDynamic(IntegerType::uint256());
|
storeInMemoryDynamic(*TypeProvider::uint256());
|
||||||
}
|
}
|
||||||
m_context << Instruction::POP;
|
m_context << Instruction::POP;
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <libsolidity/ast/ASTForward.h>
|
#include <libsolidity/ast/ASTForward.h>
|
||||||
|
#include <libsolidity/ast/TypeProvider.h>
|
||||||
|
#include <libsolidity/codegen/CompilerContext.h>
|
||||||
#include <libsolidity/codegen/CompilerContext.h>
|
#include <libsolidity/codegen/CompilerContext.h>
|
||||||
|
|
||||||
namespace dev {
|
namespace dev {
|
||||||
@ -80,7 +82,7 @@ public:
|
|||||||
/// @returns the number of bytes consumed in memory.
|
/// @returns the number of bytes consumed in memory.
|
||||||
unsigned loadFromMemory(
|
unsigned loadFromMemory(
|
||||||
unsigned _offset,
|
unsigned _offset,
|
||||||
Type const& _type = IntegerType::uint256(),
|
Type const& _type = *TypeProvider::uint256(),
|
||||||
bool _fromCalldata = false,
|
bool _fromCalldata = false,
|
||||||
bool _padToWords = false
|
bool _padToWords = false
|
||||||
);
|
);
|
||||||
@ -264,7 +266,7 @@ public:
|
|||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
static unsigned sizeOnStack(std::vector<T> const& _variables);
|
static unsigned sizeOnStack(std::vector<T> const& _variables);
|
||||||
static unsigned sizeOnStack(std::vector<std::shared_ptr<Type const>> const& _variableTypes);
|
static unsigned sizeOnStack(std::vector<Type const*> const& _variableTypes);
|
||||||
|
|
||||||
/// Helper function to shift top value on the stack to the left.
|
/// Helper function to shift top value on the stack to the left.
|
||||||
/// Stack pre: <value> <shift_by_bits>
|
/// Stack pre: <value> <shift_by_bits>
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <libsolidity/ast/AST.h>
|
#include <libsolidity/ast/AST.h>
|
||||||
|
#include <libsolidity/ast/TypeProvider.h>
|
||||||
#include <libsolidity/codegen/CompilerUtils.h>
|
#include <libsolidity/codegen/CompilerUtils.h>
|
||||||
#include <libsolidity/codegen/ContractCompiler.h>
|
#include <libsolidity/codegen/ContractCompiler.h>
|
||||||
#include <libsolidity/codegen/ExpressionCompiler.h>
|
#include <libsolidity/codegen/ExpressionCompiler.h>
|
||||||
@ -871,7 +872,7 @@ bool ContractCompiler::visit(Return const& _return)
|
|||||||
|
|
||||||
TypePointer expectedType;
|
TypePointer expectedType;
|
||||||
if (expression->annotation().type->category() == Type::Category::Tuple || types.size() != 1)
|
if (expression->annotation().type->category() == Type::Category::Tuple || types.size() != 1)
|
||||||
expectedType = make_shared<TupleType>(types);
|
expectedType = TypeProvider::tupleType(move(types));
|
||||||
else
|
else
|
||||||
expectedType = types.front();
|
expectedType = types.front();
|
||||||
compileExpression(*expression, expectedType);
|
compileExpression(*expression, expectedType);
|
||||||
@ -915,7 +916,7 @@ bool ContractCompiler::visit(VariableDeclarationStatement const& _variableDeclar
|
|||||||
CompilerUtils utils(m_context);
|
CompilerUtils utils(m_context);
|
||||||
compileExpression(*expression);
|
compileExpression(*expression);
|
||||||
TypePointers valueTypes;
|
TypePointers valueTypes;
|
||||||
if (auto tupleType = dynamic_cast<TupleType const*>(expression->annotation().type.get()))
|
if (auto tupleType = dynamic_cast<TupleType const*>(expression->annotation().type))
|
||||||
valueTypes = tupleType->components();
|
valueTypes = tupleType->components();
|
||||||
else
|
else
|
||||||
valueTypes = TypePointers{expression->annotation().type};
|
valueTypes = TypePointers{expression->annotation().type};
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include <libsolidity/codegen/ExpressionCompiler.h>
|
#include <libsolidity/codegen/ExpressionCompiler.h>
|
||||||
|
|
||||||
#include <libsolidity/ast/AST.h>
|
#include <libsolidity/ast/AST.h>
|
||||||
|
#include <libsolidity/ast/TypeProvider.h>
|
||||||
#include <libsolidity/codegen/CompilerContext.h>
|
#include <libsolidity/codegen/CompilerContext.h>
|
||||||
#include <libsolidity/codegen/CompilerUtils.h>
|
#include <libsolidity/codegen/CompilerUtils.h>
|
||||||
#include <libsolidity/codegen/LValue.h>
|
#include <libsolidity/codegen/LValue.h>
|
||||||
@ -102,7 +103,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
|
|||||||
|
|
||||||
for (size_t i = 0; i < paramTypes.size(); ++i)
|
for (size_t i = 0; i < paramTypes.size(); ++i)
|
||||||
{
|
{
|
||||||
if (auto mappingType = dynamic_cast<MappingType const*>(returnType.get()))
|
if (auto mappingType = dynamic_cast<MappingType const*>(returnType))
|
||||||
{
|
{
|
||||||
solAssert(CompilerUtils::freeMemoryPointer >= 0x40, "");
|
solAssert(CompilerUtils::freeMemoryPointer >= 0x40, "");
|
||||||
|
|
||||||
@ -152,7 +153,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
|
|||||||
m_context << u256(0);
|
m_context << u256(0);
|
||||||
returnType = mappingType->valueType();
|
returnType = mappingType->valueType();
|
||||||
}
|
}
|
||||||
else if (auto arrayType = dynamic_cast<ArrayType const*>(returnType.get()))
|
else if (auto arrayType = dynamic_cast<ArrayType const*>(returnType))
|
||||||
{
|
{
|
||||||
// pop offset
|
// pop offset
|
||||||
m_context << Instruction::POP;
|
m_context << Instruction::POP;
|
||||||
@ -176,7 +177,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
|
|||||||
unsigned retSizeOnStack = 0;
|
unsigned retSizeOnStack = 0;
|
||||||
auto returnTypes = accessorType.returnParameterTypes();
|
auto returnTypes = accessorType.returnParameterTypes();
|
||||||
solAssert(returnTypes.size() >= 1, "");
|
solAssert(returnTypes.size() >= 1, "");
|
||||||
if (StructType const* structType = dynamic_cast<StructType const*>(returnType.get()))
|
if (StructType const* structType = dynamic_cast<StructType const*>(returnType))
|
||||||
{
|
{
|
||||||
// remove offset
|
// remove offset
|
||||||
m_context << Instruction::POP;
|
m_context << Instruction::POP;
|
||||||
@ -186,7 +187,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
|
|||||||
{
|
{
|
||||||
if (returnTypes[i]->category() == Type::Category::Mapping)
|
if (returnTypes[i]->category() == Type::Category::Mapping)
|
||||||
continue;
|
continue;
|
||||||
if (auto arrayType = dynamic_cast<ArrayType const*>(returnTypes[i].get()))
|
if (auto arrayType = dynamic_cast<ArrayType const*>(returnTypes[i]))
|
||||||
if (!arrayType->isByteArray())
|
if (!arrayType->isByteArray())
|
||||||
continue;
|
continue;
|
||||||
pair<u256, unsigned> const& offsets = structType->storageOffsetsOfMember(names[i]);
|
pair<u256, unsigned> const& offsets = structType->storageOffsetsOfMember(names[i]);
|
||||||
@ -496,7 +497,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
functionType = structType.constructorType();
|
functionType = structType.constructorType();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
functionType = dynamic_pointer_cast<FunctionType const>(_functionCall.expression().annotation().type);
|
functionType = dynamic_cast<FunctionType const*>(_functionCall.expression().annotation().type);
|
||||||
|
|
||||||
TypePointers parameterTypes = functionType->parameterTypes();
|
TypePointers parameterTypes = functionType->parameterTypes();
|
||||||
vector<ASTPointer<Expression const>> const& callArguments = _functionCall.arguments();
|
vector<ASTPointer<Expression const>> const& callArguments = _functionCall.arguments();
|
||||||
@ -647,7 +648,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
_functionCall.expression().accept(*this);
|
_functionCall.expression().accept(*this);
|
||||||
|
|
||||||
arguments.front()->accept(*this);
|
arguments.front()->accept(*this);
|
||||||
utils().convertType(*arguments.front()->annotation().type, IntegerType::uint256(), true);
|
utils().convertType(*arguments.front()->annotation().type, *TypeProvider::uint256(), true);
|
||||||
// Note that function is not the original function, but the ".gas" function.
|
// 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.
|
// Its values of gasSet and valueSet is equal to the original function's though.
|
||||||
unsigned stackDepth = (function.gasSet() ? 1 : 0) + (function.valueSet() ? 1 : 0);
|
unsigned stackDepth = (function.gasSet() ? 1 : 0) + (function.valueSet() ? 1 : 0);
|
||||||
@ -731,9 +732,9 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
arguments.front()->accept(*this);
|
arguments.front()->accept(*this);
|
||||||
// Optimization: If type is bytes or string, then do not encode,
|
// Optimization: If type is bytes or string, then do not encode,
|
||||||
// but directly compute keccak256 on memory.
|
// but directly compute keccak256 on memory.
|
||||||
if (*argType == ArrayType::bytesMemory() || *argType == ArrayType::stringMemory())
|
if (*argType == *TypeProvider::bytesMemoryType() || *argType == *TypeProvider::stringMemoryType())
|
||||||
{
|
{
|
||||||
ArrayUtils(m_context).retrieveLength(ArrayType::bytesMemory());
|
ArrayUtils(m_context).retrieveLength(*TypeProvider::bytesMemoryType());
|
||||||
m_context << Instruction::SWAP1 << u256(0x20) << Instruction::ADD;
|
m_context << Instruction::SWAP1 << u256(0x20) << Instruction::ADD;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -780,7 +781,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
{
|
{
|
||||||
++numIndexed;
|
++numIndexed;
|
||||||
arguments[arg - 1]->accept(*this);
|
arguments[arg - 1]->accept(*this);
|
||||||
if (auto const& referenceType = dynamic_pointer_cast<ReferenceType const>(paramTypes[arg - 1]))
|
if (auto const& referenceType = dynamic_cast<ReferenceType const*>(paramTypes[arg - 1]))
|
||||||
{
|
{
|
||||||
utils().fetchFreeMemoryPointer();
|
utils().fetchFreeMemoryPointer();
|
||||||
utils().packedEncode(
|
utils().packedEncode(
|
||||||
@ -835,13 +836,13 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
case FunctionType::Kind::MulMod:
|
case FunctionType::Kind::MulMod:
|
||||||
{
|
{
|
||||||
arguments[2]->accept(*this);
|
arguments[2]->accept(*this);
|
||||||
utils().convertType(*arguments[2]->annotation().type, IntegerType::uint256());
|
utils().convertType(*arguments[2]->annotation().type, *TypeProvider::uint256());
|
||||||
m_context << Instruction::DUP1 << Instruction::ISZERO;
|
m_context << Instruction::DUP1 << Instruction::ISZERO;
|
||||||
m_context.appendConditionalInvalid();
|
m_context.appendConditionalInvalid();
|
||||||
for (unsigned i = 1; i < 3; i ++)
|
for (unsigned i = 1; i < 3; i ++)
|
||||||
{
|
{
|
||||||
arguments[2 - i]->accept(*this);
|
arguments[2 - i]->accept(*this);
|
||||||
utils().convertType(*arguments[2 - i]->annotation().type, IntegerType::uint256());
|
utils().convertType(*arguments[2 - i]->annotation().type, *TypeProvider::uint256());
|
||||||
}
|
}
|
||||||
if (function.kind() == FunctionType::Kind::AddMod)
|
if (function.kind() == FunctionType::Kind::AddMod)
|
||||||
m_context << Instruction::ADDMOD;
|
m_context << Instruction::ADDMOD;
|
||||||
@ -872,10 +873,10 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
solAssert(function.parameterTypes().size() == 1, "");
|
solAssert(function.parameterTypes().size() == 1, "");
|
||||||
solAssert(!!function.parameterTypes()[0], "");
|
solAssert(!!function.parameterTypes()[0], "");
|
||||||
TypePointer paramType = function.parameterTypes()[0];
|
TypePointer paramType = function.parameterTypes()[0];
|
||||||
shared_ptr<ArrayType> arrayType =
|
ArrayType const* arrayType =
|
||||||
function.kind() == FunctionType::Kind::ArrayPush ?
|
function.kind() == FunctionType::Kind::ArrayPush ?
|
||||||
make_shared<ArrayType>(DataLocation::Storage, paramType) :
|
TypeProvider::arrayType(DataLocation::Storage, paramType) :
|
||||||
make_shared<ArrayType>(DataLocation::Storage);
|
TypeProvider::arrayType(DataLocation::Storage);
|
||||||
|
|
||||||
// stack: ArrayReference
|
// stack: ArrayReference
|
||||||
arguments[0]->accept(*this);
|
arguments[0]->accept(*this);
|
||||||
@ -927,7 +928,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
|
|
||||||
// Fetch requested length.
|
// Fetch requested length.
|
||||||
arguments[0]->accept(*this);
|
arguments[0]->accept(*this);
|
||||||
utils().convertType(*arguments[0]->annotation().type, IntegerType::uint256());
|
utils().convertType(*arguments[0]->annotation().type, *TypeProvider::uint256());
|
||||||
|
|
||||||
// Stack: requested_length
|
// Stack: requested_length
|
||||||
utils().fetchFreeMemoryPointer();
|
utils().fetchFreeMemoryPointer();
|
||||||
@ -1057,11 +1058,11 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
if (function.kind() == FunctionType::Kind::ABIEncodeWithSignature)
|
if (function.kind() == FunctionType::Kind::ABIEncodeWithSignature)
|
||||||
{
|
{
|
||||||
// hash the signature
|
// hash the signature
|
||||||
if (auto const* stringType = dynamic_cast<StringLiteralType const*>(selectorType.get()))
|
if (auto const* stringType = dynamic_cast<StringLiteralType const*>(selectorType))
|
||||||
{
|
{
|
||||||
FixedHash<4> hash(dev::keccak256(stringType->value()));
|
FixedHash<4> hash(dev::keccak256(stringType->value()));
|
||||||
m_context << (u256(FixedHash<4>::Arith(hash)) << (256 - 32));
|
m_context << (u256(FixedHash<4>::Arith(hash)) << (256 - 32));
|
||||||
dataOnStack = make_shared<FixedBytesType>(4);
|
dataOnStack = TypeProvider::fixedBytesType(4);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1072,7 +1073,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
m_context << Instruction::KECCAK256;
|
m_context << Instruction::KECCAK256;
|
||||||
// stack: <memory pointer> <hash>
|
// stack: <memory pointer> <hash>
|
||||||
|
|
||||||
dataOnStack = make_shared<FixedBytesType>(32);
|
dataOnStack = TypeProvider::fixedBytesType(32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1103,7 +1104,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
arguments.front()->accept(*this);
|
arguments.front()->accept(*this);
|
||||||
TypePointer firstArgType = arguments.front()->annotation().type;
|
TypePointer firstArgType = arguments.front()->annotation().type;
|
||||||
TypePointers targetTypes;
|
TypePointers targetTypes;
|
||||||
if (TupleType const* targetTupleType = dynamic_cast<TupleType const*>(_functionCall.annotation().type.get()))
|
if (TupleType const* targetTupleType = dynamic_cast<TupleType const*>(_functionCall.annotation().type))
|
||||||
targetTypes = targetTupleType->components();
|
targetTypes = targetTupleType->components();
|
||||||
else
|
else
|
||||||
targetTypes = TypePointers{_functionCall.annotation().type};
|
targetTypes = TypePointers{_functionCall.annotation().type};
|
||||||
@ -1114,7 +1115,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
utils().abiDecode(targetTypes, false);
|
utils().abiDecode(targetTypes, false);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
utils().convertType(*firstArgType, ArrayType::bytesMemory());
|
utils().convertType(*firstArgType, *TypeProvider::bytesMemoryType());
|
||||||
m_context << Instruction::DUP1 << u256(32) << Instruction::ADD;
|
m_context << Instruction::DUP1 << u256(32) << Instruction::ADD;
|
||||||
m_context << Instruction::SWAP1 << Instruction::MLOAD;
|
m_context << Instruction::SWAP1 << Instruction::MLOAD;
|
||||||
// stack now: <mem_pos> <length>
|
// stack now: <mem_pos> <length>
|
||||||
@ -1145,7 +1146,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
|||||||
CompilerContext::LocationSetter locationSetter(m_context, _memberAccess);
|
CompilerContext::LocationSetter locationSetter(m_context, _memberAccess);
|
||||||
// Check whether the member is a bound function.
|
// Check whether the member is a bound function.
|
||||||
ASTString const& member = _memberAccess.memberName();
|
ASTString const& member = _memberAccess.memberName();
|
||||||
if (auto funType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type.get()))
|
if (auto funType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type))
|
||||||
if (funType->bound())
|
if (funType->bound())
|
||||||
{
|
{
|
||||||
_memberAccess.expression().accept(*this);
|
_memberAccess.expression().accept(*this);
|
||||||
@ -1174,14 +1175,14 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
|||||||
|
|
||||||
// Special processing for TypeType because we do not want to visit the library itself
|
// Special processing for TypeType because we do not want to visit the library itself
|
||||||
// for internal functions, or enum/struct definitions.
|
// for internal functions, or enum/struct definitions.
|
||||||
if (TypeType const* type = dynamic_cast<TypeType const*>(_memberAccess.expression().annotation().type.get()))
|
if (TypeType const* type = dynamic_cast<TypeType const*>(_memberAccess.expression().annotation().type))
|
||||||
{
|
{
|
||||||
if (dynamic_cast<ContractType const*>(type->actualType().get()))
|
if (dynamic_cast<ContractType const*>(type->actualType()))
|
||||||
{
|
{
|
||||||
solAssert(_memberAccess.annotation().type, "_memberAccess has no type");
|
solAssert(_memberAccess.annotation().type, "_memberAccess has no type");
|
||||||
if (auto variable = dynamic_cast<VariableDeclaration const*>(_memberAccess.annotation().referencedDeclaration))
|
if (auto variable = dynamic_cast<VariableDeclaration const*>(_memberAccess.annotation().referencedDeclaration))
|
||||||
appendVariable(*variable, static_cast<Expression const&>(_memberAccess));
|
appendVariable(*variable, static_cast<Expression const&>(_memberAccess));
|
||||||
else if (auto funType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type.get()))
|
else if (auto funType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type))
|
||||||
{
|
{
|
||||||
switch (funType->kind())
|
switch (funType->kind())
|
||||||
{
|
{
|
||||||
@ -1223,14 +1224,14 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
|||||||
solAssert(false, "unsupported member function");
|
solAssert(false, "unsupported member function");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (dynamic_cast<TypeType const*>(_memberAccess.annotation().type.get()))
|
else if (dynamic_cast<TypeType const*>(_memberAccess.annotation().type))
|
||||||
{
|
{
|
||||||
// no-op
|
// no-op
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
_memberAccess.expression().accept(*this);
|
_memberAccess.expression().accept(*this);
|
||||||
}
|
}
|
||||||
else if (auto enumType = dynamic_cast<EnumType const*>(type->actualType().get()))
|
else if (auto enumType = dynamic_cast<EnumType const*>(type->actualType()))
|
||||||
{
|
{
|
||||||
_memberAccess.expression().accept(*this);
|
_memberAccess.expression().accept(*this);
|
||||||
m_context << enumType->memberValue(_memberAccess.memberName());
|
m_context << enumType->memberValue(_memberAccess.memberName());
|
||||||
@ -1288,7 +1289,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
|||||||
identifier = FunctionType(*function).externalIdentifier();
|
identifier = FunctionType(*function).externalIdentifier();
|
||||||
else
|
else
|
||||||
solAssert(false, "Contract member is neither variable nor function.");
|
solAssert(false, "Contract member is neither variable nor function.");
|
||||||
utils().convertType(type, type.isPayable() ? AddressType::addressPayable() : AddressType::address(), true);
|
utils().convertType(type, type.isPayable() ? *TypeProvider::payableAddressType() : *TypeProvider::addressType(), true);
|
||||||
m_context << identifier;
|
m_context << identifier;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1306,7 +1307,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
|||||||
{
|
{
|
||||||
utils().convertType(
|
utils().convertType(
|
||||||
*_memberAccess.expression().annotation().type,
|
*_memberAccess.expression().annotation().type,
|
||||||
AddressType::address(),
|
*TypeProvider::addressType(),
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
m_context << Instruction::BALANCE;
|
m_context << Instruction::BALANCE;
|
||||||
@ -1323,7 +1324,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
|||||||
else if ((set<string>{"call", "callcode", "delegatecall", "staticcall"}).count(member))
|
else if ((set<string>{"call", "callcode", "delegatecall", "staticcall"}).count(member))
|
||||||
utils().convertType(
|
utils().convertType(
|
||||||
*_memberAccess.expression().annotation().type,
|
*_memberAccess.expression().annotation().type,
|
||||||
AddressType::address(),
|
*TypeProvider::addressType(),
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
else
|
else
|
||||||
@ -1542,7 +1543,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
|
|||||||
TypePointers{keyType}
|
TypePointers{keyType}
|
||||||
);
|
);
|
||||||
m_context << Instruction::SWAP1;
|
m_context << Instruction::SWAP1;
|
||||||
utils().storeInMemoryDynamic(IntegerType::uint256());
|
utils().storeInMemoryDynamic(*TypeProvider::uint256());
|
||||||
utils().toSizeAfterFreeMemoryPointer();
|
utils().toSizeAfterFreeMemoryPointer();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1551,7 +1552,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
|
|||||||
appendExpressionCopyToMemory(*keyType, *_indexAccess.indexExpression());
|
appendExpressionCopyToMemory(*keyType, *_indexAccess.indexExpression());
|
||||||
m_context << Instruction::SWAP1;
|
m_context << Instruction::SWAP1;
|
||||||
solAssert(CompilerUtils::freeMemoryPointer >= 0x40, "");
|
solAssert(CompilerUtils::freeMemoryPointer >= 0x40, "");
|
||||||
utils().storeInMemoryDynamic(IntegerType::uint256());
|
utils().storeInMemoryDynamic(*TypeProvider::uint256());
|
||||||
m_context << u256(0);
|
m_context << u256(0);
|
||||||
}
|
}
|
||||||
m_context << Instruction::KECCAK256;
|
m_context << Instruction::KECCAK256;
|
||||||
@ -1564,7 +1565,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
|
|||||||
solAssert(_indexAccess.indexExpression(), "Index expression expected.");
|
solAssert(_indexAccess.indexExpression(), "Index expression expected.");
|
||||||
|
|
||||||
_indexAccess.indexExpression()->accept(*this);
|
_indexAccess.indexExpression()->accept(*this);
|
||||||
utils().convertType(*_indexAccess.indexExpression()->annotation().type, IntegerType::uint256(), true);
|
utils().convertType(*_indexAccess.indexExpression()->annotation().type, *TypeProvider::uint256(), true);
|
||||||
// stack layout: <base_ref> [<length>] <index>
|
// stack layout: <base_ref> [<length>] <index>
|
||||||
switch (arrayType.location())
|
switch (arrayType.location())
|
||||||
{
|
{
|
||||||
@ -1631,7 +1632,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
|
|||||||
solAssert(_indexAccess.indexExpression(), "Index expression expected.");
|
solAssert(_indexAccess.indexExpression(), "Index expression expected.");
|
||||||
|
|
||||||
_indexAccess.indexExpression()->accept(*this);
|
_indexAccess.indexExpression()->accept(*this);
|
||||||
utils().convertType(*_indexAccess.indexExpression()->annotation().type, IntegerType::uint256(), true);
|
utils().convertType(*_indexAccess.indexExpression()->annotation().type, *TypeProvider::uint256(), true);
|
||||||
// stack layout: <value> <index>
|
// stack layout: <value> <index>
|
||||||
// check out-of-bounds access
|
// check out-of-bounds access
|
||||||
m_context << u256(fixedBytesType.numBytes());
|
m_context << u256(fixedBytesType.numBytes());
|
||||||
@ -2211,7 +2212,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
|||||||
needToUpdateFreeMemoryPtr = true;
|
needToUpdateFreeMemoryPtr = true;
|
||||||
else
|
else
|
||||||
for (auto const& retType: returnTypes)
|
for (auto const& retType: returnTypes)
|
||||||
if (dynamic_cast<ReferenceType const*>(retType.get()))
|
if (dynamic_cast<ReferenceType const*>(retType))
|
||||||
needToUpdateFreeMemoryPtr = true;
|
needToUpdateFreeMemoryPtr = true;
|
||||||
|
|
||||||
// Stack: return_data_start
|
// Stack: return_data_start
|
||||||
|
@ -35,7 +35,7 @@ using namespace langutil;
|
|||||||
|
|
||||||
|
|
||||||
StackVariable::StackVariable(CompilerContext& _compilerContext, VariableDeclaration const& _declaration):
|
StackVariable::StackVariable(CompilerContext& _compilerContext, VariableDeclaration const& _declaration):
|
||||||
LValue(_compilerContext, _declaration.annotation().type.get()),
|
LValue(_compilerContext, _declaration.annotation().type),
|
||||||
m_baseStackOffset(m_context.baseStackOffsetOfVariable(_declaration)),
|
m_baseStackOffset(m_context.baseStackOffsetOfVariable(_declaration)),
|
||||||
m_size(m_dataType->sizeOnStack())
|
m_size(m_dataType->sizeOnStack())
|
||||||
{
|
{
|
||||||
@ -475,7 +475,7 @@ void StorageByteArrayElement::setToZero(SourceLocation const&, bool _removeRefer
|
|||||||
}
|
}
|
||||||
|
|
||||||
StorageArrayLength::StorageArrayLength(CompilerContext& _compilerContext, ArrayType const& _arrayType):
|
StorageArrayLength::StorageArrayLength(CompilerContext& _compilerContext, ArrayType const& _arrayType):
|
||||||
LValue(_compilerContext, _arrayType.memberType("length").get()),
|
LValue(_compilerContext, _arrayType.memberType("length")),
|
||||||
m_arrayType(_arrayType)
|
m_arrayType(_arrayType)
|
||||||
{
|
{
|
||||||
solAssert(m_arrayType.isDynamicallySized(), "");
|
solAssert(m_arrayType.isDynamicallySized(), "");
|
||||||
|
@ -145,7 +145,7 @@ string YulUtilFunctions::leftAlignFunction(Type const& _type)
|
|||||||
templ("body", "aligned := value");
|
templ("body", "aligned := value");
|
||||||
break;
|
break;
|
||||||
case Type::Category::Contract:
|
case Type::Category::Contract:
|
||||||
templ("body", "aligned := " + leftAlignFunction(AddressType::address()) + "(value)");
|
templ("body", "aligned := " + leftAlignFunction(*TypeProvider::addressType()) + "(value)");
|
||||||
break;
|
break;
|
||||||
case Type::Category::Enum:
|
case Type::Category::Enum:
|
||||||
{
|
{
|
||||||
|
@ -82,7 +82,7 @@ void IRGeneratorForStatements::endVisit(BinaryOperation const& _binOp)
|
|||||||
{
|
{
|
||||||
solUnimplementedAssert(_binOp.getOperator() == Token::Add, "");
|
solUnimplementedAssert(_binOp.getOperator() == Token::Add, "");
|
||||||
solUnimplementedAssert(*_binOp.leftExpression().annotation().type == *_binOp.rightExpression().annotation().type, "");
|
solUnimplementedAssert(*_binOp.leftExpression().annotation().type == *_binOp.rightExpression().annotation().type, "");
|
||||||
if (IntegerType const* type = dynamic_cast<IntegerType const*>(_binOp.annotation().commonType.get()))
|
if (IntegerType const* type = dynamic_cast<IntegerType const*>(_binOp.annotation().commonType))
|
||||||
{
|
{
|
||||||
solUnimplementedAssert(!type->isSigned(), "");
|
solUnimplementedAssert(!type->isSigned(), "");
|
||||||
m_code <<
|
m_code <<
|
||||||
@ -103,7 +103,7 @@ void IRGeneratorForStatements::endVisit(BinaryOperation const& _binOp)
|
|||||||
bool IRGeneratorForStatements::visit(FunctionCall const& _functionCall)
|
bool IRGeneratorForStatements::visit(FunctionCall const& _functionCall)
|
||||||
{
|
{
|
||||||
solUnimplementedAssert(_functionCall.annotation().kind == FunctionCallKind::FunctionCall, "");
|
solUnimplementedAssert(_functionCall.annotation().kind == FunctionCallKind::FunctionCall, "");
|
||||||
FunctionTypePointer functionType = dynamic_pointer_cast<FunctionType const>(_functionCall.expression().annotation().type);
|
FunctionTypePointer functionType = dynamic_cast<FunctionType const*>(_functionCall.expression().annotation().type);
|
||||||
|
|
||||||
TypePointers parameterTypes = functionType->parameterTypes();
|
TypePointers parameterTypes = functionType->parameterTypes();
|
||||||
vector<ASTPointer<Expression const>> const& callArguments = _functionCall.arguments();
|
vector<ASTPointer<Expression const>> const& callArguments = _functionCall.arguments();
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include <libsolidity/formal/SMTChecker.h>
|
#include <libsolidity/formal/SMTChecker.h>
|
||||||
|
|
||||||
|
#include <libsolidity/ast/TypeProvider.h>
|
||||||
#include <libsolidity/formal/SMTPortfolio.h>
|
#include <libsolidity/formal/SMTPortfolio.h>
|
||||||
#include <libsolidity/formal/SymbolicTypes.h>
|
#include <libsolidity/formal/SymbolicTypes.h>
|
||||||
|
|
||||||
@ -447,7 +448,7 @@ void SMTChecker::checkUnderOverflow()
|
|||||||
void SMTChecker::checkUnderflow(OverflowTarget& _target)
|
void SMTChecker::checkUnderflow(OverflowTarget& _target)
|
||||||
{
|
{
|
||||||
solAssert(_target.type != OverflowTarget::Type::Overflow, "");
|
solAssert(_target.type != OverflowTarget::Type::Overflow, "");
|
||||||
auto intType = dynamic_cast<IntegerType const*>(_target.intType.get());
|
auto intType = dynamic_cast<IntegerType const*>(_target.intType);
|
||||||
checkCondition(
|
checkCondition(
|
||||||
_target.path && _target.value < minValue(*intType),
|
_target.path && _target.value < minValue(*intType),
|
||||||
_target.location,
|
_target.location,
|
||||||
@ -460,7 +461,7 @@ void SMTChecker::checkUnderflow(OverflowTarget& _target)
|
|||||||
void SMTChecker::checkOverflow(OverflowTarget& _target)
|
void SMTChecker::checkOverflow(OverflowTarget& _target)
|
||||||
{
|
{
|
||||||
solAssert(_target.type != OverflowTarget::Type::Underflow, "");
|
solAssert(_target.type != OverflowTarget::Type::Underflow, "");
|
||||||
auto intType = dynamic_cast<IntegerType const*>(_target.intType.get());
|
auto intType = dynamic_cast<IntegerType const*>(_target.intType);
|
||||||
checkCondition(
|
checkCondition(
|
||||||
_target.path && _target.value > maxValue(*intType),
|
_target.path && _target.value > maxValue(*intType),
|
||||||
_target.location,
|
_target.location,
|
||||||
@ -681,7 +682,7 @@ void SMTChecker::inlineFunctionCall(FunctionCall const& _funCall)
|
|||||||
{
|
{
|
||||||
vector<smt::Expression> funArgs;
|
vector<smt::Expression> funArgs;
|
||||||
Expression const* calledExpr = &_funCall.expression();
|
Expression const* calledExpr = &_funCall.expression();
|
||||||
auto const& funType = dynamic_cast<FunctionType const*>(calledExpr->annotation().type.get());
|
auto const& funType = dynamic_cast<FunctionType const*>(calledExpr->annotation().type);
|
||||||
solAssert(funType, "");
|
solAssert(funType, "");
|
||||||
if (funType->bound())
|
if (funType->bound())
|
||||||
{
|
{
|
||||||
@ -803,8 +804,8 @@ void SMTChecker::endVisit(Literal const& _literal)
|
|||||||
{
|
{
|
||||||
if (type.category() == Type::Category::StringLiteral)
|
if (type.category() == Type::Category::StringLiteral)
|
||||||
{
|
{
|
||||||
auto stringType = make_shared<ArrayType>(DataLocation::Memory, true);
|
auto stringType = TypeProvider::stringMemoryType();
|
||||||
auto stringLit = dynamic_cast<StringLiteralType const*>(_literal.annotation().type.get());
|
auto stringLit = dynamic_cast<StringLiteralType const*>(_literal.annotation().type);
|
||||||
solAssert(stringLit, "");
|
solAssert(stringLit, "");
|
||||||
auto result = newSymbolicVariable(*stringType, stringLit->richIdentifier(), *m_interface);
|
auto result = newSymbolicVariable(*stringType, stringLit->richIdentifier(), *m_interface);
|
||||||
m_expressions.emplace(&_literal, result.second);
|
m_expressions.emplace(&_literal, result.second);
|
||||||
@ -859,7 +860,7 @@ bool SMTChecker::visit(MemberAccess const& _memberAccess)
|
|||||||
{
|
{
|
||||||
if (identifier && dynamic_cast<EnumDefinition const*>(identifier->annotation().referencedDeclaration))
|
if (identifier && dynamic_cast<EnumDefinition const*>(identifier->annotation().referencedDeclaration))
|
||||||
{
|
{
|
||||||
auto enumType = dynamic_cast<EnumType const*>(accessType.get());
|
auto enumType = dynamic_cast<EnumType const*>(accessType);
|
||||||
solAssert(enumType, "");
|
solAssert(enumType, "");
|
||||||
defineExpr(_memberAccess, enumType->memberValue(_memberAccess.memberName()));
|
defineExpr(_memberAccess, enumType->memberValue(_memberAccess.memberName()));
|
||||||
}
|
}
|
||||||
@ -939,13 +940,13 @@ void SMTChecker::arrayIndexAssignment(Expression const& _expr, smt::Expression c
|
|||||||
return true;
|
return true;
|
||||||
if (prefix->category() == Type::Category::Mapping)
|
if (prefix->category() == Type::Category::Mapping)
|
||||||
{
|
{
|
||||||
auto mapPrefix = dynamic_cast<MappingType const*>(prefix.get());
|
auto mapPrefix = dynamic_cast<MappingType const*>(prefix);
|
||||||
solAssert(mapPrefix, "");
|
solAssert(mapPrefix, "");
|
||||||
prefix = mapPrefix->valueType();
|
prefix = mapPrefix->valueType();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto arrayPrefix = dynamic_cast<ArrayType const*>(prefix.get());
|
auto arrayPrefix = dynamic_cast<ArrayType const*>(prefix);
|
||||||
solAssert(arrayPrefix, "");
|
solAssert(arrayPrefix, "");
|
||||||
prefix = arrayPrefix->baseType();
|
prefix = arrayPrefix->baseType();
|
||||||
}
|
}
|
||||||
@ -1017,7 +1018,7 @@ bool SMTChecker::shortcutRationalNumber(Expression const& _expr)
|
|||||||
{
|
{
|
||||||
if (_expr.annotation().type->category() == Type::Category::RationalNumber)
|
if (_expr.annotation().type->category() == Type::Category::RationalNumber)
|
||||||
{
|
{
|
||||||
auto rationalType = dynamic_cast<RationalNumberType const*>(_expr.annotation().type.get());
|
auto rationalType = dynamic_cast<RationalNumberType const*>(_expr.annotation().type);
|
||||||
solAssert(rationalType, "");
|
solAssert(rationalType, "");
|
||||||
if (rationalType->isNegative())
|
if (rationalType->isNegative())
|
||||||
defineExpr(_expr, smt::Expression(u2s(rationalType->literalValue(nullptr))));
|
defineExpr(_expr, smt::Expression(u2s(rationalType->literalValue(nullptr))));
|
||||||
@ -1205,7 +1206,7 @@ void SMTChecker::assignment(VariableDeclaration const& _variable, smt::Expressio
|
|||||||
if (type->category() == Type::Category::Integer)
|
if (type->category() == Type::Category::Integer)
|
||||||
addOverflowTarget(OverflowTarget::Type::All, type, _value, _location);
|
addOverflowTarget(OverflowTarget::Type::All, type, _value, _location);
|
||||||
else if (type->category() == Type::Category::Address)
|
else if (type->category() == Type::Category::Address)
|
||||||
addOverflowTarget(OverflowTarget::Type::All, make_shared<IntegerType>(160), _value, _location);
|
addOverflowTarget(OverflowTarget::Type::All, TypeProvider::uint(160), _value, _location);
|
||||||
else if (type->category() == Type::Category::Mapping)
|
else if (type->category() == Type::Category::Mapping)
|
||||||
arrayAssignment();
|
arrayAssignment();
|
||||||
m_interface->addAssertion(newValue(_variable) == _value);
|
m_interface->addAssertion(newValue(_variable) == _value);
|
||||||
@ -1522,7 +1523,7 @@ void SMTChecker::resetVariables(function<bool(VariableDeclaration const&)> const
|
|||||||
|
|
||||||
TypePointer SMTChecker::typeWithoutPointer(TypePointer const& _type)
|
TypePointer SMTChecker::typeWithoutPointer(TypePointer const& _type)
|
||||||
{
|
{
|
||||||
if (auto refType = dynamic_cast<ReferenceType const*>(_type.get()))
|
if (auto refType = dynamic_cast<ReferenceType const*>(_type))
|
||||||
return ReferenceType::copyForLocationIfReference(refType->location(), _type);
|
return ReferenceType::copyForLocationIfReference(refType->location(), _type);
|
||||||
return _type;
|
return _type;
|
||||||
}
|
}
|
||||||
|
@ -178,7 +178,7 @@ private:
|
|||||||
location(_location),
|
location(_location),
|
||||||
callStack(move(_callStack))
|
callStack(move(_callStack))
|
||||||
{
|
{
|
||||||
solAssert(dynamic_cast<IntegerType const*>(intType.get()), "");
|
solAssert(dynamic_cast<IntegerType const*>(intType), "");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include <libsolidity/formal/SymbolicTypes.h>
|
#include <libsolidity/formal/SymbolicTypes.h>
|
||||||
|
|
||||||
|
#include <libsolidity/ast/TypeProvider.h>
|
||||||
#include <libsolidity/ast/Types.h>
|
#include <libsolidity/ast/Types.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@ -115,11 +116,11 @@ pair<bool, shared_ptr<SymbolicVariable>> dev::solidity::newSymbolicVariable(
|
|||||||
{
|
{
|
||||||
bool abstract = false;
|
bool abstract = false;
|
||||||
shared_ptr<SymbolicVariable> var;
|
shared_ptr<SymbolicVariable> var;
|
||||||
TypePointer type = _type.shared_from_this();
|
TypePointer type = &_type;
|
||||||
if (!isSupportedTypeDeclaration(_type))
|
if (!isSupportedTypeDeclaration(_type))
|
||||||
{
|
{
|
||||||
abstract = true;
|
abstract = true;
|
||||||
var = make_shared<SymbolicIntVariable>(make_shared<IntegerType>(256), _uniqueName, _solver);
|
var = make_shared<SymbolicIntVariable>(TypeProvider::uint256(), _uniqueName, _solver);
|
||||||
}
|
}
|
||||||
else if (isBool(_type.category()))
|
else if (isBool(_type.category()))
|
||||||
var = make_shared<SymbolicBoolVariable>(type, _uniqueName, _solver);
|
var = make_shared<SymbolicBoolVariable>(type, _uniqueName, _solver);
|
||||||
@ -129,7 +130,7 @@ pair<bool, shared_ptr<SymbolicVariable>> dev::solidity::newSymbolicVariable(
|
|||||||
var = make_shared<SymbolicIntVariable>(type, _uniqueName, _solver);
|
var = make_shared<SymbolicIntVariable>(type, _uniqueName, _solver);
|
||||||
else if (isFixedBytes(_type.category()))
|
else if (isFixedBytes(_type.category()))
|
||||||
{
|
{
|
||||||
auto fixedBytesType = dynamic_cast<FixedBytesType const*>(type.get());
|
auto fixedBytesType = dynamic_cast<FixedBytesType const*>(type);
|
||||||
solAssert(fixedBytesType, "");
|
solAssert(fixedBytesType, "");
|
||||||
var = make_shared<SymbolicFixedBytesVariable>(fixedBytesType->numBytes(), _uniqueName, _solver);
|
var = make_shared<SymbolicFixedBytesVariable>(fixedBytesType->numBytes(), _uniqueName, _solver);
|
||||||
}
|
}
|
||||||
@ -142,7 +143,7 @@ pair<bool, shared_ptr<SymbolicVariable>> dev::solidity::newSymbolicVariable(
|
|||||||
auto rational = dynamic_cast<RationalNumberType const*>(&_type);
|
auto rational = dynamic_cast<RationalNumberType const*>(&_type);
|
||||||
solAssert(rational, "");
|
solAssert(rational, "");
|
||||||
if (rational->isFractional())
|
if (rational->isFractional())
|
||||||
var = make_shared<SymbolicIntVariable>(make_shared<IntegerType>(256), _uniqueName, _solver);
|
var = make_shared<SymbolicIntVariable>(TypeProvider::uint256(), _uniqueName, _solver);
|
||||||
else
|
else
|
||||||
var = make_shared<SymbolicIntVariable>(type, _uniqueName, _solver);
|
var = make_shared<SymbolicIntVariable>(type, _uniqueName, _solver);
|
||||||
}
|
}
|
||||||
@ -253,14 +254,14 @@ void dev::solidity::smt::setSymbolicUnknownValue(smt::Expression _expr, TypePoin
|
|||||||
solAssert(_type, "");
|
solAssert(_type, "");
|
||||||
if (isEnum(_type->category()))
|
if (isEnum(_type->category()))
|
||||||
{
|
{
|
||||||
auto enumType = dynamic_cast<EnumType const*>(_type.get());
|
auto enumType = dynamic_cast<EnumType const*>(_type);
|
||||||
solAssert(enumType, "");
|
solAssert(enumType, "");
|
||||||
_interface.addAssertion(_expr >= 0);
|
_interface.addAssertion(_expr >= 0);
|
||||||
_interface.addAssertion(_expr < enumType->numberOfMembers());
|
_interface.addAssertion(_expr < enumType->numberOfMembers());
|
||||||
}
|
}
|
||||||
else if (isInteger(_type->category()))
|
else if (isInteger(_type->category()))
|
||||||
{
|
{
|
||||||
auto intType = dynamic_cast<IntegerType const*>(_type.get());
|
auto intType = dynamic_cast<IntegerType const*>(_type);
|
||||||
solAssert(intType, "");
|
solAssert(intType, "");
|
||||||
_interface.addAssertion(_expr >= minValue(*intType));
|
_interface.addAssertion(_expr >= minValue(*intType));
|
||||||
_interface.addAssertion(_expr <= maxValue(*intType));
|
_interface.addAssertion(_expr <= maxValue(*intType));
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include <libsolidity/formal/SymbolicTypes.h>
|
#include <libsolidity/formal/SymbolicTypes.h>
|
||||||
#include <libsolidity/ast/AST.h>
|
#include <libsolidity/ast/AST.h>
|
||||||
|
#include <libsolidity/ast/TypeProvider.h>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace dev;
|
using namespace dev;
|
||||||
@ -102,7 +103,7 @@ SymbolicAddressVariable::SymbolicAddressVariable(
|
|||||||
string _uniqueName,
|
string _uniqueName,
|
||||||
smt::SolverInterface& _interface
|
smt::SolverInterface& _interface
|
||||||
):
|
):
|
||||||
SymbolicIntVariable(make_shared<IntegerType>(160), move(_uniqueName), _interface)
|
SymbolicIntVariable(TypeProvider::uint(160), move(_uniqueName), _interface)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,7 +112,7 @@ SymbolicFixedBytesVariable::SymbolicFixedBytesVariable(
|
|||||||
string _uniqueName,
|
string _uniqueName,
|
||||||
smt::SolverInterface& _interface
|
smt::SolverInterface& _interface
|
||||||
):
|
):
|
||||||
SymbolicIntVariable(make_shared<IntegerType>(_numBytes * 8), move(_uniqueName), _interface)
|
SymbolicIntVariable(TypeProvider::uint(_numBytes * 8), move(_uniqueName), _interface)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ namespace solidity
|
|||||||
// Forward declarations
|
// Forward declarations
|
||||||
class ContractDefinition;
|
class ContractDefinition;
|
||||||
class Type;
|
class Type;
|
||||||
using TypePointer = std::shared_ptr<Type const>;
|
using TypePointer = Type const*;
|
||||||
|
|
||||||
class ABI
|
class ABI
|
||||||
{
|
{
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
#include <libsolidity/analysis/ViewPureChecker.h>
|
#include <libsolidity/analysis/ViewPureChecker.h>
|
||||||
|
|
||||||
#include <libsolidity/ast/AST.h>
|
#include <libsolidity/ast/AST.h>
|
||||||
|
#include <libsolidity/ast/TypeProvider.h>
|
||||||
#include <libsolidity/codegen/Compiler.h>
|
#include <libsolidity/codegen/Compiler.h>
|
||||||
#include <libsolidity/formal/SMTChecker.h>
|
#include <libsolidity/formal/SMTChecker.h>
|
||||||
#include <libsolidity/interface/ABI.h>
|
#include <libsolidity/interface/ABI.h>
|
||||||
@ -66,6 +67,26 @@ using namespace dev;
|
|||||||
using namespace langutil;
|
using namespace langutil;
|
||||||
using namespace dev::solidity;
|
using namespace dev::solidity;
|
||||||
|
|
||||||
|
static int g_compilerStackCounts = 0;
|
||||||
|
|
||||||
|
CompilerStack::CompilerStack(ReadCallback::Callback const& _readFile):
|
||||||
|
m_readFile{_readFile},
|
||||||
|
m_generateIR{false},
|
||||||
|
m_errorList{},
|
||||||
|
m_errorReporter{m_errorList}
|
||||||
|
{
|
||||||
|
// Because TypeProvider is currently a singleton API, we must ensure that
|
||||||
|
// no more than one entity is actually using it at a time.
|
||||||
|
solAssert(g_compilerStackCounts == 0, "You shall not have another CompilerStack aside me.");
|
||||||
|
++g_compilerStackCounts;
|
||||||
|
}
|
||||||
|
|
||||||
|
CompilerStack::~CompilerStack()
|
||||||
|
{
|
||||||
|
--g_compilerStackCounts;
|
||||||
|
TypeProvider::reset();
|
||||||
|
}
|
||||||
|
|
||||||
boost::optional<CompilerStack::Remapping> CompilerStack::parseRemapping(string const& _remapping)
|
boost::optional<CompilerStack::Remapping> CompilerStack::parseRemapping(string const& _remapping)
|
||||||
{
|
{
|
||||||
auto eq = find(_remapping.begin(), _remapping.end(), '=');
|
auto eq = find(_remapping.begin(), _remapping.end(), '=');
|
||||||
@ -157,6 +178,7 @@ void CompilerStack::reset(bool _keepSettings)
|
|||||||
m_sourceOrder.clear();
|
m_sourceOrder.clear();
|
||||||
m_contracts.clear();
|
m_contracts.clear();
|
||||||
m_errorReporter.clear();
|
m_errorReporter.clear();
|
||||||
|
TypeProvider::reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompilerStack::setSources(StringMap const& _sources)
|
void CompilerStack::setSources(StringMap const& _sources)
|
||||||
|
@ -98,11 +98,9 @@ public:
|
|||||||
/// Creates a new compiler stack.
|
/// Creates a new compiler stack.
|
||||||
/// @param _readFile callback to used to read files for import statements. Must return
|
/// @param _readFile callback to used to read files for import statements. Must return
|
||||||
/// and must not emit exceptions.
|
/// and must not emit exceptions.
|
||||||
explicit CompilerStack(ReadCallback::Callback const& _readFile = ReadCallback::Callback()):
|
explicit CompilerStack(ReadCallback::Callback const& _readFile = ReadCallback::Callback());
|
||||||
m_readFile(_readFile),
|
|
||||||
m_generateIR(false),
|
~CompilerStack();
|
||||||
m_errorList(),
|
|
||||||
m_errorReporter(m_errorList) {}
|
|
||||||
|
|
||||||
/// @returns the list of errors that occurred during parsing and type checking.
|
/// @returns the list of errors that occurred during parsing and type checking.
|
||||||
langutil::ErrorList const& errors() const { return m_errorReporter.errors(); }
|
langutil::ErrorList const& errors() const { return m_errorReporter.errors(); }
|
||||||
|
@ -47,21 +47,21 @@ AnalysisFramework::parseAnalyseAndReturnError(
|
|||||||
bool _allowMultipleErrors
|
bool _allowMultipleErrors
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
m_compiler.reset();
|
compiler().reset();
|
||||||
m_compiler.setSources({{"", _insertVersionPragma ? "pragma solidity >=0.0;\n" + _source : _source}});
|
compiler().setSources({{"", _insertVersionPragma ? "pragma solidity >=0.0;\n" + _source : _source}});
|
||||||
m_compiler.setEVMVersion(dev::test::Options::get().evmVersion());
|
compiler().setEVMVersion(dev::test::Options::get().evmVersion());
|
||||||
if (!m_compiler.parse())
|
if (!compiler().parse())
|
||||||
{
|
{
|
||||||
BOOST_FAIL("Parsing contract failed in analysis test suite:" + formatErrors());
|
BOOST_FAIL("Parsing contract failed in analysis test suite:" + formatErrors());
|
||||||
}
|
}
|
||||||
|
|
||||||
m_compiler.analyze();
|
compiler().analyze();
|
||||||
|
|
||||||
ErrorList errors = filterErrors(m_compiler.errors(), _reportWarnings);
|
ErrorList errors = filterErrors(compiler().errors(), _reportWarnings);
|
||||||
if (errors.size() > 1 && !_allowMultipleErrors)
|
if (errors.size() > 1 && !_allowMultipleErrors)
|
||||||
BOOST_FAIL("Multiple errors found: " + formatErrors());
|
BOOST_FAIL("Multiple errors found: " + formatErrors());
|
||||||
|
|
||||||
return make_pair(&m_compiler.ast(""), std::move(errors));
|
return make_pair(&compiler().ast(""), std::move(errors));
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorList AnalysisFramework::filterErrors(ErrorList const& _errorList, bool _includeWarnings) const
|
ErrorList AnalysisFramework::filterErrors(ErrorList const& _errorList, bool _includeWarnings) const
|
||||||
@ -118,7 +118,7 @@ ErrorList AnalysisFramework::expectError(std::string const& _source, bool _warni
|
|||||||
string AnalysisFramework::formatErrors() const
|
string AnalysisFramework::formatErrors() const
|
||||||
{
|
{
|
||||||
string message;
|
string message;
|
||||||
for (auto const& error: m_compiler.errors())
|
for (auto const& error: compiler().errors())
|
||||||
message += formatError(*error);
|
message += formatError(*error);
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
@ -35,8 +35,8 @@ namespace solidity
|
|||||||
|
|
||||||
class Type;
|
class Type;
|
||||||
class FunctionType;
|
class FunctionType;
|
||||||
using TypePointer = std::shared_ptr<Type const>;
|
using TypePointer = Type const*;
|
||||||
using FunctionTypePointer = std::shared_ptr<FunctionType const>;
|
using FunctionTypePointer = FunctionType const*;
|
||||||
|
|
||||||
namespace test
|
namespace test
|
||||||
{
|
{
|
||||||
@ -71,7 +71,25 @@ protected:
|
|||||||
langutil::ErrorList filterErrors(langutil::ErrorList const& _errorList, bool _includeWarnings) const;
|
langutil::ErrorList filterErrors(langutil::ErrorList const& _errorList, bool _includeWarnings) const;
|
||||||
|
|
||||||
std::vector<std::string> m_warningsToFilter = {"This is a pre-release compiler version"};
|
std::vector<std::string> m_warningsToFilter = {"This is a pre-release compiler version"};
|
||||||
dev::solidity::CompilerStack m_compiler;
|
|
||||||
|
/// @returns reference to lazy-instanciated CompilerStack.
|
||||||
|
dev::solidity::CompilerStack& compiler()
|
||||||
|
{
|
||||||
|
if (!m_compiler)
|
||||||
|
m_compiler = std::make_unique<dev::solidity::CompilerStack>();
|
||||||
|
return *m_compiler;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @returns reference to lazy-instanciated CompilerStack.
|
||||||
|
dev::solidity::CompilerStack const& compiler() const
|
||||||
|
{
|
||||||
|
if (!m_compiler)
|
||||||
|
m_compiler = std::make_unique<dev::solidity::CompilerStack>();
|
||||||
|
return *m_compiler;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
mutable std::unique_ptr<dev::solidity::CompilerStack> m_compiler;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Asserts that the compilation down to typechecking
|
// Asserts that the compilation down to typechecking
|
||||||
|
@ -42,11 +42,11 @@ BOOST_AUTO_TEST_CASE(does_not_include_creation_time_only_internal_functions)
|
|||||||
function f() internal { for (uint i = 0; i < 10; ++i) x += 3 + i; }
|
function f() internal { for (uint i = 0; i < 10; ++i) x += 3 + i; }
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
m_compiler.setOptimiserSettings(dev::test::Options::get().optimize);
|
compiler().setOptimiserSettings(dev::test::Options::get().optimize);
|
||||||
BOOST_REQUIRE(success(sourceCode));
|
BOOST_REQUIRE(success(sourceCode));
|
||||||
BOOST_REQUIRE_MESSAGE(m_compiler.compile(), "Compiling contract failed");
|
BOOST_REQUIRE_MESSAGE(compiler().compile(), "Compiling contract failed");
|
||||||
bytes const& creationBytecode = dev::test::bytecodeSansMetadata(m_compiler.object("C").bytecode);
|
bytes const& creationBytecode = dev::test::bytecodeSansMetadata(compiler().object("C").bytecode);
|
||||||
bytes const& runtimeBytecode = dev::test::bytecodeSansMetadata(m_compiler.runtimeObject("C").bytecode);
|
bytes const& runtimeBytecode = dev::test::bytecodeSansMetadata(compiler().runtimeObject("C").bytecode);
|
||||||
BOOST_CHECK(creationBytecode.size() >= 90);
|
BOOST_CHECK(creationBytecode.size() >= 90);
|
||||||
BOOST_CHECK(creationBytecode.size() <= 120);
|
BOOST_CHECK(creationBytecode.size() <= 120);
|
||||||
BOOST_CHECK(runtimeBytecode.size() >= 10);
|
BOOST_CHECK(runtimeBytecode.size() >= 10);
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include <libsolidity/codegen/CompilerContext.h>
|
#include <libsolidity/codegen/CompilerContext.h>
|
||||||
#include <libsolidity/codegen/ExpressionCompiler.h>
|
#include <libsolidity/codegen/ExpressionCompiler.h>
|
||||||
#include <libsolidity/ast/AST.h>
|
#include <libsolidity/ast/AST.h>
|
||||||
|
#include <libsolidity/ast/TypeProvider.h>
|
||||||
#include <libsolidity/analysis/TypeChecker.h>
|
#include <libsolidity/analysis/TypeChecker.h>
|
||||||
#include <liblangutil/ErrorReporter.h>
|
#include <liblangutil/ErrorReporter.h>
|
||||||
#include <test/Options.h>
|
#include <test/Options.h>
|
||||||
@ -597,7 +598,7 @@ BOOST_AUTO_TEST_CASE(blockhash)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
|
|
||||||
auto blockhashFun = make_shared<FunctionType>(strings{"uint256"}, strings{"bytes32"},
|
auto blockhashFun = TypeProvider::functionType(strings{"uint256"}, strings{"bytes32"},
|
||||||
FunctionType::Kind::BlockHash, false, StateMutability::View);
|
FunctionType::Kind::BlockHash, false, StateMutability::View);
|
||||||
|
|
||||||
bytes code = compileFirstExpression(sourceCode, {}, {}, {make_shared<MagicVariableDeclaration>("blockhash", blockhashFun)});
|
bytes code = compileFirstExpression(sourceCode, {}, {}, {make_shared<MagicVariableDeclaration>("blockhash", blockhashFun)});
|
||||||
@ -618,7 +619,7 @@ BOOST_AUTO_TEST_CASE(gas_left)
|
|||||||
)";
|
)";
|
||||||
bytes code = compileFirstExpression(
|
bytes code = compileFirstExpression(
|
||||||
sourceCode, {}, {},
|
sourceCode, {}, {},
|
||||||
{make_shared<MagicVariableDeclaration>("gasleft", make_shared<FunctionType>(strings(), strings{"uint256"}, FunctionType::Kind::GasLeft))}
|
{make_shared<MagicVariableDeclaration>("gasleft", TypeProvider::functionType(strings(), strings{"uint256"}, FunctionType::Kind::GasLeft))}
|
||||||
);
|
);
|
||||||
|
|
||||||
bytes expectation = bytes({uint8_t(Instruction::GAS)});
|
bytes expectation = bytes({uint8_t(Instruction::GAS)});
|
||||||
|
@ -436,7 +436,7 @@ BOOST_AUTO_TEST_CASE(getter_is_memory_type)
|
|||||||
)";
|
)";
|
||||||
CHECK_SUCCESS_NO_WARNINGS(text);
|
CHECK_SUCCESS_NO_WARNINGS(text);
|
||||||
// Check that the getters return a memory strings, not a storage strings.
|
// Check that the getters return a memory strings, not a storage strings.
|
||||||
ContractDefinition const& c = dynamic_cast<ContractDefinition const&>(*m_compiler.ast("").nodes().at(1));
|
ContractDefinition const& c = dynamic_cast<ContractDefinition const&>(*compiler().ast("").nodes().at(1));
|
||||||
BOOST_CHECK(c.interfaceFunctions().size() == 2);
|
BOOST_CHECK(c.interfaceFunctions().size() == 2);
|
||||||
for (auto const& f: c.interfaceFunctions())
|
for (auto const& f: c.interfaceFunctions())
|
||||||
{
|
{
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <libsolidity/ast/Types.h>
|
#include <libsolidity/ast/Types.h>
|
||||||
|
#include <libsolidity/ast/TypeProvider.h>
|
||||||
#include <libsolidity/ast/AST.h>
|
#include <libsolidity/ast/AST.h>
|
||||||
#include <libdevcore/Keccak256.h>
|
#include <libdevcore/Keccak256.h>
|
||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
@ -39,51 +40,51 @@ BOOST_AUTO_TEST_SUITE(SolidityTypes)
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(int_types)
|
BOOST_AUTO_TEST_CASE(int_types)
|
||||||
{
|
{
|
||||||
BOOST_CHECK(*Type::fromElementaryTypeName(ElementaryTypeNameToken(Token::Int, 0, 0)) == *make_shared<IntegerType>(256, IntegerType::Modifier::Signed));
|
BOOST_CHECK(*TypeProvider::fromElementaryTypeName(ElementaryTypeNameToken(Token::Int, 0, 0)) == *TypeProvider::integerType(256, IntegerType::Modifier::Signed));
|
||||||
for (unsigned i = 8; i <= 256; i += 8)
|
for (unsigned i = 8; i <= 256; i += 8)
|
||||||
BOOST_CHECK(*Type::fromElementaryTypeName(ElementaryTypeNameToken(Token::IntM, i, 0)) == *make_shared<IntegerType>(i, IntegerType::Modifier::Signed));
|
BOOST_CHECK(*TypeProvider::fromElementaryTypeName(ElementaryTypeNameToken(Token::IntM, i, 0)) == *TypeProvider::integerType(i, IntegerType::Modifier::Signed));
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(uint_types)
|
BOOST_AUTO_TEST_CASE(uint_types)
|
||||||
{
|
{
|
||||||
BOOST_CHECK(*Type::fromElementaryTypeName(ElementaryTypeNameToken(Token::UInt, 0, 0)) == *make_shared<IntegerType>(256, IntegerType::Modifier::Unsigned));
|
BOOST_CHECK(*TypeProvider::fromElementaryTypeName(ElementaryTypeNameToken(Token::UInt, 0, 0)) == *TypeProvider::integerType(256, IntegerType::Modifier::Unsigned));
|
||||||
for (unsigned i = 8; i <= 256; i += 8)
|
for (unsigned i = 8; i <= 256; i += 8)
|
||||||
BOOST_CHECK(*Type::fromElementaryTypeName(ElementaryTypeNameToken(Token::UIntM, i, 0)) == *make_shared<IntegerType>(i, IntegerType::Modifier::Unsigned));
|
BOOST_CHECK(*TypeProvider::fromElementaryTypeName(ElementaryTypeNameToken(Token::UIntM, i, 0)) == *TypeProvider::integerType(i, IntegerType::Modifier::Unsigned));
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(byte_types)
|
BOOST_AUTO_TEST_CASE(byte_types)
|
||||||
{
|
{
|
||||||
BOOST_CHECK(*Type::fromElementaryTypeName(ElementaryTypeNameToken(Token::Byte, 0, 0)) == *make_shared<FixedBytesType>(1));
|
BOOST_CHECK(*TypeProvider::fromElementaryTypeName(ElementaryTypeNameToken(Token::Byte, 0, 0)) == *TypeProvider::fixedBytesType(1));
|
||||||
for (unsigned i = 1; i <= 32; i++)
|
for (unsigned i = 1; i <= 32; i++)
|
||||||
BOOST_CHECK(*Type::fromElementaryTypeName(ElementaryTypeNameToken(Token::BytesM, i, 0)) == *make_shared<FixedBytesType>(i));
|
BOOST_CHECK(*TypeProvider::fromElementaryTypeName(ElementaryTypeNameToken(Token::BytesM, i, 0)) == *TypeProvider::fixedBytesType(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(fixed_types)
|
BOOST_AUTO_TEST_CASE(fixed_types)
|
||||||
{
|
{
|
||||||
BOOST_CHECK(*Type::fromElementaryTypeName(ElementaryTypeNameToken(Token::Fixed, 0, 0)) == *make_shared<FixedPointType>(128, 18, FixedPointType::Modifier::Signed));
|
BOOST_CHECK(*TypeProvider::fromElementaryTypeName(ElementaryTypeNameToken(Token::Fixed, 0, 0)) == *TypeProvider::fixedPointType(128, 18, FixedPointType::Modifier::Signed));
|
||||||
for (unsigned i = 8; i <= 256; i += 8)
|
for (unsigned i = 8; i <= 256; i += 8)
|
||||||
{
|
{
|
||||||
BOOST_CHECK(*Type::fromElementaryTypeName(ElementaryTypeNameToken(Token::FixedMxN, i, 0)) == *make_shared<FixedPointType>(i, 0, FixedPointType::Modifier::Signed));
|
BOOST_CHECK(*TypeProvider::fromElementaryTypeName(ElementaryTypeNameToken(Token::FixedMxN, i, 0)) == *TypeProvider::fixedPointType(i, 0, FixedPointType::Modifier::Signed));
|
||||||
BOOST_CHECK(*Type::fromElementaryTypeName(ElementaryTypeNameToken(Token::FixedMxN, i, 2)) == *make_shared<FixedPointType>(i, 2, FixedPointType::Modifier::Signed));
|
BOOST_CHECK(*TypeProvider::fromElementaryTypeName(ElementaryTypeNameToken(Token::FixedMxN, i, 2)) == *TypeProvider::fixedPointType(i, 2, FixedPointType::Modifier::Signed));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(ufixed_types)
|
BOOST_AUTO_TEST_CASE(ufixed_types)
|
||||||
{
|
{
|
||||||
BOOST_CHECK(*Type::fromElementaryTypeName(ElementaryTypeNameToken(Token::UFixed, 0, 0)) == *make_shared<FixedPointType>(128, 18, FixedPointType::Modifier::Unsigned));
|
BOOST_CHECK(*TypeProvider::fromElementaryTypeName(ElementaryTypeNameToken(Token::UFixed, 0, 0)) == *TypeProvider::fixedPointType(128, 18, FixedPointType::Modifier::Unsigned));
|
||||||
for (unsigned i = 8; i <= 256; i += 8)
|
for (unsigned i = 8; i <= 256; i += 8)
|
||||||
{
|
{
|
||||||
BOOST_CHECK(*Type::fromElementaryTypeName(ElementaryTypeNameToken(Token::UFixedMxN, i, 0)) == *make_shared<FixedPointType>(i, 0, FixedPointType::Modifier::Unsigned));
|
BOOST_CHECK(*TypeProvider::fromElementaryTypeName(ElementaryTypeNameToken(Token::UFixedMxN, i, 0)) == *TypeProvider::fixedPointType(i, 0, FixedPointType::Modifier::Unsigned));
|
||||||
BOOST_CHECK(*Type::fromElementaryTypeName(ElementaryTypeNameToken(Token::UFixedMxN, i, 2)) == *make_shared<FixedPointType>(i, 2, FixedPointType::Modifier::Unsigned));
|
BOOST_CHECK(*TypeProvider::fromElementaryTypeName(ElementaryTypeNameToken(Token::UFixedMxN, i, 2)) == *TypeProvider::fixedPointType(i, 2, FixedPointType::Modifier::Unsigned));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(storage_layout_simple)
|
BOOST_AUTO_TEST_CASE(storage_layout_simple)
|
||||||
{
|
{
|
||||||
MemberList members(MemberList::MemberMap({
|
MemberList members(MemberList::MemberMap({
|
||||||
{string("first"), Type::fromElementaryTypeName("uint128")},
|
{string("first"), TypeProvider::fromElementaryTypeName("uint128")},
|
||||||
{string("second"), Type::fromElementaryTypeName("uint120")},
|
{string("second"), TypeProvider::fromElementaryTypeName("uint120")},
|
||||||
{string("wraps"), Type::fromElementaryTypeName("uint16")}
|
{string("wraps"), TypeProvider::fromElementaryTypeName("uint16")}
|
||||||
}));
|
}));
|
||||||
BOOST_REQUIRE_EQUAL(u256(2), members.storageSize());
|
BOOST_REQUIRE_EQUAL(u256(2), members.storageSize());
|
||||||
BOOST_REQUIRE(members.memberStorageOffset("first") != nullptr);
|
BOOST_REQUIRE(members.memberStorageOffset("first") != nullptr);
|
||||||
@ -97,15 +98,15 @@ BOOST_AUTO_TEST_CASE(storage_layout_simple)
|
|||||||
BOOST_AUTO_TEST_CASE(storage_layout_mapping)
|
BOOST_AUTO_TEST_CASE(storage_layout_mapping)
|
||||||
{
|
{
|
||||||
MemberList members(MemberList::MemberMap({
|
MemberList members(MemberList::MemberMap({
|
||||||
{string("first"), Type::fromElementaryTypeName("uint128")},
|
{string("first"), TypeProvider::fromElementaryTypeName("uint128")},
|
||||||
{string("second"), make_shared<MappingType>(
|
{string("second"), TypeProvider::mappingType(
|
||||||
Type::fromElementaryTypeName("uint8"),
|
TypeProvider::fromElementaryTypeName("uint8"),
|
||||||
Type::fromElementaryTypeName("uint8")
|
TypeProvider::fromElementaryTypeName("uint8")
|
||||||
)},
|
)},
|
||||||
{string("third"), Type::fromElementaryTypeName("uint16")},
|
{string("third"), TypeProvider::fromElementaryTypeName("uint16")},
|
||||||
{string("final"), make_shared<MappingType>(
|
{string("final"), TypeProvider::mappingType(
|
||||||
Type::fromElementaryTypeName("uint8"),
|
TypeProvider::fromElementaryTypeName("uint8"),
|
||||||
Type::fromElementaryTypeName("uint8")
|
TypeProvider::fromElementaryTypeName("uint8")
|
||||||
)},
|
)},
|
||||||
}));
|
}));
|
||||||
BOOST_REQUIRE_EQUAL(u256(4), members.storageSize());
|
BOOST_REQUIRE_EQUAL(u256(4), members.storageSize());
|
||||||
@ -121,13 +122,13 @@ BOOST_AUTO_TEST_CASE(storage_layout_mapping)
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(storage_layout_arrays)
|
BOOST_AUTO_TEST_CASE(storage_layout_arrays)
|
||||||
{
|
{
|
||||||
BOOST_CHECK(ArrayType(DataLocation::Storage, make_shared<FixedBytesType>(1), 32).storageSize() == 1);
|
BOOST_CHECK(ArrayType(DataLocation::Storage, TypeProvider::fixedBytesType(1), 32).storageSize() == 1);
|
||||||
BOOST_CHECK(ArrayType(DataLocation::Storage, make_shared<FixedBytesType>(1), 33).storageSize() == 2);
|
BOOST_CHECK(ArrayType(DataLocation::Storage, TypeProvider::fixedBytesType(1), 33).storageSize() == 2);
|
||||||
BOOST_CHECK(ArrayType(DataLocation::Storage, make_shared<FixedBytesType>(2), 31).storageSize() == 2);
|
BOOST_CHECK(ArrayType(DataLocation::Storage, TypeProvider::fixedBytesType(2), 31).storageSize() == 2);
|
||||||
BOOST_CHECK(ArrayType(DataLocation::Storage, make_shared<FixedBytesType>(7), 8).storageSize() == 2);
|
BOOST_CHECK(ArrayType(DataLocation::Storage, TypeProvider::fixedBytesType(7), 8).storageSize() == 2);
|
||||||
BOOST_CHECK(ArrayType(DataLocation::Storage, make_shared<FixedBytesType>(7), 9).storageSize() == 3);
|
BOOST_CHECK(ArrayType(DataLocation::Storage, TypeProvider::fixedBytesType(7), 9).storageSize() == 3);
|
||||||
BOOST_CHECK(ArrayType(DataLocation::Storage, make_shared<FixedBytesType>(31), 9).storageSize() == 9);
|
BOOST_CHECK(ArrayType(DataLocation::Storage, TypeProvider::fixedBytesType(31), 9).storageSize() == 9);
|
||||||
BOOST_CHECK(ArrayType(DataLocation::Storage, make_shared<FixedBytesType>(32), 9).storageSize() == 9);
|
BOOST_CHECK(ArrayType(DataLocation::Storage, TypeProvider::fixedBytesType(32), 9).storageSize() == 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(type_identifier_escaping)
|
BOOST_AUTO_TEST_CASE(type_identifier_escaping)
|
||||||
@ -149,12 +150,12 @@ BOOST_AUTO_TEST_CASE(type_identifier_escaping)
|
|||||||
BOOST_AUTO_TEST_CASE(type_identifiers)
|
BOOST_AUTO_TEST_CASE(type_identifiers)
|
||||||
{
|
{
|
||||||
ASTNode::resetID();
|
ASTNode::resetID();
|
||||||
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("uint128")->identifier(), "t_uint128");
|
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("uint128")->identifier(), "t_uint128");
|
||||||
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("int128")->identifier(), "t_int128");
|
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("int128")->identifier(), "t_int128");
|
||||||
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("address")->identifier(), "t_address");
|
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("address")->identifier(), "t_address");
|
||||||
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("uint8")->identifier(), "t_uint8");
|
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("uint8")->identifier(), "t_uint8");
|
||||||
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("ufixed64x2")->identifier(), "t_ufixed64x2");
|
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("ufixed64x2")->identifier(), "t_ufixed64x2");
|
||||||
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("fixed128x8")->identifier(), "t_fixed128x8");
|
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("fixed128x8")->identifier(), "t_fixed128x8");
|
||||||
BOOST_CHECK_EQUAL(RationalNumberType(rational(7, 1)).identifier(), "t_rational_7_by_1");
|
BOOST_CHECK_EQUAL(RationalNumberType(rational(7, 1)).identifier(), "t_rational_7_by_1");
|
||||||
BOOST_CHECK_EQUAL(RationalNumberType(rational(200, 77)).identifier(), "t_rational_200_by_77");
|
BOOST_CHECK_EQUAL(RationalNumberType(rational(200, 77)).identifier(), "t_rational_200_by_77");
|
||||||
BOOST_CHECK_EQUAL(RationalNumberType(rational(2 * 200, 2 * 77)).identifier(), "t_rational_200_by_77");
|
BOOST_CHECK_EQUAL(RationalNumberType(rational(2 * 200, 2 * 77)).identifier(), "t_rational_200_by_77");
|
||||||
@ -163,22 +164,22 @@ BOOST_AUTO_TEST_CASE(type_identifiers)
|
|||||||
StringLiteralType(Literal(SourceLocation{}, Token::StringLiteral, make_shared<string>("abc - def"))).identifier(),
|
StringLiteralType(Literal(SourceLocation{}, Token::StringLiteral, make_shared<string>("abc - def"))).identifier(),
|
||||||
"t_stringliteral_196a9142ee0d40e274a6482393c762b16dd8315713207365e1e13d8d85b74fc4"
|
"t_stringliteral_196a9142ee0d40e274a6482393c762b16dd8315713207365e1e13d8d85b74fc4"
|
||||||
);
|
);
|
||||||
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("byte")->identifier(), "t_bytes1");
|
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("byte")->identifier(), "t_bytes1");
|
||||||
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("bytes8")->identifier(), "t_bytes8");
|
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("bytes8")->identifier(), "t_bytes8");
|
||||||
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("bytes32")->identifier(), "t_bytes32");
|
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("bytes32")->identifier(), "t_bytes32");
|
||||||
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("bool")->identifier(), "t_bool");
|
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("bool")->identifier(), "t_bool");
|
||||||
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("bytes")->identifier(), "t_bytes_storage_ptr");
|
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("bytes")->identifier(), "t_bytes_storage_ptr");
|
||||||
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("bytes memory")->identifier(), "t_bytes_memory_ptr");
|
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("bytes memory")->identifier(), "t_bytes_memory_ptr");
|
||||||
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("bytes storage")->identifier(), "t_bytes_storage_ptr");
|
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("bytes storage")->identifier(), "t_bytes_storage_ptr");
|
||||||
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("bytes calldata")->identifier(), "t_bytes_calldata_ptr");
|
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("bytes calldata")->identifier(), "t_bytes_calldata_ptr");
|
||||||
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("string")->identifier(), "t_string_storage_ptr");
|
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("string")->identifier(), "t_string_storage_ptr");
|
||||||
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("string memory")->identifier(), "t_string_memory_ptr");
|
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("string memory")->identifier(), "t_string_memory_ptr");
|
||||||
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("string storage")->identifier(), "t_string_storage_ptr");
|
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("string storage")->identifier(), "t_string_storage_ptr");
|
||||||
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("string calldata")->identifier(), "t_string_calldata_ptr");
|
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("string calldata")->identifier(), "t_string_calldata_ptr");
|
||||||
ArrayType largeintArray(DataLocation::Memory, Type::fromElementaryTypeName("int128"), u256("2535301200456458802993406410752"));
|
ArrayType largeintArray(DataLocation::Memory, TypeProvider::fromElementaryTypeName("int128"), u256("2535301200456458802993406410752"));
|
||||||
BOOST_CHECK_EQUAL(largeintArray.identifier(), "t_array$_t_int128_$2535301200456458802993406410752_memory_ptr");
|
BOOST_CHECK_EQUAL(largeintArray.identifier(), "t_array$_t_int128_$2535301200456458802993406410752_memory_ptr");
|
||||||
TypePointer stringArray = make_shared<ArrayType>(DataLocation::Storage, Type::fromElementaryTypeName("string"), u256("20"));
|
TypePointer stringArray = TypeProvider::arrayType(DataLocation::Storage, TypeProvider::fromElementaryTypeName("string"), u256("20"));
|
||||||
TypePointer multiArray = make_shared<ArrayType>(DataLocation::Storage, stringArray);
|
TypePointer multiArray = TypeProvider::arrayType(DataLocation::Storage, stringArray);
|
||||||
BOOST_CHECK_EQUAL(multiArray->identifier(), "t_array$_t_array$_t_string_storage_$20_storage_$dyn_storage_ptr");
|
BOOST_CHECK_EQUAL(multiArray->identifier(), "t_array$_t_array$_t_string_storage_$20_storage_$dyn_storage_ptr");
|
||||||
|
|
||||||
ContractDefinition c(SourceLocation{}, make_shared<string>("MyContract$"), {}, {}, {}, ContractDefinition::ContractKind::Contract);
|
ContractDefinition c(SourceLocation{}, make_shared<string>("MyContract$"), {}, {}, {}, ContractDefinition::ContractKind::Contract);
|
||||||
@ -194,14 +195,14 @@ BOOST_AUTO_TEST_CASE(type_identifiers)
|
|||||||
TupleType t({e.type(), s.type(), stringArray, nullptr});
|
TupleType t({e.type(), s.type(), stringArray, nullptr});
|
||||||
BOOST_CHECK_EQUAL(t.identifier(), "t_tuple$_t_type$_t_enum$_Enum_$4_$_$_t_type$_t_struct$_Struct_$3_storage_ptr_$_$_t_array$_t_string_storage_$20_storage_ptr_$__$");
|
BOOST_CHECK_EQUAL(t.identifier(), "t_tuple$_t_type$_t_enum$_Enum_$4_$_$_t_type$_t_struct$_Struct_$3_storage_ptr_$_$_t_array$_t_string_storage_$20_storage_ptr_$__$");
|
||||||
|
|
||||||
TypePointer keccak256fun = make_shared<FunctionType>(strings{}, strings{}, FunctionType::Kind::KECCAK256);
|
TypePointer keccak256fun = TypeProvider::functionType(strings{}, strings{}, FunctionType::Kind::KECCAK256);
|
||||||
BOOST_CHECK_EQUAL(keccak256fun->identifier(), "t_function_keccak256_nonpayable$__$returns$__$");
|
BOOST_CHECK_EQUAL(keccak256fun->identifier(), "t_function_keccak256_nonpayable$__$returns$__$");
|
||||||
|
|
||||||
FunctionType metaFun(TypePointers{keccak256fun}, TypePointers{s.type()}, strings{""}, strings{""});
|
FunctionType metaFun(TypePointers{keccak256fun}, TypePointers{s.type()}, strings{""}, strings{""});
|
||||||
BOOST_CHECK_EQUAL(metaFun.identifier(), "t_function_internal_nonpayable$_t_function_keccak256_nonpayable$__$returns$__$_$returns$_t_type$_t_struct$_Struct_$3_storage_ptr_$_$");
|
BOOST_CHECK_EQUAL(metaFun.identifier(), "t_function_internal_nonpayable$_t_function_keccak256_nonpayable$__$returns$__$_$returns$_t_type$_t_struct$_Struct_$3_storage_ptr_$_$");
|
||||||
|
|
||||||
TypePointer m = make_shared<MappingType>(Type::fromElementaryTypeName("bytes32"), s.type());
|
TypePointer m = TypeProvider::mappingType(TypeProvider::fromElementaryTypeName("bytes32"), s.type());
|
||||||
MappingType m2(Type::fromElementaryTypeName("uint64"), m);
|
MappingType m2(TypeProvider::fromElementaryTypeName("uint64"), m);
|
||||||
BOOST_CHECK_EQUAL(m2.identifier(), "t_mapping$_t_uint64_$_t_mapping$_t_bytes32_$_t_type$_t_struct$_Struct_$3_storage_ptr_$_$_$");
|
BOOST_CHECK_EQUAL(m2.identifier(), "t_mapping$_t_uint64_$_t_mapping$_t_bytes32_$_t_type$_t_struct$_Struct_$3_storage_ptr_$_$_$");
|
||||||
|
|
||||||
// TypeType is tested with contract
|
// TypeType is tested with contract
|
||||||
@ -230,9 +231,9 @@ BOOST_AUTO_TEST_CASE(encoded_sizes)
|
|||||||
BOOST_CHECK_EQUAL(BoolType().calldataEncodedSize(true), 32);
|
BOOST_CHECK_EQUAL(BoolType().calldataEncodedSize(true), 32);
|
||||||
BOOST_CHECK_EQUAL(BoolType().calldataEncodedSize(false), 1);
|
BOOST_CHECK_EQUAL(BoolType().calldataEncodedSize(false), 1);
|
||||||
|
|
||||||
shared_ptr<ArrayType> uint24Array = make_shared<ArrayType>(
|
ArrayType const* uint24Array = TypeProvider::arrayType(
|
||||||
DataLocation::Memory,
|
DataLocation::Memory,
|
||||||
make_shared<IntegerType>(24),
|
TypeProvider::uint(24),
|
||||||
9
|
9
|
||||||
);
|
);
|
||||||
BOOST_CHECK_EQUAL(uint24Array->calldataEncodedSize(true), 9 * 32);
|
BOOST_CHECK_EQUAL(uint24Array->calldataEncodedSize(true), 9 * 32);
|
||||||
|
@ -66,14 +66,14 @@ SyntaxTest::SyntaxTest(string const& _filename, langutil::EVMVersion _evmVersion
|
|||||||
bool SyntaxTest::run(ostream& _stream, string const& _linePrefix, bool _formatted)
|
bool SyntaxTest::run(ostream& _stream, string const& _linePrefix, bool _formatted)
|
||||||
{
|
{
|
||||||
string const versionPragma = "pragma solidity >=0.0;\n";
|
string const versionPragma = "pragma solidity >=0.0;\n";
|
||||||
m_compiler.reset();
|
compiler().reset();
|
||||||
m_compiler.setSources({{"", versionPragma + m_source}});
|
compiler().setSources({{"", versionPragma + m_source}});
|
||||||
m_compiler.setEVMVersion(m_evmVersion);
|
compiler().setEVMVersion(m_evmVersion);
|
||||||
|
|
||||||
if (m_compiler.parse())
|
if (compiler().parse())
|
||||||
m_compiler.analyze();
|
compiler().analyze();
|
||||||
|
|
||||||
for (auto const& currentError: filterErrors(m_compiler.errors(), true))
|
for (auto const& currentError: filterErrors(compiler().errors(), true))
|
||||||
{
|
{
|
||||||
int locationStart = -1, locationEnd = -1;
|
int locationStart = -1, locationEnd = -1;
|
||||||
if (auto location = boost::get_error_info<errinfo_sourceLocation>(*currentError))
|
if (auto location = boost::get_error_info<errinfo_sourceLocation>(*currentError))
|
||||||
|
Loading…
Reference in New Issue
Block a user