libsolidity: Introducing TypeProvider API, for clear type system ownership.

This commit is contained in:
Christian Parpart
2019-04-16 18:26:45 +02:00
committed by chriseth
parent 862d798047
commit bf43eebea9
38 changed files with 1489 additions and 837 deletions
+22 -21
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));
}
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
+5 -4
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
+5 -5
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
+1 -1
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;
+423
View File
@@ -0,0 +1,423 @@
/*
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 <libdevcore/make_array.h>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/split.hpp>
using namespace std;
using namespace dev;
using namespace solidity;
template <size_t... N>
constexpr array<IntegerType, sizeof...(N)> createIntegerTypes(IntegerType::Modifier _modifier, index_sequence<N...>)
{
return make_array<IntegerType>(IntegerType((static_cast<unsigned>(N) + 1) * 8, _modifier)...);
}
template <size_t... N>
constexpr array<FixedBytesType, sizeof...(N)> createFixedBytesTypes(index_sequence<N...>)
{
return make_array<FixedBytesType>(FixedBytesType(static_cast<unsigned>(N) + 1)...);
}
BoolType const TypeProvider::m_boolType{};
InaccessibleDynamicType const TypeProvider::m_inaccessibleDynamicType{};
ArrayType const TypeProvider::m_bytesStorageType{DataLocation::Storage, false};
ArrayType const TypeProvider::m_bytesMemoryType{DataLocation::Memory, false};
ArrayType const TypeProvider::m_stringStorageType{DataLocation::Storage, true};
ArrayType const TypeProvider::m_stringMemoryType{DataLocation::Memory, true};
TupleType const TypeProvider::m_emptyTupleType{};
AddressType const TypeProvider::m_payableAddressType{StateMutability::Payable};
AddressType const TypeProvider::m_addressType{StateMutability::NonPayable};
array<IntegerType, 32> const TypeProvider::m_intM{createIntegerTypes(IntegerType::Modifier::Signed, make_index_sequence<32>{})};
array<IntegerType, 32> const TypeProvider::m_uintM{createIntegerTypes(IntegerType::Modifier::Unsigned, make_index_sequence<32>{})};
array<FixedBytesType, 32> const TypeProvider::m_bytesM{createFixedBytesTypes(make_index_sequence<32>{})};
array<MagicType, 4> const TypeProvider::m_magicTypes{
MagicType{MagicType::Kind::Block},
MagicType{MagicType::Kind::Message},
MagicType{MagicType::Kind::Transaction},
MagicType{MagicType::Kind::ABI}
// MetaType is stored separately
};
inline void clearCache(Type const& type)
{
type.clearCache();
}
template <typename... Args>
inline void clearCache(Type const& type, Args&... moreTypes)
{
clearCache(type);
clearCache(moreTypes...);
}
template <typename Container>
inline void clearAllCaches(Container& container)
{
for_each(begin(container), end(container), [](Type const& t) { t.clearCache(); });
}
template <typename Container, typename... Args>
inline void clearAllCaches(Container& types, Args&... more)
{
clearAllCaches(types);
clearAllCaches(more...);
}
void TypeProvider::reset()
{
clearCache(
m_boolType,
m_inaccessibleDynamicType,
m_bytesStorageType,
m_bytesMemoryType,
m_stringStorageType,
m_stringMemoryType,
m_emptyTupleType,
m_payableAddressType,
m_addressType
);
clearAllCaches(instance().m_intM, instance().m_uintM, instance().m_bytesM, 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 bytesType();
case Token::String:
return stringType();
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;
}
}
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 stringType();
if (_location == DataLocation::Memory)
return stringMemoryType();
}
else
{
if (_location == DataLocation::Storage)
return bytesType();
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));
}
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);
}
+218
View File
@@ -0,0 +1,218 @@
/*
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); }
static ArrayType const* bytesType() noexcept { return &m_bytesStorageType; }
static ArrayType const* bytesMemoryType() noexcept { return &m_bytesMemoryType; }
static ArrayType const* stringType() noexcept { return &m_stringStorageType; }
static ArrayType const* stringMemoryType() noexcept { return &m_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 = 256, IntegerType::Modifier _modifier = IntegerType::Modifier::Unsigned)
{
solAssert((_bits % 8) == 0, "");
if (_modifier == IntegerType::Modifier::Unsigned)
return &m_uintM.at(_bits / 8 - 1);
else
return &m_intM.at(_bits / 8 - 1);
}
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 = DataLocation::Storage);
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;
static ArrayType const m_bytesStorageType;
static ArrayType const m_bytesMemoryType;
static ArrayType const m_stringStorageType;
static ArrayType const m_stringMemoryType;
static TupleType const m_emptyTupleType;
static AddressType const m_payableAddressType;
static AddressType const m_addressType;
static std::array<IntegerType, 32> const m_intM;
static std::array<IntegerType, 32> const m_uintM;
static std::array<FixedBytesType, 32> const m_bytesM;
static std::array<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
+286 -336
View File
File diff suppressed because it is too large Load Diff
+164 -150
View File
@@ -45,10 +45,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 +95,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 +103,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 +150,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&&) = default;
Type& operator=(Type const&) = delete;
Type& operator=(Type&&) = default;
virtual ~Type() = default;
enum class Category
{
Address, Integer, RationalNumber, StringLiteral, Bool, FixedPoint, Array,
@@ -160,20 +168,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 +197,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 +254,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 +294,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 +307,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 +334,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 +358,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 +378,21 @@ 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);
IntegerType(IntegerType&&) = default;
IntegerType& operator=(IntegerType&&) = default;
IntegerType(IntegerType const&) = default;
IntegerType& operator=(IntegerType const&) = default;
~IntegerType() = default;
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 +403,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 +413,8 @@ public:
bigint maxValue() const;
private:
unsigned m_bits;
Modifier m_modifier;
unsigned const m_bits;
Modifier const m_modifier;
};
/**
@@ -427,15 +427,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 +446,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 +462,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 +478,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 +500,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 +515,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 +525,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 +539,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 +574,22 @@ private:
class FixedBytesType: public Type
{
public:
explicit FixedBytesType(unsigned _bytes);
Category category() const override { return Category::FixedBytes; }
explicit FixedBytesType(unsigned _bytes);
FixedBytesType(FixedBytesType const&) = delete;
FixedBytesType& operator=(FixedBytesType const&) = delete;
FixedBytesType(FixedBytesType&&) = default;
FixedBytesType& operator=(FixedBytesType&&) = default;
~FixedBytesType() = default;
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 +598,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; }
@@ -608,10 +613,12 @@ private:
class BoolType: public Type
{
public:
BoolType() = default;
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 +627,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 +637,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 +672,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 +697,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 +742,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 +755,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 +765,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 +778,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 +803,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 +822,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 +833,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 +842,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 +857,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 +871,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 +890,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 +907,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 +925,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 +947,16 @@ 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) {}
TupleType(TupleType&&) = default;
TupleType& operator=(TupleType&) = default;
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 +965,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 +1026,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 +1053,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 +1093,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 +1106,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 +1142,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 +1238,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 +1271,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 +1298,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 +1324,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 +1356,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 +1389,6 @@ private:
Kind m_kind;
/// Contract type used for contract metadata magic.
TypePointer m_typeArgument;
};
/**
@@ -1386,12 +1398,14 @@ private:
class InaccessibleDynamicType: public Type
{
public:
InaccessibleDynamicType() = default;
Category category() const override { return Category::InaccessibleDynamic; }
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 +1413,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;
};
}