Merge pull request #6417 from ethereum/memleaks

Type System API refactor
This commit is contained in:
chriseth 2019-04-17 11:04:24 +02:00 committed by GitHub
commit b8ad8fb15e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 1635 additions and 860 deletions

View File

@ -47,6 +47,8 @@ set(sources
ast/ExperimentalFeatures.h
ast/Types.cpp
ast/Types.h
ast/TypeProvider.cpp
ast/TypeProvider.h
codegen/ABIFunctions.cpp
codegen/ABIFunctions.h
codegen/ArrayUtils.cpp

View File

@ -23,6 +23,7 @@
#include <libsolidity/analysis/ConstantEvaluator.h>
#include <libsolidity/ast/AST.h>
#include <libsolidity/ast/TypeProvider.h>
#include <liblangutil/ErrorReporter.h>
using namespace std;
@ -56,7 +57,7 @@ void ConstantEvaluator::endVisit(BinaryOperation const& _operation)
setType(
_operation,
TokenTraits::isCompareOp(_operation.getOperator()) ?
make_shared<BoolType>() :
TypeProvider::boolType() :
commonType
);
}
@ -64,7 +65,7 @@ void ConstantEvaluator::endVisit(BinaryOperation const& _operation)
void ConstantEvaluator::endVisit(Literal const& _literal)
{
setType(_literal, Type::forLiteral(_literal));
setType(_literal, TypeProvider::forLiteral(_literal));
}
void ConstantEvaluator::endVisit(Identifier const& _identifier)

View File

@ -22,6 +22,7 @@
#include <libsolidity/analysis/ContractLevelChecker.h>
#include <libsolidity/ast/AST.h>
#include <libsolidity/ast/TypeProvider.h>
#include <libsolidity/analysis/TypeChecker.h>
#include <liblangutil/ErrorReporter.h>
#include <boost/range/adaptor/reversed.hpp>
@ -244,13 +245,13 @@ void ContractLevelChecker::checkAbstractFunctions(ContractDefinition const& _con
{
for (VariableDeclaration const* v: contract->stateVariables())
if (v->isPartOfExternalInterface())
registerFunction(*v, make_shared<FunctionType>(*v), true);
registerFunction(*v, TypeProvider::functionType(*v), true);
for (FunctionDefinition const* function: contract->definedFunctions())
if (!function->isConstructor())
registerFunction(
*function,
make_shared<FunctionType>(*function)->asCallableFunction(false),
TypeProvider::functionType(*function)->asCallableFunction(false),
function->isImplemented()
);
}
@ -407,7 +408,7 @@ void ContractLevelChecker::checkExternalTypeClashes(ContractDefinition const& _c
for (FunctionDefinition const* f: contract->definedFunctions())
if (f->isPartOfExternalInterface())
{
auto functionType = make_shared<FunctionType>(*f);
auto functionType = TypeProvider::functionType(*f);
// under non error circumstances this should be true
if (functionType->interfaceFunctionType())
externalDeclarations[functionType->externalSignature()].emplace_back(
@ -417,7 +418,7 @@ void ContractLevelChecker::checkExternalTypeClashes(ContractDefinition const& _c
for (VariableDeclaration const* v: contract->stateVariables())
if (v->isPartOfExternalInterface())
{
auto functionType = make_shared<FunctionType>(*v);
auto functionType = TypeProvider::functionType(*v);
// under non error circumstances this should be true
if (functionType->interfaceFunctionType())
externalDeclarations[functionType->externalSignature()].emplace_back(

View File

@ -235,7 +235,7 @@ bool ControlFlowBuilder::visit(FunctionCall const& _functionCall)
solAssert(!!m_currentNode, "");
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())
{
case FunctionType::Kind::Revert:

View File

@ -24,6 +24,7 @@
#include <libsolidity/analysis/GlobalContext.h>
#include <libsolidity/ast/AST.h>
#include <libsolidity/ast/TypeProvider.h>
#include <libsolidity/ast/Types.h>
#include <memory>
@ -34,42 +35,50 @@ namespace dev
namespace solidity
{
GlobalContext::GlobalContext():
m_magicVariables(vector<shared_ptr<MagicVariableDeclaration const>>{
make_shared<MagicVariableDeclaration>("abi", make_shared<MagicType>(MagicType::Kind::ABI)),
make_shared<MagicVariableDeclaration>("addmod", make_shared<FunctionType>(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Kind::AddMod, false, StateMutability::Pure)),
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)),
make_shared<MagicVariableDeclaration>("ecrecover", make_shared<FunctionType>(strings{"bytes32", "uint8", "bytes32", "bytes32"}, strings{"address"}, FunctionType::Kind::ECRecover, false, StateMutability::Pure)),
make_shared<MagicVariableDeclaration>("gasleft", make_shared<FunctionType>(strings(), strings{"uint256"}, FunctionType::Kind::GasLeft, false, StateMutability::View)),
make_shared<MagicVariableDeclaration>("keccak256", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::KECCAK256, false, StateMutability::Pure)),
make_shared<MagicVariableDeclaration>("log0", make_shared<FunctionType>(strings{"bytes32"}, strings{}, FunctionType::Kind::Log0)),
make_shared<MagicVariableDeclaration>("log1", make_shared<FunctionType>(strings{"bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log1)),
make_shared<MagicVariableDeclaration>("log2", make_shared<FunctionType>(strings{"bytes32", "bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log2)),
make_shared<MagicVariableDeclaration>("log3", make_shared<FunctionType>(strings{"bytes32", "bytes32", "bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log3)),
make_shared<MagicVariableDeclaration>("log4", make_shared<FunctionType>(strings{"bytes32", "bytes32", "bytes32", "bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log4)),
make_shared<MagicVariableDeclaration>("msg", make_shared<MagicType>(MagicType::Kind::Message)),
make_shared<MagicVariableDeclaration>("mulmod", make_shared<FunctionType>(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Kind::MulMod, false, StateMutability::Pure)),
make_shared<MagicVariableDeclaration>("now", make_shared<IntegerType>(256)),
make_shared<MagicVariableDeclaration>("require", make_shared<FunctionType>(strings{"bool"}, strings{}, FunctionType::Kind::Require, false, StateMutability::Pure)),
make_shared<MagicVariableDeclaration>("require", make_shared<FunctionType>(strings{"bool", "string memory"}, strings{}, FunctionType::Kind::Require, false, StateMutability::Pure)),
make_shared<MagicVariableDeclaration>("revert", make_shared<FunctionType>(strings(), strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)),
make_shared<MagicVariableDeclaration>("revert", make_shared<FunctionType>(strings{"string memory"}, strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)),
make_shared<MagicVariableDeclaration>("ripemd160", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bytes20"}, FunctionType::Kind::RIPEMD160, false, StateMutability::Pure)),
make_shared<MagicVariableDeclaration>("selfdestruct", make_shared<FunctionType>(strings{"address payable"}, strings{}, FunctionType::Kind::Selfdestruct)),
make_shared<MagicVariableDeclaration>("sha256", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::SHA256, false, StateMutability::Pure)),
make_shared<MagicVariableDeclaration>("sha3", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::KECCAK256, false, StateMutability::Pure)),
make_shared<MagicVariableDeclaration>("suicide", make_shared<FunctionType>(strings{"address payable"}, strings{}, FunctionType::Kind::Selfdestruct)),
make_shared<MagicVariableDeclaration>("tx", make_shared<MagicType>(MagicType::Kind::Transaction)),
make_shared<MagicVariableDeclaration>("type", make_shared<FunctionType>(
strings{"address"} /* accepts any contract type, handled by the type checker */,
strings{} /* returns a MagicType, handled by the type checker */,
FunctionType::Kind::MetaType,
false,
StateMutability::Pure
)),
})
inline vector<shared_ptr<MagicVariableDeclaration const>> constructMagicVariables()
{
static auto const magicVarDecl = [](string const& _name, Type const* _type) {
return make_shared<MagicVariableDeclaration>(_name, _type);
};
return {
magicVarDecl("abi", TypeProvider::magicType(MagicType::Kind::ABI)),
magicVarDecl("addmod", TypeProvider::functionType(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Kind::AddMod, false, StateMutability::Pure)),
magicVarDecl("assert", TypeProvider::functionType(strings{"bool"}, strings{}, FunctionType::Kind::Assert, false, StateMutability::Pure)),
magicVarDecl("block", TypeProvider::magicType(MagicType::Kind::Block)),
magicVarDecl("blockhash", TypeProvider::functionType(strings{"uint256"}, strings{"bytes32"}, FunctionType::Kind::BlockHash, false, StateMutability::View)),
magicVarDecl("ecrecover", TypeProvider::functionType(strings{"bytes32", "uint8", "bytes32", "bytes32"}, strings{"address"}, FunctionType::Kind::ECRecover, false, StateMutability::Pure)),
magicVarDecl("gasleft", TypeProvider::functionType(strings(), strings{"uint256"}, FunctionType::Kind::GasLeft, false, StateMutability::View)),
magicVarDecl("keccak256", TypeProvider::functionType(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::KECCAK256, false, StateMutability::Pure)),
magicVarDecl("log0", TypeProvider::functionType(strings{"bytes32"}, strings{}, FunctionType::Kind::Log0)),
magicVarDecl("log1", TypeProvider::functionType(strings{"bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log1)),
magicVarDecl("log2", TypeProvider::functionType(strings{"bytes32", "bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log2)),
magicVarDecl("log3", TypeProvider::functionType(strings{"bytes32", "bytes32", "bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log3)),
magicVarDecl("log4", TypeProvider::functionType(strings{"bytes32", "bytes32", "bytes32", "bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log4)),
magicVarDecl("msg", TypeProvider::magicType(MagicType::Kind::Message)),
magicVarDecl("mulmod", TypeProvider::functionType(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Kind::MulMod, false, StateMutability::Pure)),
magicVarDecl("now", TypeProvider::uint256()),
magicVarDecl("require", TypeProvider::functionType(strings{"bool"}, strings{}, FunctionType::Kind::Require, false, StateMutability::Pure)),
magicVarDecl("require", TypeProvider::functionType(strings{"bool", "string memory"}, strings{}, FunctionType::Kind::Require, false, StateMutability::Pure)),
magicVarDecl("revert", TypeProvider::functionType(strings(), strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)),
magicVarDecl("revert", TypeProvider::functionType(strings{"string memory"}, strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)),
magicVarDecl("ripemd160", TypeProvider::functionType(strings{"bytes memory"}, strings{"bytes20"}, FunctionType::Kind::RIPEMD160, false, StateMutability::Pure)),
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{} /* returns a MagicType, handled by the type checker */,
FunctionType::Kind::MetaType,
false,
StateMutability::Pure
)),
};
}
GlobalContext::GlobalContext(): m_magicVariables{constructMagicVariables()}
{
}
@ -90,7 +99,7 @@ vector<Declaration const*> GlobalContext::declarations() const
MagicVariableDeclaration const* GlobalContext::currentThis() const
{
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();
}
@ -98,7 +107,7 @@ MagicVariableDeclaration const* GlobalContext::currentThis() const
MagicVariableDeclaration const* GlobalContext::currentSuper() const
{
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();
}

View File

@ -228,7 +228,7 @@ vector<Declaration const*> NameAndTypeResolver::cleanedDeclarations(
uniqueFunctions.end(),
[&](Declaration const* d)
{
shared_ptr<FunctionType const> newFunctionType { d->functionType(false) };
FunctionType const* newFunctionType = d->functionType(false);
if (!newFunctionType)
newFunctionType = d->functionType(true);
return newFunctionType && functionType->hasEqualParameterTypes(*newFunctionType);

View File

@ -24,6 +24,7 @@
#include <libsolidity/analysis/NameAndTypeResolver.h>
#include <libsolidity/analysis/ConstantEvaluator.h>
#include <libsolidity/ast/AST.h>
#include <libsolidity/ast/TypeProvider.h>
#include <libyul/AsmAnalysis.h>
#include <libyul/AsmAnalysisInfo.h>
@ -120,7 +121,7 @@ bool ReferencesResolver::visit(ElementaryTypeName const& _typeName)
{
if (!_typeName.annotation().type)
{
_typeName.annotation().type = Type::fromElementaryTypeName(_typeName.typeName());
_typeName.annotation().type = TypeProvider::fromElementaryTypeName(_typeName.typeName());
if (_typeName.stateMutability().is_initialized())
{
// for non-address types this was already caught by the parser
@ -128,8 +129,10 @@ bool ReferencesResolver::visit(ElementaryTypeName const& _typeName)
switch(*_typeName.stateMutability())
{
case StateMutability::Payable:
_typeName.annotation().type = TypeProvider::payableAddressType();
break;
case StateMutability::NonPayable:
_typeName.annotation().type = make_shared<AddressType>(*_typeName.stateMutability());
_typeName.annotation().type = TypeProvider::addressType();
break;
default:
m_errorReporter.typeError(
@ -179,14 +182,14 @@ void ReferencesResolver::endVisit(UserDefinedTypeName const& _typeName)
_typeName.annotation().referencedDeclaration = 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))
_typeName.annotation().type = make_shared<EnumType>(*enumDef);
_typeName.annotation().type = TypeProvider::enumType(*enumDef);
else if (ContractDefinition const* contract = dynamic_cast<ContractDefinition const*>(declaration))
_typeName.annotation().type = make_shared<ContractType>(*contract);
_typeName.annotation().type = TypeProvider::contractType(*contract);
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.");
}
}
@ -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)
@ -231,7 +234,7 @@ void ReferencesResolver::endVisit(Mapping const& _typeName)
keyType = ReferenceType::copyForLocationIfReference(DataLocation::Memory, keyType);
// Convert value type to storage reference.
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)
@ -249,7 +252,7 @@ void ReferencesResolver::endVisit(ArrayTypeName const& _typeName)
TypePointer& lengthTypeGeneric = length->annotation().type;
if (!lengthTypeGeneric)
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())
fatalTypeError(length->location(), "Invalid array length, expected integer literal or constant expression.");
else if (lengthType->isZero())
@ -259,10 +262,10 @@ void ReferencesResolver::endVisit(ArrayTypeName const& _typeName)
else if (lengthType->isNegative())
fatalTypeError(length->location(), "Array with negative length specified.");
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
_typeName.annotation().type = make_shared<ArrayType>(DataLocation::Storage, baseType);
_typeName.annotation().type = TypeProvider::arrayType(DataLocation::Storage, baseType);
}
bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly)
@ -436,10 +439,10 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
}
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();
type = ref->copyForLocation(typeLoc, isPointer);
type = TypeProvider::withLocation(ref, typeLoc, isPointer);
}
_variable.annotation().type = type;

View File

@ -190,7 +190,7 @@ bool StaticAnalyzer::visit(ExpressionStatement const& _statement)
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")
m_errorReporter.typeError(
@ -217,7 +217,7 @@ bool StaticAnalyzer::visit(MemberAccess const& _memberAccess)
}
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)
m_errorReporter.typeError(
_memberAccess.location(),
@ -278,7 +278,7 @@ bool StaticAnalyzer::visit(BinaryOperation const& _operation)
_operation.rightExpression().annotation().isPure &&
(_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())
))
if (rhs->isZero())
@ -294,13 +294,13 @@ bool StaticAnalyzer::visit(FunctionCall const& _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, "");
if (functionType->kind() == FunctionType::Kind::AddMod || functionType->kind() == FunctionType::Kind::MulMod)
{
solAssert(_functionCall.arguments().size() == 3, "");
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])
))
if (lastArg->isZero())

View File

@ -22,6 +22,7 @@
#include <libsolidity/analysis/TypeChecker.h>
#include <libsolidity/ast/AST.h>
#include <libsolidity/ast/TypeProvider.h>
#include <libyul/AsmAnalysis.h>
#include <libyul/AsmAnalysisInfo.h>
@ -107,7 +108,7 @@ void TypeChecker::checkDoubleStorageAssignment(Assignment const& _assignment)
size_t toStorageCopies = 0;
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())
continue;
toStorageCopies++;
@ -137,7 +138,7 @@ TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall c
if (arguments.size() >= 1)
{
BoolResult result = type(*arguments.front())->isImplicitlyConvertibleTo(ArrayType::bytesMemory());
BoolResult result = type(*arguments.front())->isImplicitlyConvertibleTo(*TypeProvider::bytesMemoryType());
if (!result)
m_errorReporter.typeErrorConcatenateDescriptions(
@ -169,17 +170,17 @@ TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall c
for (auto const& typeArgument: tupleExpression->components())
{
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();
solAssert(actualType, "");
// We force memory because the parser currently cannot handle
// data locations. Furthermore, storage can be a little dangerous and
// 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.
if (actualType->category() == Type::Category::Address)
actualType = make_shared<AddressType>(StateMutability::Payable);
actualType = TypeProvider::payableAddressType();
solAssert(
!actualType->dataStoredIn(DataLocation::CallData) &&
!actualType->dataStoredIn(DataLocation::Storage),
@ -195,7 +196,7 @@ TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall c
else
{
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;
@ -303,12 +304,12 @@ bool TypeChecker::visit(StructDefinition const& _struct)
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))
{
if (arrayType->isDynamicallySized())
break;
memberType = arrayType->baseType().get();
memberType = arrayType->baseType();
}
if (auto structType = dynamic_cast<StructType const*>(memberType))
if (_cycleDetector.run(structType->structDefinition()))
@ -359,7 +360,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
{
auto iType = type(var)->interfaceType(isLibraryFunction);
if (!iType.get())
if (!iType)
{
solAssert(!iType.message().empty(), "Expected detailed error message!");
m_errorReporter.fatalTypeError(var.location(), iType.message());
@ -455,7 +456,7 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
if (!_variable.type()->isValueType())
{
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();
if (!allowed)
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())
{
case Type::Category::Array:
if (auto arrayType = dynamic_cast<ArrayType const*>(varType.get()))
if (auto arrayType = dynamic_cast<ArrayType const*>(varType))
if (
((arrayType->location() == DataLocation::Memory) ||
(arrayType->location() == DataLocation::CallData)) &&
@ -584,7 +585,7 @@ bool TypeChecker::visit(EventDefinition const& _eventDef)
numIndexed++;
if (!type(*var)->canLiveOutsideStorage())
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.");
if (
!_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);
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)
@ -716,7 +717,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
bool TypeChecker::visit(IfStatement const& _ifStatement)
{
expectType(_ifStatement.condition(), BoolType());
expectType(_ifStatement.condition(), *TypeProvider::boolType());
_ifStatement.trueStatement().accept(*this);
if (_ifStatement.falseStatement())
_ifStatement.falseStatement()->accept(*this);
@ -725,7 +726,7 @@ bool TypeChecker::visit(IfStatement const& _ifStatement)
bool TypeChecker::visit(WhileStatement const& _whileStatement)
{
expectType(_whileStatement.condition(), BoolType());
expectType(_whileStatement.condition(), *TypeProvider::boolType());
_whileStatement.body().accept(*this);
return false;
}
@ -735,7 +736,7 @@ bool TypeChecker::visit(ForStatement const& _forStatement)
if (_forStatement.initializationExpression())
_forStatement.initializationExpression()->accept(*this);
if (_forStatement.condition())
expectType(*_forStatement.condition(), BoolType());
expectType(*_forStatement.condition(), *TypeProvider::boolType());
if (_forStatement.loopExpression())
_forStatement.loopExpression()->accept(*this);
_forStatement.body().accept(*this);
@ -759,7 +760,7 @@ void TypeChecker::endVisit(Return const& _return)
TypePointers returnTypes;
for (auto const& var: params->parameters())
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())
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)
return false;
if (auto functionType = dynamic_cast<FunctionType const*>(decl->annotation().type.get()))
if (auto functionType = dynamic_cast<FunctionType const*>(decl->annotation().type))
if (
functionType->kind() != FunctionType::Kind::Internal &&
functionType->kind() != FunctionType::Kind::External
@ -878,7 +879,7 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
if (!varDecl.annotation().type)
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))
{
@ -888,7 +889,7 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
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(
varDecl.location(),
"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);
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();
else
valueTypes = TypePointers{type(*_statement.initialValue())};
@ -950,13 +951,13 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
else
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.");
else if (valueComponentType->category() == Type::Category::RationalNumber)
{
string typeName = var.annotation().type->toString(true);
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();
bool isSigned = type->isSigned();
@ -974,7 +975,7 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
extension = ", which can hold values between " + minValue + " and " + maxValue;
}
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);
@ -1054,7 +1055,7 @@ void TypeChecker::endVisit(ExpressionStatement const& _statement)
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();
if (
@ -1072,7 +1073,7 @@ void TypeChecker::endVisit(ExpressionStatement const& _statement)
bool TypeChecker::visit(Conditional const& _conditional)
{
expectType(_conditional.condition(), BoolType());
expectType(_conditional.condition(), *TypeProvider::boolType());
_conditional.trueExpression().accept(*this);
_conditional.falseExpression().accept(*this);
@ -1080,7 +1081,7 @@ bool TypeChecker::visit(Conditional const& _conditional)
TypePointer trueType = type(_conditional.trueExpression())->mobileType();
TypePointer falseType = type(_conditional.falseExpression())->mobileType();
TypePointer commonType;
TypePointer commonType = nullptr;
if (!trueType)
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))
{
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(
tupleExpression->components().size() == types.size() || m_errorReporter.hasErrors(),
@ -1168,7 +1169,7 @@ bool TypeChecker::visit(Assignment const& _assignment)
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)
m_errorReporter.typeError(
@ -1176,12 +1177,12 @@ bool TypeChecker::visit(Assignment const& _assignment)
"Compound assignment is not allowed for tuple types."
);
// 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 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);
}
else if (_assignment.assignmentOperator() == Token::Assign)
@ -1228,14 +1229,14 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
if (components.size() == 1)
_tuple.annotation().type = type(*components[0]);
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.
_tuple.annotation().isLValue = true;
}
else
{
bool isPure = true;
TypePointer inlineArrayType;
TypePointer inlineArrayType = nullptr;
for (size_t i = 0; i < components.size(); ++i)
{
@ -1285,14 +1286,14 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
else if (!inlineArrayType->canLiveOutsideStorage())
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
{
if (components.size() == 1)
_tuple.annotation().type = type(*components[0]);
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().type =
TokenTraits::isCompareOp(_operation.getOperator()) ?
make_shared<BoolType>() :
TypeProvider::boolType() :
commonType;
_operation.annotation().isPure =
_operation.leftExpression().annotation().isPure &&
@ -1401,20 +1402,20 @@ TypePointer TypeChecker::typeCheckTypeConversionAndRetrieveReturnType(
);
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
// type with a different data location.
// (data location cannot yet be specified for type conversions)
DataLocation dataLoc = DataLocation::Memory;
if (auto argRefType = dynamic_cast<ReferenceType const*>(argType.get()))
if (auto argRefType = dynamic_cast<ReferenceType const*>(argType))
dataLoc = argRefType->location();
if (auto type = dynamic_cast<ReferenceType const*>(resultType.get()))
resultType = type->copyForLocation(dataLoc, type->isPointer());
if (auto type = dynamic_cast<ReferenceType const*>(resultType))
resultType = TypeProvider::withLocation(type, dataLoc, type->isPointer());
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(
argArrayType->location() != DataLocation::Storage ||
@ -1436,9 +1437,9 @@ TypePointer TypeChecker::typeCheckTypeConversionAndRetrieveReturnType(
argType->category() == Type::Category::Address
)
{
solAssert(dynamic_cast<ContractType const*>(resultType.get())->isPayable(), "");
solAssert(dynamic_cast<ContractType const*>(resultType)->isPayable(), "");
solAssert(
dynamic_cast<AddressType const*>(argType.get())->stateMutability() <
dynamic_cast<AddressType const*>(argType)->stateMutability() <
StateMutability::Payable,
""
);
@ -1474,10 +1475,8 @@ TypePointer TypeChecker::typeCheckTypeConversionAndRetrieveReturnType(
}
if (resultType->category() == Type::Category::Address)
{
bool const payable = argType->isExplicitlyConvertibleTo(AddressType::addressPayable());
resultType = make_shared<AddressType>(
payable ? StateMutability::Payable : StateMutability::NonPayable
);
bool const payable = argType->isExplicitlyConvertibleTo(*TypeProvider::payableAddressType());
resultType = payable ? TypeProvider::payableAddressType() : TypeProvider::addressType();
}
}
return resultType;
@ -1829,17 +1828,17 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
_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
FunctionCallAnnotation& funcCallAnno = _functionCall.annotation();
FunctionTypePointer functionType;
FunctionTypePointer functionType = nullptr;
// Determine and assign function call kind, purity and function type for this FunctionCall node
switch (expressionType->category())
{
case Type::Category::Function:
functionType = dynamic_pointer_cast<FunctionType const>(expressionType);
functionType = dynamic_cast<FunctionType const*>(expressionType);
funcCallAnno.kind = FunctionCallKind::FunctionCall;
// 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 ?
move(returnTypes.front()) :
make_shared<TupleType>(move(returnTypes));
TypeProvider::tupleType(move(returnTypes));
break;
}
@ -1936,7 +1935,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
// for non-callables, ensure error reported and annotate node to void function
solAssert(m_errorReporter.hasErrors(), "");
funcCallAnno.kind = FunctionCallKind::FunctionCall;
funcCallAnno.type = make_shared<TupleType>();
funcCallAnno.type = TypeProvider::emptyTupleType();
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."
);
type = ReferenceType::copyForLocationIfReference(DataLocation::Memory, type);
_newExpression.annotation().type = make_shared<FunctionType>(
TypePointers{make_shared<IntegerType>(256)},
_newExpression.annotation().type = TypeProvider::functionType(
TypePointers{TypeProvider::uint256()},
TypePointers{type},
strings(1, ""),
strings(1, ""),
@ -2059,7 +2058,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
string errorMsg = "Member \"" + memberName + "\" not found or not visible "
"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();
@ -2079,7 +2078,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
}
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)
{
Identifier const* var = dynamic_cast<Identifier const*>(&_memberAccess.expression());
@ -2088,7 +2087,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
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.
if (memberName == "send" || memberName == "transfer")
@ -2118,14 +2117,14 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
annotation.referencedDeclaration = possibleMembers.front().declaration;
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(
!funType->bound() || exprType->isImplicitlyConvertibleTo(*funType->selfType()),
"Function \"" + memberName + "\" cannot be called on an object of type " +
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);
else if (exprType->category() == Type::Category::Array)
{
@ -2138,18 +2137,18 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
}
else if (exprType->category() == Type::Category::FixedBytes)
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();
}
// 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.
if (auto tt = dynamic_cast<TypeType const*>(exprType.get()))
if (auto tt = dynamic_cast<TypeType const*>(exprType))
if (tt->actualType()->category() == Type::Category::Enum)
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)
annotation.isPure = true;
@ -2178,7 +2177,7 @@ bool TypeChecker::visit(IndexAccess const& _access)
{
_access.baseExpression().accept(*this);
TypePointer baseType = type(_access.baseExpression());
TypePointer resultType;
TypePointer resultType = nullptr;
bool isLValue = false;
bool isPure = _access.baseExpression().annotation().isPure;
Expression const* index = _access.indexExpression();
@ -2196,9 +2195,9 @@ bool TypeChecker::visit(IndexAccess const& _access)
}
else
{
expectType(*index, IntegerType::uint256());
expectType(*index, *TypeProvider::uint256());
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(), "");
if (!actualType.isDynamicallySized() && actualType.length() <= numberType->literalValue(nullptr))
@ -2223,16 +2222,16 @@ bool TypeChecker::visit(IndexAccess const& _access)
case Type::Category::TypeType:
{
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.");
if (!index)
resultType = make_shared<TypeType>(make_shared<ArrayType>(DataLocation::Memory, typeType.actualType()));
resultType = TypeProvider::typeType(TypeProvider::arrayType(DataLocation::Memory, typeType.actualType()));
else
{
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);
else
m_errorReporter.fatalTypeError(index->location(), "Integer constant expected.");
@ -2240,7 +2239,7 @@ bool TypeChecker::visit(IndexAccess const& _access)
else
solAssert(m_errorReporter.hasErrors(), "Expected errors as expectType returned false");
resultType = make_shared<TypeType>(make_shared<ArrayType>(
resultType = TypeProvider::typeType(TypeProvider::arrayType(
DataLocation::Memory,
typeType.actualType(),
length
@ -2255,13 +2254,13 @@ bool TypeChecker::visit(IndexAccess const& _access)
m_errorReporter.typeError(_access.location(), "Index expression cannot be omitted.");
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.");
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))
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
break;
}
@ -2271,7 +2270,7 @@ bool TypeChecker::visit(IndexAccess const& _access)
"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;
if (index && !index->annotation().isPure)
isPure = false;
@ -2337,16 +2336,16 @@ bool TypeChecker::visit(Identifier const& _identifier)
annotation.isPure = annotation.isConstant = variableDeclaration->isConstant();
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;
}
else if (dynamic_cast<TypeType const*>(annotation.type.get()))
else if (dynamic_cast<TypeType const*>(annotation.type))
annotation.isPure = true;
// Check for deprecated function names.
// 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)
m_errorReporter.typeError(
@ -2365,7 +2364,7 @@ bool TypeChecker::visit(Identifier const& _identifier)
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;
}
@ -2374,7 +2373,7 @@ void TypeChecker::endVisit(Literal const& _literal)
if (_literal.looksLikeAddress())
{
// 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;
if (_literal.valueWithoutUnderscores().length() != 42) // "0x" + 40 hex digits
@ -2413,7 +2412,7 @@ void TypeChecker::endVisit(Literal const& _literal)
);
if (!_literal.annotation().type)
_literal.annotation().type = Type::forLiteral(_literal);
_literal.annotation().type = TypeProvider::forLiteral(_literal);
if (!_literal.annotation().type)
m_errorReporter.fatalTypeError(_literal.location(), "Invalid literal value.");
@ -2460,7 +2459,7 @@ bool TypeChecker::expectType(Expression const& _expression, Type const& _expecte
_expectedType.toString();
if (
type(_expression)->category() == Type::Category::RationalNumber &&
dynamic_pointer_cast<RationalNumberType const>(type(_expression))->isFractional() &&
dynamic_cast<RationalNumberType const*>(type(_expression))->isFractional() &&
type(_expression)->mobileType()
)
{

View File

@ -24,6 +24,7 @@
#include <libsolidity/ast/ASTVisitor.h>
#include <libsolidity/ast/AST_accept.h>
#include <libsolidity/ast/TypeProvider.h>
#include <libdevcore/Keccak256.h>
#include <boost/algorithm/string.hpp>
@ -105,7 +106,7 @@ ImportAnnotation& ImportDirective::annotation() const
TypePointer ImportDirective::type() const
{
solAssert(!!annotation().sourceUnit, "");
return make_shared<ModuleType>(*annotation().sourceUnit);
return TypeProvider::moduleType(*annotation().sourceUnit);
}
map<FixedHash<4>, FunctionTypePointer> ContractDefinition::interfaceFunctions() const
@ -188,10 +189,10 @@ vector<pair<FixedHash<4>, FunctionTypePointer>> const& ContractDefinition::inter
vector<FunctionTypePointer> functions;
for (FunctionDefinition const* f: contract->definedFunctions())
if (f->isPartOfExternalInterface())
functions.push_back(make_shared<FunctionType>(*f, false));
functions.push_back(TypeProvider::functionType(*f, false));
for (VariableDeclaration const* v: contract->stateVariables())
if (v->isPartOfExternalInterface())
functions.push_back(make_shared<FunctionType>(*v));
functions.push_back(TypeProvider::functionType(*v));
for (FunctionTypePointer const& fun: functions)
{
if (!fun->interfaceFunctionType())
@ -246,7 +247,7 @@ vector<Declaration const*> const& ContractDefinition::inheritableMembers() const
TypePointer ContractDefinition::type() const
{
return make_shared<TypeType>(make_shared<ContractType>(*this));
return TypeProvider::typeType(TypeProvider::contractType(*this));
}
ContractDefinitionAnnotation& ContractDefinition::annotation() const
@ -265,7 +266,7 @@ TypeNameAnnotation& TypeName::annotation() 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
@ -279,12 +280,12 @@ TypePointer EnumValue::type() const
{
auto parentDef = dynamic_cast<EnumDefinition const*>(scope());
solAssert(parentDef, "Enclosing Scope of EnumValue was not set");
return make_shared<EnumType>(*parentDef);
return TypeProvider::enumType(*parentDef);
}
TypePointer EnumDefinition::type() const
{
return make_shared<TypeType>(make_shared<EnumType>(*this));
return TypeProvider::typeType(TypeProvider::enumType(*this));
}
TypeDeclarationAnnotation& EnumDefinition::annotation() const
@ -312,7 +313,7 @@ FunctionTypePointer FunctionDefinition::functionType(bool _internal) const
case Declaration::Visibility::Private:
case Declaration::Visibility::Internal:
case Declaration::Visibility::Public:
return make_shared<FunctionType>(*this, _internal);
return TypeProvider::functionType(*this, _internal);
case Declaration::Visibility::External:
return {};
}
@ -328,7 +329,7 @@ FunctionTypePointer FunctionDefinition::functionType(bool _internal) const
return {};
case Declaration::Visibility::Public:
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
{
solAssert(visibility() != Declaration::Visibility::External, "");
return make_shared<FunctionType>(*this);
return TypeProvider::functionType(*this);
}
string FunctionDefinition::externalSignature() const
{
return FunctionType(*this).externalSignature();
return TypeProvider::functionType(*this)->externalSignature();
}
FunctionDefinitionAnnotation& FunctionDefinition::annotation() const
@ -356,7 +357,7 @@ FunctionDefinitionAnnotation& FunctionDefinition::annotation() const
TypePointer ModifierDefinition::type() const
{
return make_shared<ModifierType>(*this);
return TypeProvider::modifierType(*this);
}
ModifierDefinitionAnnotation& ModifierDefinition::annotation() const
@ -368,15 +369,15 @@ ModifierDefinitionAnnotation& ModifierDefinition::annotation() const
TypePointer EventDefinition::type() const
{
return make_shared<FunctionType>(*this);
return TypeProvider::functionType(*this);
}
FunctionTypePointer EventDefinition::functionType(bool _internal) const
{
if (_internal)
return make_shared<FunctionType>(*this);
return TypeProvider::functionType(*this);
else
return {};
return nullptr;
}
EventDefinitionAnnotation& EventDefinition::annotation() const
@ -508,8 +509,8 @@ bool VariableDeclaration::hasReferenceOrMappingType() const
{
solAssert(typeName(), "");
solAssert(typeName()->annotation().type, "Can only be called after reference resolution");
TypePointer const& type = typeName()->annotation().type;
return type->category() == Type::Category::Mapping || dynamic_cast<ReferenceType const*>(type.get());
Type const* type = typeName()->annotation().type;
return type->category() == Type::Category::Mapping || dynamic_cast<ReferenceType const*>(type);
}
set<VariableDeclaration::Location> VariableDeclaration::allowedDataLocations() const
@ -557,21 +558,21 @@ TypePointer VariableDeclaration::type() const
FunctionTypePointer VariableDeclaration::functionType(bool _internal) const
{
if (_internal)
return {};
return nullptr;
switch (visibility())
{
case Declaration::Visibility::Default:
solAssert(false, "visibility() should not return Default");
case Declaration::Visibility::Private:
case Declaration::Visibility::Internal:
return {};
return nullptr;
case Declaration::Visibility::Public:
case Declaration::Visibility::External:
return make_shared<FunctionType>(*this);
return TypeProvider::functionType(*this);
}
// To make the compiler happy
return {};
return nullptr;
}
VariableDeclarationAnnotation& VariableDeclaration::annotation() const

View File

@ -848,8 +848,9 @@ private:
class MagicVariableDeclaration: public Declaration
{
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) {}
void accept(ASTVisitor&) override
{
solAssert(false, "MagicVariableDeclaration used inside real AST.");
@ -859,15 +860,15 @@ public:
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, "");
return std::dynamic_pointer_cast<FunctionType const>(m_type);
return dynamic_cast<FunctionType const*>(m_type);
}
TypePointer type() const override { return m_type; }
private:
std::shared_ptr<Type const> m_type;
Type const* m_type;
};
/// Types

View File

@ -45,7 +45,7 @@ namespace solidity
{
class Type;
using TypePointer = std::shared_ptr<Type const>;
using TypePointer = Type const*;
struct ASTAnnotation
{
@ -122,7 +122,7 @@ struct ModifierDefinitionAnnotation: ASTAnnotation, DocumentedAnnotation
struct VariableDeclarationAnnotation: ASTAnnotation
{
/// Type of variable (type of identifier referencing this variable).
TypePointer type;
TypePointer type = nullptr;
};
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.
/// Set during reference resolution stage.
TypePointer type;
TypePointer type = nullptr;
};
struct UserDefinedTypeNameAnnotation: TypeNameAnnotation
@ -170,7 +170,7 @@ struct UserDefinedTypeNameAnnotation: TypeNameAnnotation
struct ExpressionAnnotation: ASTAnnotation
{
/// Inferred type of the expression.
TypePointer type;
TypePointer type = nullptr;
/// Whether the expression is a constant variable
bool isConstant = false;
/// 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
/// e.g. for comparisons is bool).
TypePointer commonType;
TypePointer commonType = nullptr;
};
enum class FunctionCallKind

View File

@ -57,7 +57,7 @@ class Type;
struct FuncCallArguments
{
/// Types of arguments
std::vector<std::shared_ptr<Type const>> types;
std::vector<Type const*> types;
/// Names of the arguments if given, otherwise unset
std::vector<ASTPointer<ASTString>> names;

View 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);
}

View 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

View File

@ -32,7 +32,6 @@
#include <libdevcore/Result.h>
#include <boost/optional.hpp>
#include <boost/noncopyable.hpp>
#include <boost/rational.hpp>
#include <map>
@ -45,10 +44,11 @@ namespace dev
namespace solidity
{
class TypeProvider;
class Type; // forward
class FunctionType; // forward
using TypePointer = std::shared_ptr<Type const>;
using FunctionTypePointer = std::shared_ptr<FunctionType const>;
using TypePointer = Type const*;
using FunctionTypePointer = FunctionType const*;
using TypePointers = std::vector<TypePointer>;
using rational = boost::rational<dev::bigint>;
using TypeResult = Result<TypePointer>;
@ -94,7 +94,7 @@ class MemberList
public:
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),
type(_type),
declaration(_declaration)
@ -102,17 +102,18 @@ public:
}
std::string name;
TypePointer type;
Type const* type;
Declaration const* declaration = nullptr;
};
using MemberMap = std::vector<Member>;
explicit MemberList(MemberMap const& _members): m_memberTypes(_members) {}
void combine(MemberList const& _other);
TypePointer memberType(std::string const& _name) const
{
TypePointer type;
TypePointer type = nullptr;
for (auto const& it: m_memberTypes)
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.
*/
class Type: private boost::noncopyable, public std::enable_shared_from_this<Type>
class Type
{
public:
Type() = default;
Type(Type const&) = delete;
Type(Type&&) = delete;
Type& operator=(Type const&) = delete;
Type& operator=(Type&&) = delete;
virtual ~Type() = default;
enum class Category
{
Address, Integer, RationalNumber, StringLiteral, Bool, FixedPoint, Array,
@ -160,20 +167,8 @@ public:
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
static TypePointer commonType(TypePointer const& _a, TypePointer const& _b);
static TypePointer commonType(Type const* _a, Type const* _b);
virtual Category category() const = 0;
/// @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
/// this is not possible.
/// 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
/// this is not possible.
/// 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(); }
@ -258,14 +253,14 @@ public:
/// This returns the corresponding IntegerType or FixedPointType for RationalNumberType
/// and the pointer type for storage reference types.
/// 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
/// given location.
virtual bool dataStoredIn(DataLocation) const { return false; }
/// @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)
/// 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;
}
@ -298,7 +293,7 @@ public:
/// @returns a (simpler) type that is encoded in the same way for external function calls.
/// This for example returns address for contract types.
/// 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
/// when used for e.g. abi.encode(...) or the empty pointer if the object
/// cannot be encoded.
@ -311,7 +306,10 @@ public:
/// 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
/// 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:
/// @returns a member list containing all members added to this type by `using for` directives.
@ -335,18 +333,15 @@ protected:
class AddressType: public Type
{
public:
static AddressType& address() { static std::shared_ptr<AddressType> addr(std::make_shared<AddressType>(StateMutability::NonPayable)); return *addr; }
static AddressType& addressPayable() { static std::shared_ptr<AddressType> addr(std::make_shared<AddressType>(StateMutability::Payable)); return *addr; }
explicit AddressType(StateMutability _stateMutability);
Category category() const override { return Category::Address; }
explicit AddressType(StateMutability _stateMutability);
std::string richIdentifier() const override;
BoolResult isImplicitlyConvertibleTo(Type const& _other) const override;
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) 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;
@ -362,8 +357,8 @@ public:
u256 literalValue(Literal const* _literal) const override;
TypePointer encodingType() const override { return shared_from_this(); }
TypeResult interfaceType(bool) const override { return shared_from_this(); }
TypePointer encodingType() const override { return this; }
TypeResult interfaceType(bool) const override { return this; }
StateMutability stateMutability(void) const { return m_stateMutability; }
@ -382,17 +377,15 @@ public:
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; }
explicit IntegerType(unsigned _bits, Modifier _modifier = Modifier::Unsigned);
std::string richIdentifier() const override;
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) 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;
@ -403,8 +396,8 @@ public:
std::string toString(bool _short) const override;
TypePointer encodingType() const override { return shared_from_this(); }
TypeResult interfaceType(bool) const override { return shared_from_this(); }
TypePointer encodingType() const override { return this; }
TypeResult interfaceType(bool) const override { return this; }
unsigned numBits() const { return m_bits; }
bool isSigned() const { return m_modifier == Modifier::Signed; }
@ -413,8 +406,8 @@ public:
bigint maxValue() const;
private:
unsigned m_bits;
Modifier m_modifier;
unsigned const m_bits;
Modifier const m_modifier;
};
/**
@ -427,15 +420,15 @@ public:
{
Unsigned, Signed
};
Category category() const override { return Category::FixedPoint; }
explicit FixedPointType(unsigned _totalBits, unsigned _fractionalDigits, Modifier _modifier = Modifier::Unsigned);
Category category() const override { return Category::FixedPoint; }
std::string richIdentifier() const override;
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) 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;
@ -446,8 +439,8 @@ public:
std::string toString(bool _short) const override;
TypePointer encodingType() const override { return shared_from_this(); }
TypeResult interfaceType(bool) const override { return shared_from_this(); }
TypePointer encodingType() const override { return this; }
TypeResult interfaceType(bool) const override { return this; }
/// Number of bits used for this type in total.
unsigned numBits() const { return m_totalBits; }
@ -462,7 +455,7 @@ public:
bigint minIntegerValue() const;
/// @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:
unsigned m_totalBits;
@ -478,18 +471,16 @@ private:
class RationalNumberType: public Type
{
public:
explicit RationalNumberType(rational const& _value, Type const* _compatibleBytesType = nullptr):
m_value(_value), m_compatibleBytesType(_compatibleBytesType)
{}
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 isExplicitlyConvertibleTo(Type const& _convertTo) 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;
bool operator==(Type const& _other) const override;
@ -502,11 +493,11 @@ public:
TypePointer mobileType() const override;
/// @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,
/// 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.
std::shared_ptr<FixedPointType const> fixedPointType() const;
FixedPointType const* fixedPointType() const;
/// @returns true if the value is not an integer.
bool isFractional() const { return m_value.denominator() != 1; }
@ -517,6 +508,9 @@ public:
/// @returns true if the value is zero.
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:
rational m_value;
@ -524,9 +518,6 @@ private:
/// Empty for all rationals that are not directly parsed from hex literals.
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.
static std::tuple<bool, rational> parseRational(std::string const& _value);
@ -541,14 +532,15 @@ private:
class StringLiteralType: public Type
{
public:
explicit StringLiteralType(Literal const& _literal);
explicit StringLiteralType(std::string const& _value);
Category category() const override { return Category::StringLiteral; }
explicit StringLiteralType(Literal const& _literal);
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;
@ -575,16 +567,16 @@ private:
class FixedBytesType: public Type
{
public:
Category category() const override { return Category::FixedBytes; }
explicit FixedBytesType(unsigned _bytes);
Category category() const override { return Category::FixedBytes; }
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
std::string richIdentifier() const override;
bool operator==(Type const& _other) 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 storageBytes() const override { return m_bytes; }
@ -593,8 +585,8 @@ public:
std::string toString(bool) const override { return "bytes" + dev::toString(m_bytes); }
MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
TypePointer encodingType() const override { return shared_from_this(); }
TypeResult interfaceType(bool) const override { return shared_from_this(); }
TypePointer encodingType() const override { return this; }
TypeResult interfaceType(bool) const override { return this; }
unsigned numBytes() const { return m_bytes; }
@ -611,7 +603,7 @@ public:
Category category() const override { return Category::Bool; }
std::string richIdentifier() const override { return "t_bool"; }
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 storageBytes() const override { return 1; }
@ -620,8 +612,8 @@ public:
std::string toString(bool) const override { return "bool"; }
u256 literalValue(Literal const* _literal) const override;
TypePointer encodingType() const override { return shared_from_this(); }
TypeResult interfaceType(bool) const override { return shared_from_this(); }
TypePointer encodingType() const override { return this; }
TypeResult interfaceType(bool) const override { return this; }
};
/**
@ -630,22 +622,24 @@ public:
*/
class ReferenceType: public Type
{
public:
protected:
explicit ReferenceType(DataLocation _location): m_location(_location) {}
public:
DataLocation location() const { return m_location; }
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; }
/// @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.
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 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)
/// if _type is a reference type and an unmodified copy of _type otherwise.
/// 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:
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.
std::string stringForReferencePart() const;
/// @returns the suffix computed from the reference part to be used by identifier();
@ -686,32 +682,26 @@ protected:
class ArrayType: public ReferenceType
{
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.
explicit ArrayType(DataLocation _location, bool _isString = false):
ReferenceType(_location),
m_arrayKind(_isString ? ArrayKind::String : ArrayKind::Bytes),
m_baseType(std::make_shared<FixedBytesType>(1))
{
}
explicit ArrayType(DataLocation _location, bool _isString = false);
/// Constructor for a dynamically sized array type ("type[]")
ArrayType(DataLocation _location, TypePointer const& _baseType):
ArrayType(DataLocation _location, Type const* _baseType):
ReferenceType(_location),
m_baseType(copyForLocationIfReference(_baseType))
{
}
/// 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),
m_baseType(copyForLocationIfReference(_baseType)),
m_hasDynamicLength(false),
m_length(_length)
{}
Category category() const override { return Category::Array; }
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
std::string richIdentifier() const override;
@ -737,11 +727,11 @@ public:
bool isByteArray() const { return m_arrayKind != ArrayKind::Ordinary; }
/// @returns true if this is a 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 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.
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.
unsigned storageStride() const { return isByteArray() ? 1 : m_baseType->storageBytes(); }
void clearCache() const override;
private:
/// String is interpreted as a subtype of Bytes.
enum class ArrayKind { Ordinary, Bytes, String };
@ -758,7 +750,7 @@ private:
///< Byte arrays ("bytes") and strings have different semantics from ordinary arrays.
ArrayKind m_arrayKind = ArrayKind::Ordinary;
TypePointer m_baseType;
Type const* m_baseType;
bool m_hasDynamicLength = true;
u256 m_length;
mutable boost::optional<TypeResult> m_interfaceType;
@ -771,9 +763,10 @@ private:
class ContractType: public Type
{
public:
Category category() const override { return Category::Contract; }
explicit ContractType(ContractDefinition const& _contract, bool _super = false):
m_contract(_contract), m_super(_super) {}
Category category() const override { return Category::Contract; }
/// Contracts can be implicitly converted only to base contracts.
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
/// Contracts can only be explicitly converted to address types and base contracts.
@ -795,17 +788,14 @@ public:
std::string canonicalName() const override;
MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
TypePointer encodingType() const override
{
if (isSuper())
return TypePointer{};
return std::make_shared<AddressType>(isPayable() ? StateMutability::Payable : StateMutability::NonPayable);
}
Type const* encodingType() const override;
TypeResult interfaceType(bool _inLibrary) const override
{
if (isSuper())
return TypePointer{};
return _inLibrary ? shared_from_this() : encodingType();
return nullptr;
return _inLibrary ? this : encodingType();
}
/// See documentation of m_super
@ -817,7 +807,7 @@ public:
ContractDefinition const& contractDefinition() const { return m_contract; }
/// 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
/// 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
bool m_super = false;
/// 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
{
public:
Category category() const override { return Category::Struct; }
explicit StructType(StructDefinition const& _struct, DataLocation _location = DataLocation::Storage):
ReferenceType(_location), m_struct(_struct) {}
Category category() const override { return Category::Struct; }
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
std::string richIdentifier() const override;
bool operator==(Type const& _other) const override;
@ -851,10 +842,8 @@ public:
std::string toString(bool _short) const override;
MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
TypePointer encodingType() const override
{
return location() == DataLocation::Storage ? std::make_shared<IntegerType>(256) : shared_from_this();
}
Type const* encodingType() const override;
TypeResult interfaceType(bool _inLibrary) const override;
bool recursive() const
@ -867,14 +856,14 @@ public:
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 signatureInExternalFunction(bool _structsByName) const override;
/// @returns a function that performs the type conversion between a list of struct members
/// 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;
u256 memoryOffsetOfMember(std::string const& _name) const;
@ -886,6 +875,9 @@ public:
TypePointers memoryMemberTypes() const;
/// @returns the set of all members that are removed in the memory version (typically mappings).
std::set<std::string> membersMissingInMemory() const;
void clearCache() const override;
private:
StructDefinition const& m_struct;
// Caches for interfaceType(bool)
@ -900,8 +892,9 @@ private:
class EnumType: public Type
{
public:
Category category() const override { return Category::Enum; }
explicit EnumType(EnumDefinition const& _enum): m_enum(_enum) {}
Category category() const override { return Category::Enum; }
TypeResult unaryOperatorResult(Token _operator) const override;
std::string richIdentifier() const override;
bool operator==(Type const& _other) const override;
@ -917,13 +910,10 @@ public:
bool isValueType() const override { return true; }
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
TypePointer encodingType() const override
{
return std::make_shared<IntegerType>(8 * int(storageBytes()));
}
TypePointer encodingType() 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; }
@ -942,12 +932,14 @@ private:
class TupleType: public Type
{
public:
explicit TupleType(std::vector<TypePointer> _types = {}): m_components(std::move(_types)) {}
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;
std::string richIdentifier() 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;
bool canBeStored() const override { return false; }
u256 storageSize() const override;
@ -956,7 +948,7 @@ public:
bool hasSimpleZeroValueInMemory() const override { return false; }
TypePointer mobileType() const override;
/// 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; }
@ -1017,8 +1009,6 @@ public:
MetaType ///< type(...)
};
Category category() const override { return Category::Function; }
/// Creates the type of a function.
explicit FunctionType(FunctionDefinition const& _function, bool _isInternal = true);
/// 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.
FunctionType(
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;
std::vector<std::string> parameterNames() const;
TypePointers const& returnParameterTypes() const { return m_returnParameterTypes; }
@ -1097,14 +1089,14 @@ public:
TypePointers returnParameterTypesWithoutDynamicTypes() const;
std::vector<std::string> const& returnParameterNames() const { return m_returnParameterNames; }
/// @returns the "self" parameter type for a bound function
TypePointer const& selfType() const;
Type const* selfType() const;
std::string richIdentifier() const override;
bool operator==(Type const& _other) const override;
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) 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 toString(bool _short) const override;
unsigned calldataEncodedSize(bool _padded) const override;
@ -1133,7 +1125,7 @@ public:
/// expression the function is called on.
bool canTakeArguments(
FuncCallArguments const& _arguments,
TypePointer const& _selfType = TypePointer()
Type const* _selfType = nullptr
) const;
/// @returns true if the types of parameters are equal (does not check return parameter types)
@ -1229,27 +1221,25 @@ private:
class MappingType: public Type
{
public:
Category category() const override { return Category::Mapping; }
MappingType(TypePointer const& _keyType, TypePointer const& _valueType):
MappingType(Type const* _keyType, Type const* _valueType):
m_keyType(_keyType), m_valueType(_valueType) {}
Category category() const override { return Category::Mapping; }
std::string richIdentifier() const override;
bool operator==(Type const& _other) const override;
std::string toString(bool _short) const override;
std::string canonicalName() const override;
bool canLiveOutsideStorage() const override { return false; }
TypeResult binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
TypePointer encodingType() const override
{
return std::make_shared<IntegerType>(256);
}
TypeResult binaryOperatorResult(Token, Type const*) const override { return nullptr; }
Type const* encodingType() const override;
TypeResult interfaceType(bool _inLibrary) const override;
bool dataStoredIn(DataLocation _location) const override { return _location == DataLocation::Storage; }
/// Cannot be stored in memory, but just in case.
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
TypePointer const& keyType() const { return m_keyType; }
TypePointer const& valueType() const { return m_valueType; }
Type const* keyType() const { return m_keyType; }
Type const* valueType() const { return m_valueType; }
private:
TypePointer m_keyType;
@ -1264,11 +1254,12 @@ private:
class TypeType: public Type
{
public:
Category category() const override { return Category::TypeType; }
explicit TypeType(TypePointer const& _actualType): m_actualType(_actualType) {}
TypePointer const& actualType() const { return m_actualType; }
explicit TypeType(Type const* _actualType): m_actualType(_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;
bool operator==(Type const& _other) const override;
bool canBeStored() const override { return false; }
@ -1290,10 +1281,11 @@ private:
class ModifierType: public Type
{
public:
Category category() const override { return Category::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; }
u256 storageSize() const override;
bool canLiveOutsideStorage() const override { return false; }
@ -1315,11 +1307,11 @@ private:
class ModuleType: public Type
{
public:
Category category() const override { return Category::Module; }
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;
bool operator==(Type const& _other) const override;
bool canBeStored() const override { return false; }
@ -1347,15 +1339,19 @@ public:
ABI, ///< "abi"
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; }
explicit MagicType(Kind _kind): m_kind(_kind) {}
/// 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;
@ -1376,7 +1372,6 @@ private:
Kind m_kind;
/// Contract type used for contract metadata magic.
TypePointer m_typeArgument;
};
/**
@ -1391,7 +1386,7 @@ public:
std::string richIdentifier() const override { return "t_inaccessible"; }
BoolResult isImplicitlyConvertibleTo(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; }
bool canBeStored() const override { return false; }
bool canLiveOutsideStorage() const override { return false; }
@ -1399,7 +1394,7 @@ public:
unsigned sizeOnStack() const override { return 1; }
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
std::string toString(bool) const override { return "inaccessible dynamic type"; }
TypePointer decodingType() const override { return std::make_shared<IntegerType>(256); }
TypePointer decodingType() const override;
};
}

View File

@ -311,7 +311,7 @@ string ABIFunctions::abiEncodingFunction(
case DataLocation::CallData:
if (
fromArray.isByteArray() ||
*fromArray.baseType() == IntegerType::uint256() ||
*fromArray.baseType() == *TypeProvider::uint256() ||
*fromArray.baseType() == FixedBytesType(32)
)
return abiEncodingFunctionCalldataArrayWithoutCleanup(fromArray, *toArray, _options);
@ -369,7 +369,7 @@ string ABIFunctions::abiEncodingFunction(
// possible for library calls where we just forward the storage reference
solAssert(_options.encodeAsLibraryTypes, "");
solAssert(_options.padded && !_options.dynamicInplace, "Non-padded / inplace encoding for library call requested.");
solAssert(to == IntegerType::uint256(), "");
solAssert(to == *TypeProvider::uint256(), "");
templ("cleanupConvert", "value");
}
else
@ -445,7 +445,7 @@ string ABIFunctions::abiEncodingFunctionCalldataArrayWithoutCleanup(
solAssert(fromArrayType.location() == DataLocation::CallData, "");
solAssert(
fromArrayType.isByteArray() ||
*fromArrayType.baseType() == IntegerType::uint256() ||
*fromArrayType.baseType() == *TypeProvider::uint256() ||
*fromArrayType.baseType() == FixedBytesType(32),
"");
solAssert(fromArrayType.calldataStride() == toArrayType.memoryStride(), "");
@ -1077,7 +1077,7 @@ string ABIFunctions::abiDecodingFunction(Type const& _type, bool _fromMemory, bo
TypePointer decodingType = _type.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))
{
@ -1089,7 +1089,7 @@ string ABIFunctions::abiDecodingFunction(Type const& _type, bool _fromMemory, bo
else
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))
{
@ -1099,7 +1099,7 @@ string ABIFunctions::abiDecodingFunction(Type const& _type, bool _fromMemory, bo
else
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);
else
return abiDecodingFunctionValueType(_type, _fromMemory);

View File

@ -41,7 +41,7 @@ class Type;
class ArrayType;
class StructType;
class FunctionType;
using TypePointer = std::shared_ptr<Type const>;
using TypePointer = Type const*;
using TypePointers = std::vector<TypePointer>;
/**

View File

@ -23,6 +23,7 @@
#include <libsolidity/codegen/ArrayUtils.h>
#include <libsolidity/ast/Types.h>
#include <libsolidity/ast/TypeProvider.h>
#include <libsolidity/codegen/CompilerContext.h>
#include <libsolidity/codegen/CompilerUtils.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)
solAssert(_targetType.location() == DataLocation::Storage, "");
TypePointer uint256 = make_shared<IntegerType>(256);
TypePointer uint256 = TypeProvider::uint256();
TypePointer targetBaseType = _targetType.isByteArray() ? uint256 : _targetType.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
TypePointer targetType = _targetType.shared_from_this();
TypePointer sourceType = _sourceType.shared_from_this();
TypePointer targetType = &_targetType;
TypePointer sourceType = &_sourceType;
m_context.callLowLevelFunction(
"$copyArrayToStorage_" + sourceType->identifier() + "_to_" + targetType->identifier(),
3,
@ -336,7 +337,7 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
m_context << Instruction::DUP3 << Instruction::DUP5;
accessIndex(_sourceType, false);
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);
else
utils.storeInMemoryDynamic(*_sourceType.baseType());
@ -493,7 +494,7 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
else
m_context << Instruction::DUP2 << u256(0);
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);
else
utils.storeInMemoryDynamic(*_sourceType.baseType());
@ -530,7 +531,7 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
void ArrayUtils::clearArray(ArrayType const& _typeIn) const
{
TypePointer type = _typeIn.shared_from_this();
TypePointer type = &_typeIn;
m_context.callLowLevelFunction(
"$clearArray_" + _typeIn.identifier(),
2,
@ -584,7 +585,7 @@ void ArrayUtils::clearArray(ArrayType const& _typeIn) const
ArrayUtils(_context).convertLengthToSize(_type);
_context << Instruction::ADD << Instruction::SWAP1;
if (_type.baseType()->storageBytes() < 32)
ArrayUtils(_context).clearStorageLoop(make_shared<IntegerType>(256));
ArrayUtils(_context).clearStorageLoop(TypeProvider::uint256());
else
ArrayUtils(_context).clearStorageLoop(_type.baseType());
_context << Instruction::POP;
@ -625,7 +626,7 @@ void ArrayUtils::clearDynamicArray(ArrayType const& _type) const
<< Instruction::SWAP1;
// stack: data_pos_end data_pos
if (_type.storageStride() < 32)
clearStorageLoop(make_shared<IntegerType>(256));
clearStorageLoop(TypeProvider::uint256());
else
clearStorageLoop(_type.baseType());
// cleanup
@ -635,7 +636,7 @@ void ArrayUtils::clearDynamicArray(ArrayType const& _type) const
void ArrayUtils::resizeDynamicArray(ArrayType const& _typeIn) const
{
TypePointer type = _typeIn.shared_from_this();
TypePointer type = &_typeIn;
m_context.callLowLevelFunction(
"$resizeDynamicArray_" + _typeIn.identifier(),
2,
@ -732,7 +733,7 @@ void ArrayUtils::resizeDynamicArray(ArrayType const& _typeIn) const
ArrayUtils(_context).convertLengthToSize(_type);
_context << Instruction::DUP2 << Instruction::ADD << Instruction::SWAP1;
// 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;
// stack: ref new_length current_length first_word
solAssert(_context.stackHeight() - stackHeightStart == 4 - 2, "3");
@ -771,7 +772,7 @@ void ArrayUtils::resizeDynamicArray(ArrayType const& _typeIn) const
_context << Instruction::SWAP2 << Instruction::ADD;
// stack: ref new_length delete_end delete_start
if (_type.storageStride() < 32)
ArrayUtils(_context).clearStorageLoop(make_shared<IntegerType>(256));
ArrayUtils(_context).clearStorageLoop(TypeProvider::uint256());
else
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(
"$clearStorageLoop_" + _type->identifier(),

View File

@ -32,7 +32,7 @@ namespace solidity
class CompilerContext;
class Type;
class ArrayType;
using TypePointer = std::shared_ptr<Type const>;
using TypePointer = Type const*;
/**
* 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).
/// Stack pre: end_ref start_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).
/// if @a _pad then add padding to multiples of 32 bytes for calldata/memory.
/// Stack pre: length

View File

@ -23,6 +23,7 @@
#include <libsolidity/codegen/CompilerUtils.h>
#include <libsolidity/ast/AST.h>
#include <libsolidity/ast/TypeProvider.h>
#include <libsolidity/codegen/ABIFunctions.h>
#include <libsolidity/codegen/ArrayUtils.h>
#include <libsolidity/codegen/LValue.h>
@ -83,13 +84,13 @@ void CompilerUtils::toSizeAfterFreeMemoryPointer()
void CompilerUtils::revertWithStringData(Type const& _argumentType)
{
solAssert(_argumentType.isImplicitlyConvertibleTo(*Type::fromElementaryTypeName("string memory")), "");
solAssert(_argumentType.isImplicitlyConvertibleTo(*TypeProvider::fromElementaryTypeName("string memory")), "");
fetchFreeMemoryPointer();
m_context << (u256(FixedHash<4>::Arith(FixedHash<4>(dev::keccak256("Error(string)")))) << (256 - 32));
m_context << Instruction::DUP2 << Instruction::MSTORE;
m_context << u256(4) << Instruction::ADD;
// 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();
m_context << Instruction::REVERT;
}
@ -185,7 +186,7 @@ void CompilerUtils::loadFromMemoryDynamic(
void CompilerUtils::storeInMemory(unsigned _offset)
{
unsigned numBytes = prepareMemoryStore(IntegerType::uint256(), true);
unsigned numBytes = prepareMemoryStore(*TypeProvider::uint256(), true);
if (numBytes > 0)
m_context << u256(_offset) << Instruction::MSTORE;
}
@ -199,7 +200,7 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound
ref->location() == DataLocation::Memory,
"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))
{
@ -311,11 +312,11 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem
else
{
// 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())
{
// put on stack: data_pointer length
loadFromMemoryDynamic(IntegerType::uint256(), !_fromMemory);
loadFromMemoryDynamic(*TypeProvider::uint256(), !_fromMemory);
m_context << Instruction::SWAP1;
// stack: input_end base_offset next_pointer 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"}
);
// retrieve length
loadFromMemoryDynamic(IntegerType::uint256(), !_fromMemory, true);
loadFromMemoryDynamic(*TypeProvider::uint256(), !_fromMemory, true);
// stack: input_end base_offset next_pointer array_length data_pointer
m_context << Instruction::SWAP2;
// stack: input_end base_offset data_pointer array_length next_pointer
@ -454,7 +455,7 @@ void CompilerUtils::encodeToMemory(
type = _givenTypes[i]; // delay conversion
else
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);
else
storeInMemoryDynamic(*type, _padToWordBoundaries);
@ -482,7 +483,7 @@ void CompilerUtils::encodeToMemory(
{
auto const& strType = dynamic_cast<StringLiteralType const&>(*_givenTypes[i]);
m_context << u256(strType.value().size());
storeInMemoryDynamic(IntegerType::uint256(), true);
storeInMemoryDynamic(*TypeProvider::uint256(), true);
// stack: ... <end_of_mem'>
storeInMemoryDynamic(strType, _padToWordBoundaries);
}
@ -497,7 +498,7 @@ void CompilerUtils::encodeToMemory(
m_context << dupInstruction(1 + arrayType.sizeOnStack());
ArrayUtils(m_context).retrieveLength(arrayType, 1);
// 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''>
// copy the new memory pointer
m_context << swapInstruction(arrayType.sizeOnStack() + 1) << Instruction::POP;
@ -868,7 +869,7 @@ void CompilerUtils::convertType(
allocateMemory(storageSize);
// stack: mempos
m_context << Instruction::DUP1 << u256(data.size());
storeInMemoryDynamic(IntegerType::uint256());
storeInMemoryDynamic(*TypeProvider::uint256());
// stack: mempos datapos
storeStringData(data);
}
@ -917,7 +918,7 @@ void CompilerUtils::convertType(
if (targetType.isDynamicallySized())
{
m_context << Instruction::DUP2;
storeInMemoryDynamic(IntegerType::uint256());
storeInMemoryDynamic(*TypeProvider::uint256());
}
// stack: <mem start> <source ref> (variably sized) <length> <mem data pos>
if (targetType.baseType()->isValueType())
@ -988,10 +989,9 @@ void CompilerUtils::convertType(
{
case DataLocation::Storage:
{
auto conversionImpl = [
typeOnStack = dynamic_pointer_cast<StructType const>(_typeOnStack.shared_from_this()),
targetType = dynamic_pointer_cast<StructType const>(targetType.shared_from_this())
](CompilerContext& _context) {
auto conversionImpl =
[typeOnStack = &typeOnStack, targetType = &targetType](CompilerContext& _context)
{
CompilerUtils utils(_context);
// stack: <source ref>
utils.allocateMemory(typeOnStack->memorySize());
@ -1029,7 +1029,7 @@ void CompilerUtils::convertType(
m_context << Instruction::DUP1;
m_context << Instruction::CALLDATASIZE;
m_context << Instruction::SUB;
abiDecode({targetType.shared_from_this()}, false);
abiDecode({&targetType}, false);
break;
}
case DataLocation::Memory:
@ -1162,7 +1162,7 @@ void CompilerUtils::pushZeroValue(Type const& _type)
return;
}
TypePointer type = _type.shared_from_this();
TypePointer type = &_type;
m_context.callLowLevelFunction(
"$pushZeroValue_" + referenceType->identifier(),
0,
@ -1172,13 +1172,13 @@ void CompilerUtils::pushZeroValue(Type const& _type)
utils.allocateMemory(max(32u, type->calldataEncodedSize()));
_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))
{
utils.pushZeroValue(*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(), "");
if (arrayType->length() > 0)
@ -1275,10 +1275,10 @@ void CompilerUtils::popAndJump(unsigned _toHeight, eth::AssemblyItem const& _jum
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;
for (shared_ptr<Type const> const& type: _variableTypes)
for (Type const* const& type: _variableTypes)
size += type->sizeOnStack();
return size;
}
@ -1321,7 +1321,7 @@ void CompilerUtils::storeStringData(bytesConstRef _data)
for (unsigned i = 0; i < _data.size(); i += 32)
{
m_context << h256::Arith(h256(_data.cropped(i), h256::AlignLeft));
storeInMemoryDynamic(IntegerType::uint256());
storeInMemoryDynamic(*TypeProvider::uint256());
}
m_context << Instruction::POP;
}

View File

@ -23,6 +23,8 @@
#pragma once
#include <libsolidity/ast/ASTForward.h>
#include <libsolidity/ast/TypeProvider.h>
#include <libsolidity/codegen/CompilerContext.h>
#include <libsolidity/codegen/CompilerContext.h>
namespace dev {
@ -80,7 +82,7 @@ public:
/// @returns the number of bytes consumed in memory.
unsigned loadFromMemory(
unsigned _offset,
Type const& _type = IntegerType::uint256(),
Type const& _type = *TypeProvider::uint256(),
bool _fromCalldata = false,
bool _padToWords = false
);
@ -264,7 +266,7 @@ public:
template <class T>
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.
/// Stack pre: <value> <shift_by_bits>

View File

@ -21,6 +21,7 @@
*/
#include <libsolidity/ast/AST.h>
#include <libsolidity/ast/TypeProvider.h>
#include <libsolidity/codegen/CompilerUtils.h>
#include <libsolidity/codegen/ContractCompiler.h>
#include <libsolidity/codegen/ExpressionCompiler.h>
@ -871,7 +872,7 @@ bool ContractCompiler::visit(Return const& _return)
TypePointer expectedType;
if (expression->annotation().type->category() == Type::Category::Tuple || types.size() != 1)
expectedType = make_shared<TupleType>(types);
expectedType = TypeProvider::tupleType(move(types));
else
expectedType = types.front();
compileExpression(*expression, expectedType);
@ -915,7 +916,7 @@ bool ContractCompiler::visit(VariableDeclarationStatement const& _variableDeclar
CompilerUtils utils(m_context);
compileExpression(*expression);
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();
else
valueTypes = TypePointers{expression->annotation().type};

View File

@ -23,6 +23,7 @@
#include <libsolidity/codegen/ExpressionCompiler.h>
#include <libsolidity/ast/AST.h>
#include <libsolidity/ast/TypeProvider.h>
#include <libsolidity/codegen/CompilerContext.h>
#include <libsolidity/codegen/CompilerUtils.h>
#include <libsolidity/codegen/LValue.h>
@ -102,7 +103,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
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, "");
@ -152,7 +153,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
m_context << u256(0);
returnType = mappingType->valueType();
}
else if (auto arrayType = dynamic_cast<ArrayType const*>(returnType.get()))
else if (auto arrayType = dynamic_cast<ArrayType const*>(returnType))
{
// pop offset
m_context << Instruction::POP;
@ -176,7 +177,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
unsigned retSizeOnStack = 0;
auto returnTypes = accessorType.returnParameterTypes();
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
m_context << Instruction::POP;
@ -186,7 +187,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
{
if (returnTypes[i]->category() == Type::Category::Mapping)
continue;
if (auto arrayType = dynamic_cast<ArrayType const*>(returnTypes[i].get()))
if (auto arrayType = dynamic_cast<ArrayType const*>(returnTypes[i]))
if (!arrayType->isByteArray())
continue;
pair<u256, unsigned> const& offsets = structType->storageOffsetsOfMember(names[i]);
@ -496,7 +497,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
functionType = structType.constructorType();
}
else
functionType = dynamic_pointer_cast<FunctionType const>(_functionCall.expression().annotation().type);
functionType = dynamic_cast<FunctionType const*>(_functionCall.expression().annotation().type);
TypePointers parameterTypes = functionType->parameterTypes();
vector<ASTPointer<Expression const>> const& callArguments = _functionCall.arguments();
@ -647,7 +648,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
_functionCall.expression().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.
// Its values of gasSet and valueSet is equal to the original function's though.
unsigned stackDepth = (function.gasSet() ? 1 : 0) + (function.valueSet() ? 1 : 0);
@ -731,9 +732,9 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
arguments.front()->accept(*this);
// Optimization: If type is bytes or string, then do not encode,
// 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;
}
else
@ -780,7 +781,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
{
++numIndexed;
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().packedEncode(
@ -835,13 +836,13 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
case FunctionType::Kind::MulMod:
{
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.appendConditionalInvalid();
for (unsigned i = 1; i < 3; i ++)
{
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)
m_context << Instruction::ADDMOD;
@ -872,10 +873,10 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
solAssert(function.parameterTypes().size() == 1, "");
solAssert(!!function.parameterTypes()[0], "");
TypePointer paramType = function.parameterTypes()[0];
shared_ptr<ArrayType> arrayType =
ArrayType const* arrayType =
function.kind() == FunctionType::Kind::ArrayPush ?
make_shared<ArrayType>(DataLocation::Storage, paramType) :
make_shared<ArrayType>(DataLocation::Storage);
TypeProvider::arrayType(DataLocation::Storage, paramType) :
TypeProvider::arrayType(DataLocation::Storage);
// stack: ArrayReference
arguments[0]->accept(*this);
@ -927,7 +928,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
// Fetch requested length.
arguments[0]->accept(*this);
utils().convertType(*arguments[0]->annotation().type, IntegerType::uint256());
utils().convertType(*arguments[0]->annotation().type, *TypeProvider::uint256());
// Stack: requested_length
utils().fetchFreeMemoryPointer();
@ -1057,11 +1058,11 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
if (function.kind() == FunctionType::Kind::ABIEncodeWithSignature)
{
// 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()));
m_context << (u256(FixedHash<4>::Arith(hash)) << (256 - 32));
dataOnStack = make_shared<FixedBytesType>(4);
dataOnStack = TypeProvider::fixedBytesType(4);
}
else
{
@ -1072,7 +1073,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
m_context << Instruction::KECCAK256;
// stack: <memory pointer> <hash>
dataOnStack = make_shared<FixedBytesType>(32);
dataOnStack = TypeProvider::fixedBytesType(32);
}
}
else
@ -1103,7 +1104,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
arguments.front()->accept(*this);
TypePointer firstArgType = arguments.front()->annotation().type;
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();
else
targetTypes = TypePointers{_functionCall.annotation().type};
@ -1114,7 +1115,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
utils().abiDecode(targetTypes, false);
else
{
utils().convertType(*firstArgType, ArrayType::bytesMemory());
utils().convertType(*firstArgType, *TypeProvider::bytesMemoryType());
m_context << Instruction::DUP1 << u256(32) << Instruction::ADD;
m_context << Instruction::SWAP1 << Instruction::MLOAD;
// stack now: <mem_pos> <length>
@ -1145,7 +1146,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
CompilerContext::LocationSetter locationSetter(m_context, _memberAccess);
// Check whether the member is a bound function.
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())
{
_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
// 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");
if (auto variable = dynamic_cast<VariableDeclaration const*>(_memberAccess.annotation().referencedDeclaration))
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())
{
@ -1223,14 +1224,14 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
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
}
else
_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);
m_context << enumType->memberValue(_memberAccess.memberName());
@ -1288,7 +1289,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
identifier = FunctionType(*function).externalIdentifier();
else
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;
}
else
@ -1306,7 +1307,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
{
utils().convertType(
*_memberAccess.expression().annotation().type,
AddressType::address(),
*TypeProvider::addressType(),
true
);
m_context << Instruction::BALANCE;
@ -1323,7 +1324,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
else if ((set<string>{"call", "callcode", "delegatecall", "staticcall"}).count(member))
utils().convertType(
*_memberAccess.expression().annotation().type,
AddressType::address(),
*TypeProvider::addressType(),
true
);
else
@ -1542,7 +1543,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
TypePointers{keyType}
);
m_context << Instruction::SWAP1;
utils().storeInMemoryDynamic(IntegerType::uint256());
utils().storeInMemoryDynamic(*TypeProvider::uint256());
utils().toSizeAfterFreeMemoryPointer();
}
else
@ -1551,7 +1552,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
appendExpressionCopyToMemory(*keyType, *_indexAccess.indexExpression());
m_context << Instruction::SWAP1;
solAssert(CompilerUtils::freeMemoryPointer >= 0x40, "");
utils().storeInMemoryDynamic(IntegerType::uint256());
utils().storeInMemoryDynamic(*TypeProvider::uint256());
m_context << u256(0);
}
m_context << Instruction::KECCAK256;
@ -1564,7 +1565,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
solAssert(_indexAccess.indexExpression(), "Index expression expected.");
_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>
switch (arrayType.location())
{
@ -1631,7 +1632,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
solAssert(_indexAccess.indexExpression(), "Index expression expected.");
_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>
// check out-of-bounds access
m_context << u256(fixedBytesType.numBytes());
@ -2211,7 +2212,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
needToUpdateFreeMemoryPtr = true;
else
for (auto const& retType: returnTypes)
if (dynamic_cast<ReferenceType const*>(retType.get()))
if (dynamic_cast<ReferenceType const*>(retType))
needToUpdateFreeMemoryPtr = true;
// Stack: return_data_start

View File

@ -35,7 +35,7 @@ using namespace langutil;
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_size(m_dataType->sizeOnStack())
{
@ -475,7 +475,7 @@ void StorageByteArrayElement::setToZero(SourceLocation const&, bool _removeRefer
}
StorageArrayLength::StorageArrayLength(CompilerContext& _compilerContext, ArrayType const& _arrayType):
LValue(_compilerContext, _arrayType.memberType("length").get()),
LValue(_compilerContext, _arrayType.memberType("length")),
m_arrayType(_arrayType)
{
solAssert(m_arrayType.isDynamicallySized(), "");

View File

@ -145,7 +145,7 @@ string YulUtilFunctions::leftAlignFunction(Type const& _type)
templ("body", "aligned := value");
break;
case Type::Category::Contract:
templ("body", "aligned := " + leftAlignFunction(AddressType::address()) + "(value)");
templ("body", "aligned := " + leftAlignFunction(*TypeProvider::addressType()) + "(value)");
break;
case Type::Category::Enum:
{

View File

@ -82,7 +82,7 @@ void IRGeneratorForStatements::endVisit(BinaryOperation const& _binOp)
{
solUnimplementedAssert(_binOp.getOperator() == Token::Add, "");
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(), "");
m_code <<
@ -103,7 +103,7 @@ void IRGeneratorForStatements::endVisit(BinaryOperation const& _binOp)
bool IRGeneratorForStatements::visit(FunctionCall const& _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();
vector<ASTPointer<Expression const>> const& callArguments = _functionCall.arguments();

View File

@ -17,6 +17,7 @@
#include <libsolidity/formal/SMTChecker.h>
#include <libsolidity/ast/TypeProvider.h>
#include <libsolidity/formal/SMTPortfolio.h>
#include <libsolidity/formal/SymbolicTypes.h>
@ -447,7 +448,7 @@ void SMTChecker::checkUnderOverflow()
void SMTChecker::checkUnderflow(OverflowTarget& _target)
{
solAssert(_target.type != OverflowTarget::Type::Overflow, "");
auto intType = dynamic_cast<IntegerType const*>(_target.intType.get());
auto intType = dynamic_cast<IntegerType const*>(_target.intType);
checkCondition(
_target.path && _target.value < minValue(*intType),
_target.location,
@ -460,7 +461,7 @@ void SMTChecker::checkUnderflow(OverflowTarget& _target)
void SMTChecker::checkOverflow(OverflowTarget& _target)
{
solAssert(_target.type != OverflowTarget::Type::Underflow, "");
auto intType = dynamic_cast<IntegerType const*>(_target.intType.get());
auto intType = dynamic_cast<IntegerType const*>(_target.intType);
checkCondition(
_target.path && _target.value > maxValue(*intType),
_target.location,
@ -681,7 +682,7 @@ void SMTChecker::inlineFunctionCall(FunctionCall const& _funCall)
{
vector<smt::Expression> funArgs;
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, "");
if (funType->bound())
{
@ -803,8 +804,8 @@ void SMTChecker::endVisit(Literal const& _literal)
{
if (type.category() == Type::Category::StringLiteral)
{
auto stringType = make_shared<ArrayType>(DataLocation::Memory, true);
auto stringLit = dynamic_cast<StringLiteralType const*>(_literal.annotation().type.get());
auto stringType = TypeProvider::stringMemoryType();
auto stringLit = dynamic_cast<StringLiteralType const*>(_literal.annotation().type);
solAssert(stringLit, "");
auto result = newSymbolicVariable(*stringType, stringLit->richIdentifier(), *m_interface);
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))
{
auto enumType = dynamic_cast<EnumType const*>(accessType.get());
auto enumType = dynamic_cast<EnumType const*>(accessType);
solAssert(enumType, "");
defineExpr(_memberAccess, enumType->memberValue(_memberAccess.memberName()));
}
@ -939,13 +940,13 @@ void SMTChecker::arrayIndexAssignment(Expression const& _expr, smt::Expression c
return true;
if (prefix->category() == Type::Category::Mapping)
{
auto mapPrefix = dynamic_cast<MappingType const*>(prefix.get());
auto mapPrefix = dynamic_cast<MappingType const*>(prefix);
solAssert(mapPrefix, "");
prefix = mapPrefix->valueType();
}
else
{
auto arrayPrefix = dynamic_cast<ArrayType const*>(prefix.get());
auto arrayPrefix = dynamic_cast<ArrayType const*>(prefix);
solAssert(arrayPrefix, "");
prefix = arrayPrefix->baseType();
}
@ -1017,7 +1018,7 @@ bool SMTChecker::shortcutRationalNumber(Expression const& _expr)
{
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, "");
if (rationalType->isNegative())
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)
addOverflowTarget(OverflowTarget::Type::All, type, _value, _location);
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)
arrayAssignment();
m_interface->addAssertion(newValue(_variable) == _value);
@ -1522,7 +1523,7 @@ void SMTChecker::resetVariables(function<bool(VariableDeclaration const&)> const
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 _type;
}

View File

@ -178,7 +178,7 @@ private:
location(_location),
callStack(move(_callStack))
{
solAssert(dynamic_cast<IntegerType const*>(intType.get()), "");
solAssert(dynamic_cast<IntegerType const*>(intType), "");
}
};

View File

@ -17,6 +17,7 @@
#include <libsolidity/formal/SymbolicTypes.h>
#include <libsolidity/ast/TypeProvider.h>
#include <libsolidity/ast/Types.h>
#include <memory>
@ -115,11 +116,11 @@ pair<bool, shared_ptr<SymbolicVariable>> dev::solidity::newSymbolicVariable(
{
bool abstract = false;
shared_ptr<SymbolicVariable> var;
TypePointer type = _type.shared_from_this();
TypePointer type = &_type;
if (!isSupportedTypeDeclaration(_type))
{
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()))
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);
else if (isFixedBytes(_type.category()))
{
auto fixedBytesType = dynamic_cast<FixedBytesType const*>(type.get());
auto fixedBytesType = dynamic_cast<FixedBytesType const*>(type);
solAssert(fixedBytesType, "");
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);
solAssert(rational, "");
if (rational->isFractional())
var = make_shared<SymbolicIntVariable>(make_shared<IntegerType>(256), _uniqueName, _solver);
var = make_shared<SymbolicIntVariable>(TypeProvider::uint256(), _uniqueName, _solver);
else
var = make_shared<SymbolicIntVariable>(type, _uniqueName, _solver);
}
@ -253,14 +254,14 @@ void dev::solidity::smt::setSymbolicUnknownValue(smt::Expression _expr, TypePoin
solAssert(_type, "");
if (isEnum(_type->category()))
{
auto enumType = dynamic_cast<EnumType const*>(_type.get());
auto enumType = dynamic_cast<EnumType const*>(_type);
solAssert(enumType, "");
_interface.addAssertion(_expr >= 0);
_interface.addAssertion(_expr < enumType->numberOfMembers());
}
else if (isInteger(_type->category()))
{
auto intType = dynamic_cast<IntegerType const*>(_type.get());
auto intType = dynamic_cast<IntegerType const*>(_type);
solAssert(intType, "");
_interface.addAssertion(_expr >= minValue(*intType));
_interface.addAssertion(_expr <= maxValue(*intType));

View File

@ -19,6 +19,7 @@
#include <libsolidity/formal/SymbolicTypes.h>
#include <libsolidity/ast/AST.h>
#include <libsolidity/ast/TypeProvider.h>
using namespace std;
using namespace dev;
@ -102,7 +103,7 @@ SymbolicAddressVariable::SymbolicAddressVariable(
string _uniqueName,
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,
smt::SolverInterface& _interface
):
SymbolicIntVariable(make_shared<IntegerType>(_numBytes * 8), move(_uniqueName), _interface)
SymbolicIntVariable(TypeProvider::uint(_numBytes * 8), move(_uniqueName), _interface)
{
}

View File

@ -32,7 +32,7 @@ namespace solidity
// Forward declarations
class ContractDefinition;
class Type;
using TypePointer = std::shared_ptr<Type const>;
using TypePointer = Type const*;
class ABI
{

View File

@ -38,6 +38,7 @@
#include <libsolidity/analysis/ViewPureChecker.h>
#include <libsolidity/ast/AST.h>
#include <libsolidity/ast/TypeProvider.h>
#include <libsolidity/codegen/Compiler.h>
#include <libsolidity/formal/SMTChecker.h>
#include <libsolidity/interface/ABI.h>
@ -66,6 +67,26 @@ using namespace dev;
using namespace langutil;
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)
{
auto eq = find(_remapping.begin(), _remapping.end(), '=');
@ -157,6 +178,7 @@ void CompilerStack::reset(bool _keepSettings)
m_sourceOrder.clear();
m_contracts.clear();
m_errorReporter.clear();
TypeProvider::reset();
}
void CompilerStack::setSources(StringMap const& _sources)

View File

@ -98,11 +98,9 @@ public:
/// Creates a new compiler stack.
/// @param _readFile callback to used to read files for import statements. Must return
/// and must not emit exceptions.
explicit CompilerStack(ReadCallback::Callback const& _readFile = ReadCallback::Callback()):
m_readFile(_readFile),
m_generateIR(false),
m_errorList(),
m_errorReporter(m_errorList) {}
explicit CompilerStack(ReadCallback::Callback const& _readFile = ReadCallback::Callback());
~CompilerStack();
/// @returns the list of errors that occurred during parsing and type checking.
langutil::ErrorList const& errors() const { return m_errorReporter.errors(); }

View File

@ -47,21 +47,21 @@ AnalysisFramework::parseAnalyseAndReturnError(
bool _allowMultipleErrors
)
{
m_compiler.reset();
m_compiler.setSources({{"", _insertVersionPragma ? "pragma solidity >=0.0;\n" + _source : _source}});
m_compiler.setEVMVersion(dev::test::Options::get().evmVersion());
if (!m_compiler.parse())
compiler().reset();
compiler().setSources({{"", _insertVersionPragma ? "pragma solidity >=0.0;\n" + _source : _source}});
compiler().setEVMVersion(dev::test::Options::get().evmVersion());
if (!compiler().parse())
{
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)
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
@ -118,7 +118,7 @@ ErrorList AnalysisFramework::expectError(std::string const& _source, bool _warni
string AnalysisFramework::formatErrors() const
{
string message;
for (auto const& error: m_compiler.errors())
for (auto const& error: compiler().errors())
message += formatError(*error);
return message;
}

View File

@ -35,8 +35,8 @@ namespace solidity
class Type;
class FunctionType;
using TypePointer = std::shared_ptr<Type const>;
using FunctionTypePointer = std::shared_ptr<FunctionType const>;
using TypePointer = Type const*;
using FunctionTypePointer = FunctionType const*;
namespace test
{
@ -71,7 +71,25 @@ protected:
langutil::ErrorList filterErrors(langutil::ErrorList const& _errorList, bool _includeWarnings) const;
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

View File

@ -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; }
}
)";
m_compiler.setOptimiserSettings(dev::test::Options::get().optimize);
compiler().setOptimiserSettings(dev::test::Options::get().optimize);
BOOST_REQUIRE(success(sourceCode));
BOOST_REQUIRE_MESSAGE(m_compiler.compile(), "Compiling contract failed");
bytes const& creationBytecode = dev::test::bytecodeSansMetadata(m_compiler.object("C").bytecode);
bytes const& runtimeBytecode = dev::test::bytecodeSansMetadata(m_compiler.runtimeObject("C").bytecode);
BOOST_REQUIRE_MESSAGE(compiler().compile(), "Compiling contract failed");
bytes const& creationBytecode = dev::test::bytecodeSansMetadata(compiler().object("C").bytecode);
bytes const& runtimeBytecode = dev::test::bytecodeSansMetadata(compiler().runtimeObject("C").bytecode);
BOOST_CHECK(creationBytecode.size() >= 90);
BOOST_CHECK(creationBytecode.size() <= 120);
BOOST_CHECK(runtimeBytecode.size() >= 10);

View File

@ -28,6 +28,7 @@
#include <libsolidity/codegen/CompilerContext.h>
#include <libsolidity/codegen/ExpressionCompiler.h>
#include <libsolidity/ast/AST.h>
#include <libsolidity/ast/TypeProvider.h>
#include <libsolidity/analysis/TypeChecker.h>
#include <liblangutil/ErrorReporter.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);
bytes code = compileFirstExpression(sourceCode, {}, {}, {make_shared<MagicVariableDeclaration>("blockhash", blockhashFun)});
@ -618,7 +619,7 @@ BOOST_AUTO_TEST_CASE(gas_left)
)";
bytes code = compileFirstExpression(
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)});

View File

@ -436,7 +436,7 @@ BOOST_AUTO_TEST_CASE(getter_is_memory_type)
)";
CHECK_SUCCESS_NO_WARNINGS(text);
// 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);
for (auto const& f: c.interfaceFunctions())
{

View File

@ -21,6 +21,7 @@
*/
#include <libsolidity/ast/Types.h>
#include <libsolidity/ast/TypeProvider.h>
#include <libsolidity/ast/AST.h>
#include <libdevcore/Keccak256.h>
#include <boost/test/unit_test.hpp>
@ -39,51 +40,51 @@ BOOST_AUTO_TEST_SUITE(SolidityTypes)
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)
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_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)
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_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++)
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_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)
{
BOOST_CHECK(*Type::fromElementaryTypeName(ElementaryTypeNameToken(Token::FixedMxN, i, 0)) == *make_shared<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, 0)) == *TypeProvider::fixedPointType(i, 0, 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_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)
{
BOOST_CHECK(*Type::fromElementaryTypeName(ElementaryTypeNameToken(Token::UFixedMxN, i, 0)) == *make_shared<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, 0)) == *TypeProvider::fixedPointType(i, 0, 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)
{
MemberList members(MemberList::MemberMap({
{string("first"), Type::fromElementaryTypeName("uint128")},
{string("second"), Type::fromElementaryTypeName("uint120")},
{string("wraps"), Type::fromElementaryTypeName("uint16")}
{string("first"), TypeProvider::fromElementaryTypeName("uint128")},
{string("second"), TypeProvider::fromElementaryTypeName("uint120")},
{string("wraps"), TypeProvider::fromElementaryTypeName("uint16")}
}));
BOOST_REQUIRE_EQUAL(u256(2), members.storageSize());
BOOST_REQUIRE(members.memberStorageOffset("first") != nullptr);
@ -97,15 +98,15 @@ BOOST_AUTO_TEST_CASE(storage_layout_simple)
BOOST_AUTO_TEST_CASE(storage_layout_mapping)
{
MemberList members(MemberList::MemberMap({
{string("first"), Type::fromElementaryTypeName("uint128")},
{string("second"), make_shared<MappingType>(
Type::fromElementaryTypeName("uint8"),
Type::fromElementaryTypeName("uint8")
{string("first"), TypeProvider::fromElementaryTypeName("uint128")},
{string("second"), TypeProvider::mappingType(
TypeProvider::fromElementaryTypeName("uint8"),
TypeProvider::fromElementaryTypeName("uint8")
)},
{string("third"), Type::fromElementaryTypeName("uint16")},
{string("final"), make_shared<MappingType>(
Type::fromElementaryTypeName("uint8"),
Type::fromElementaryTypeName("uint8")
{string("third"), TypeProvider::fromElementaryTypeName("uint16")},
{string("final"), TypeProvider::mappingType(
TypeProvider::fromElementaryTypeName("uint8"),
TypeProvider::fromElementaryTypeName("uint8")
)},
}));
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_CHECK(ArrayType(DataLocation::Storage, make_shared<FixedBytesType>(1), 32).storageSize() == 1);
BOOST_CHECK(ArrayType(DataLocation::Storage, make_shared<FixedBytesType>(1), 33).storageSize() == 2);
BOOST_CHECK(ArrayType(DataLocation::Storage, make_shared<FixedBytesType>(2), 31).storageSize() == 2);
BOOST_CHECK(ArrayType(DataLocation::Storage, make_shared<FixedBytesType>(7), 8).storageSize() == 2);
BOOST_CHECK(ArrayType(DataLocation::Storage, make_shared<FixedBytesType>(7), 9).storageSize() == 3);
BOOST_CHECK(ArrayType(DataLocation::Storage, make_shared<FixedBytesType>(31), 9).storageSize() == 9);
BOOST_CHECK(ArrayType(DataLocation::Storage, make_shared<FixedBytesType>(32), 9).storageSize() == 9);
BOOST_CHECK(ArrayType(DataLocation::Storage, TypeProvider::fixedBytesType(1), 32).storageSize() == 1);
BOOST_CHECK(ArrayType(DataLocation::Storage, TypeProvider::fixedBytesType(1), 33).storageSize() == 2);
BOOST_CHECK(ArrayType(DataLocation::Storage, TypeProvider::fixedBytesType(2), 31).storageSize() == 2);
BOOST_CHECK(ArrayType(DataLocation::Storage, TypeProvider::fixedBytesType(7), 8).storageSize() == 2);
BOOST_CHECK(ArrayType(DataLocation::Storage, TypeProvider::fixedBytesType(7), 9).storageSize() == 3);
BOOST_CHECK(ArrayType(DataLocation::Storage, TypeProvider::fixedBytesType(31), 9).storageSize() == 9);
BOOST_CHECK(ArrayType(DataLocation::Storage, TypeProvider::fixedBytesType(32), 9).storageSize() == 9);
}
BOOST_AUTO_TEST_CASE(type_identifier_escaping)
@ -149,12 +150,12 @@ BOOST_AUTO_TEST_CASE(type_identifier_escaping)
BOOST_AUTO_TEST_CASE(type_identifiers)
{
ASTNode::resetID();
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("uint128")->identifier(), "t_uint128");
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("int128")->identifier(), "t_int128");
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("address")->identifier(), "t_address");
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("uint8")->identifier(), "t_uint8");
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("ufixed64x2")->identifier(), "t_ufixed64x2");
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("fixed128x8")->identifier(), "t_fixed128x8");
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("uint128")->identifier(), "t_uint128");
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("int128")->identifier(), "t_int128");
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("address")->identifier(), "t_address");
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("uint8")->identifier(), "t_uint8");
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("ufixed64x2")->identifier(), "t_ufixed64x2");
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(200, 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(),
"t_stringliteral_196a9142ee0d40e274a6482393c762b16dd8315713207365e1e13d8d85b74fc4"
);
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("byte")->identifier(), "t_bytes1");
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("bytes8")->identifier(), "t_bytes8");
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("bytes32")->identifier(), "t_bytes32");
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("bool")->identifier(), "t_bool");
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("bytes")->identifier(), "t_bytes_storage_ptr");
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("bytes memory")->identifier(), "t_bytes_memory_ptr");
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("bytes storage")->identifier(), "t_bytes_storage_ptr");
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("bytes calldata")->identifier(), "t_bytes_calldata_ptr");
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("string")->identifier(), "t_string_storage_ptr");
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("string memory")->identifier(), "t_string_memory_ptr");
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("string storage")->identifier(), "t_string_storage_ptr");
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("string calldata")->identifier(), "t_string_calldata_ptr");
ArrayType largeintArray(DataLocation::Memory, Type::fromElementaryTypeName("int128"), u256("2535301200456458802993406410752"));
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("byte")->identifier(), "t_bytes1");
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("bytes8")->identifier(), "t_bytes8");
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("bytes32")->identifier(), "t_bytes32");
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("bool")->identifier(), "t_bool");
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("bytes")->identifier(), "t_bytes_storage_ptr");
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("bytes memory")->identifier(), "t_bytes_memory_ptr");
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("bytes storage")->identifier(), "t_bytes_storage_ptr");
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("bytes calldata")->identifier(), "t_bytes_calldata_ptr");
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("string")->identifier(), "t_string_storage_ptr");
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("string memory")->identifier(), "t_string_memory_ptr");
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("string storage")->identifier(), "t_string_storage_ptr");
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("string calldata")->identifier(), "t_string_calldata_ptr");
ArrayType largeintArray(DataLocation::Memory, TypeProvider::fromElementaryTypeName("int128"), u256("2535301200456458802993406410752"));
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 multiArray = make_shared<ArrayType>(DataLocation::Storage, stringArray);
TypePointer stringArray = TypeProvider::arrayType(DataLocation::Storage, TypeProvider::fromElementaryTypeName("string"), u256("20"));
TypePointer multiArray = TypeProvider::arrayType(DataLocation::Storage, stringArray);
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);
@ -194,14 +195,14 @@ BOOST_AUTO_TEST_CASE(type_identifiers)
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_$__$");
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$__$");
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_$_$");
TypePointer m = make_shared<MappingType>(Type::fromElementaryTypeName("bytes32"), s.type());
MappingType m2(Type::fromElementaryTypeName("uint64"), m);
TypePointer m = TypeProvider::mappingType(TypeProvider::fromElementaryTypeName("bytes32"), s.type());
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_$_$_$");
// 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(false), 1);
shared_ptr<ArrayType> uint24Array = make_shared<ArrayType>(
ArrayType const* uint24Array = TypeProvider::arrayType(
DataLocation::Memory,
make_shared<IntegerType>(24),
TypeProvider::uint(24),
9
);
BOOST_CHECK_EQUAL(uint24Array->calldataEncodedSize(true), 9 * 32);

View File

@ -66,14 +66,14 @@ SyntaxTest::SyntaxTest(string const& _filename, langutil::EVMVersion _evmVersion
bool SyntaxTest::run(ostream& _stream, string const& _linePrefix, bool _formatted)
{
string const versionPragma = "pragma solidity >=0.0;\n";
m_compiler.reset();
m_compiler.setSources({{"", versionPragma + m_source}});
m_compiler.setEVMVersion(m_evmVersion);
compiler().reset();
compiler().setSources({{"", versionPragma + m_source}});
compiler().setEVMVersion(m_evmVersion);
if (m_compiler.parse())
m_compiler.analyze();
if (compiler().parse())
compiler().analyze();
for (auto const& currentError: filterErrors(m_compiler.errors(), true))
for (auto const& currentError: filterErrors(compiler().errors(), true))
{
int locationStart = -1, locationEnd = -1;
if (auto location = boost::get_error_info<errinfo_sourceLocation>(*currentError))