/*
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 .
*/
// SPDX-License-Identifier: GPL-3.0
#include
#include
#include
#include
using namespace std;
using namespace solidity;
using namespace solidity::frontend;
using namespace solidity::util;
BoolType const TypeProvider::m_boolean{};
InaccessibleDynamicType const TypeProvider::m_inaccessibleDynamic{};
/// 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.
unique_ptr TypeProvider::m_bytesStorage;
unique_ptr TypeProvider::m_bytesMemory;
unique_ptr TypeProvider::m_bytesCalldata;
unique_ptr TypeProvider::m_stringStorage;
unique_ptr TypeProvider::m_stringMemory;
TupleType const TypeProvider::m_emptyTuple{};
AddressType const TypeProvider::m_payableAddress{StateMutability::Payable};
AddressType const TypeProvider::m_address{StateMutability::NonPayable};
array, 32> const TypeProvider::m_intM{{
{make_unique(8 * 1, IntegerType::Modifier::Signed)},
{make_unique(8 * 2, IntegerType::Modifier::Signed)},
{make_unique(8 * 3, IntegerType::Modifier::Signed)},
{make_unique(8 * 4, IntegerType::Modifier::Signed)},
{make_unique(8 * 5, IntegerType::Modifier::Signed)},
{make_unique(8 * 6, IntegerType::Modifier::Signed)},
{make_unique(8 * 7, IntegerType::Modifier::Signed)},
{make_unique(8 * 8, IntegerType::Modifier::Signed)},
{make_unique(8 * 9, IntegerType::Modifier::Signed)},
{make_unique(8 * 10, IntegerType::Modifier::Signed)},
{make_unique(8 * 11, IntegerType::Modifier::Signed)},
{make_unique(8 * 12, IntegerType::Modifier::Signed)},
{make_unique(8 * 13, IntegerType::Modifier::Signed)},
{make_unique(8 * 14, IntegerType::Modifier::Signed)},
{make_unique(8 * 15, IntegerType::Modifier::Signed)},
{make_unique(8 * 16, IntegerType::Modifier::Signed)},
{make_unique(8 * 17, IntegerType::Modifier::Signed)},
{make_unique(8 * 18, IntegerType::Modifier::Signed)},
{make_unique(8 * 19, IntegerType::Modifier::Signed)},
{make_unique(8 * 20, IntegerType::Modifier::Signed)},
{make_unique(8 * 21, IntegerType::Modifier::Signed)},
{make_unique(8 * 22, IntegerType::Modifier::Signed)},
{make_unique(8 * 23, IntegerType::Modifier::Signed)},
{make_unique(8 * 24, IntegerType::Modifier::Signed)},
{make_unique(8 * 25, IntegerType::Modifier::Signed)},
{make_unique(8 * 26, IntegerType::Modifier::Signed)},
{make_unique(8 * 27, IntegerType::Modifier::Signed)},
{make_unique(8 * 28, IntegerType::Modifier::Signed)},
{make_unique(8 * 29, IntegerType::Modifier::Signed)},
{make_unique(8 * 30, IntegerType::Modifier::Signed)},
{make_unique(8 * 31, IntegerType::Modifier::Signed)},
{make_unique(8 * 32, IntegerType::Modifier::Signed)}
}};
array, 32> const TypeProvider::m_uintM{{
{make_unique(8 * 1, IntegerType::Modifier::Unsigned)},
{make_unique(8 * 2, IntegerType::Modifier::Unsigned)},
{make_unique(8 * 3, IntegerType::Modifier::Unsigned)},
{make_unique(8 * 4, IntegerType::Modifier::Unsigned)},
{make_unique(8 * 5, IntegerType::Modifier::Unsigned)},
{make_unique(8 * 6, IntegerType::Modifier::Unsigned)},
{make_unique(8 * 7, IntegerType::Modifier::Unsigned)},
{make_unique(8 * 8, IntegerType::Modifier::Unsigned)},
{make_unique(8 * 9, IntegerType::Modifier::Unsigned)},
{make_unique(8 * 10, IntegerType::Modifier::Unsigned)},
{make_unique(8 * 11, IntegerType::Modifier::Unsigned)},
{make_unique(8 * 12, IntegerType::Modifier::Unsigned)},
{make_unique(8 * 13, IntegerType::Modifier::Unsigned)},
{make_unique(8 * 14, IntegerType::Modifier::Unsigned)},
{make_unique(8 * 15, IntegerType::Modifier::Unsigned)},
{make_unique(8 * 16, IntegerType::Modifier::Unsigned)},
{make_unique(8 * 17, IntegerType::Modifier::Unsigned)},
{make_unique(8 * 18, IntegerType::Modifier::Unsigned)},
{make_unique(8 * 19, IntegerType::Modifier::Unsigned)},
{make_unique(8 * 20, IntegerType::Modifier::Unsigned)},
{make_unique(8 * 21, IntegerType::Modifier::Unsigned)},
{make_unique(8 * 22, IntegerType::Modifier::Unsigned)},
{make_unique(8 * 23, IntegerType::Modifier::Unsigned)},
{make_unique(8 * 24, IntegerType::Modifier::Unsigned)},
{make_unique(8 * 25, IntegerType::Modifier::Unsigned)},
{make_unique(8 * 26, IntegerType::Modifier::Unsigned)},
{make_unique(8 * 27, IntegerType::Modifier::Unsigned)},
{make_unique(8 * 28, IntegerType::Modifier::Unsigned)},
{make_unique(8 * 29, IntegerType::Modifier::Unsigned)},
{make_unique(8 * 30, IntegerType::Modifier::Unsigned)},
{make_unique(8 * 31, IntegerType::Modifier::Unsigned)},
{make_unique(8 * 32, IntegerType::Modifier::Unsigned)}
}};
array, 32> const TypeProvider::m_bytesM{{
{make_unique(1)},
{make_unique(2)},
{make_unique(3)},
{make_unique(4)},
{make_unique(5)},
{make_unique(6)},
{make_unique(7)},
{make_unique(8)},
{make_unique(9)},
{make_unique(10)},
{make_unique(11)},
{make_unique(12)},
{make_unique(13)},
{make_unique(14)},
{make_unique(15)},
{make_unique(16)},
{make_unique(17)},
{make_unique(18)},
{make_unique(19)},
{make_unique(20)},
{make_unique(21)},
{make_unique(22)},
{make_unique(23)},
{make_unique(24)},
{make_unique(25)},
{make_unique(26)},
{make_unique(27)},
{make_unique(28)},
{make_unique(29)},
{make_unique(30)},
{make_unique(31)},
{make_unique(32)}
}};
array, 4> const TypeProvider::m_magics{{
{make_unique(MagicType::Kind::Block)},
{make_unique(MagicType::Kind::Message)},
{make_unique(MagicType::Kind::Transaction)},
{make_unique(MagicType::Kind::ABI)}
// MetaType is stored separately
}};
inline void clearCache(Type const& type)
{
type.clearCache();
}
template
inline void clearCache(unique_ptr const& type)
{
// Some lazy-initialized types might not exist yet.
if (type)
type->clearCache();
}
template
inline void clearCaches(Container& container)
{
for (auto const& e: container)
clearCache(e);
}
void TypeProvider::reset()
{
clearCache(m_boolean);
clearCache(m_inaccessibleDynamic);
clearCache(m_bytesStorage);
clearCache(m_bytesMemory);
clearCache(m_bytesCalldata);
clearCache(m_stringStorage);
clearCache(m_stringMemory);
clearCache(m_emptyTuple);
clearCache(m_payableAddress);
clearCache(m_address);
clearCaches(instance().m_intM);
clearCaches(instance().m_uintM);
clearCaches(instance().m_bytesM);
clearCaches(instance().m_magics);
instance().m_generalTypes.clear();
instance().m_stringLiteralTypes.clear();
instance().m_ufixedMxN.clear();
instance().m_fixedMxN.clear();
}
template
inline T const* TypeProvider::createAndGet(Args&& ... _args)
{
instance().m_generalTypes.emplace_back(make_unique(std::forward(_args)...));
return static_cast(instance().m_generalTypes.back().get());
}
Type const* TypeProvider::fromElementaryTypeName(ElementaryTypeNameToken const& _type, std::optional _stateMutability)
{
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 integer(m, IntegerType::Modifier::Signed);
case Token::UIntM:
return integer(m, IntegerType::Modifier::Unsigned);
case Token::Byte:
return byte();
case Token::BytesM:
return fixedBytes(m);
case Token::FixedMxN:
return fixedPoint(m, n, FixedPointType::Modifier::Signed);
case Token::UFixedMxN:
return fixedPoint(m, n, FixedPointType::Modifier::Unsigned);
case Token::Int:
return integer(256, IntegerType::Modifier::Signed);
case Token::UInt:
return integer(256, IntegerType::Modifier::Unsigned);
case Token::Fixed:
return fixedPoint(128, 18, FixedPointType::Modifier::Signed);
case Token::UFixed:
return fixedPoint(128, 18, FixedPointType::Modifier::Unsigned);
case Token::Address:
{
if (_stateMutability)
{
solAssert(*_stateMutability == StateMutability::Payable, "");
return payableAddress();
}
return address();
}
case Token::Bool:
return boolean();
case Token::Bytes:
return bytesStorage();
case Token::String:
return stringStorage();
default:
solAssert(
false,
"Unable to convert elementary typename " + _type.toString() + " to type."
);
}
}
TypePointer TypeProvider::fromElementaryTypeName(string const& _name)
{
vector 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(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 payableAddress();
else
solAssert(false, "Invalid state mutability for address type: " + nameParts[1]);
}
return address();
}
else
{
solAssert(nameParts.size() == 1, "Storage location suffix only allowed for reference types");
return t;
}
}
ArrayType const* TypeProvider::bytesStorage()
{
if (!m_bytesStorage)
m_bytesStorage = make_unique(DataLocation::Storage, false);
return m_bytesStorage.get();
}
ArrayType const* TypeProvider::bytesMemory()
{
if (!m_bytesMemory)
m_bytesMemory = make_unique(DataLocation::Memory, false);
return m_bytesMemory.get();
}
ArrayType const* TypeProvider::bytesCalldata()
{
if (!m_bytesCalldata)
m_bytesCalldata = make_unique(DataLocation::CallData, false);
return m_bytesCalldata.get();
}
ArrayType const* TypeProvider::stringStorage()
{
if (!m_stringStorage)
m_stringStorage = make_unique(DataLocation::Storage, true);
return m_stringStorage.get();
}
ArrayType const* TypeProvider::stringMemory()
{
if (!m_stringMemory)
m_stringMemory = make_unique(DataLocation::Memory, true);
return m_stringMemory.get();
}
TypePointer TypeProvider::forLiteral(Literal const& _literal)
{
switch (_literal.token())
{
case Token::TrueLiteral:
case Token::FalseLiteral:
return boolean();
case Token::Number:
return rationalNumber(_literal);
case Token::StringLiteral:
case Token::UnicodeStringLiteral:
case Token::HexStringLiteral:
return stringLiteral(_literal.value());
default:
return nullptr;
}
}
RationalNumberType const* TypeProvider::rationalNumber(Literal const& _literal)
{
solAssert(_literal.token() == Token::Number, "");
std::tuple 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 = fixedBytes(static_cast(digitCount / 2));
}
return rationalNumber(std::get<1>(validLiteral), compatibleBytesType);
}
return nullptr;
}
StringLiteralType const* TypeProvider::stringLiteral(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(literal)).first->second.get();
}
FixedPointType const* TypeProvider::fixedPoint(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(m, n, _modifier)
).first->second.get();
}
TupleType const* TypeProvider::tuple(vector members)
{
if (members.empty())
return &m_emptyTuple;
return createAndGet(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(instance().m_generalTypes.back().get());
}
FunctionType const* TypeProvider::function(FunctionDefinition const& _function, FunctionType::Kind _kind)
{
return createAndGet(_function, _kind);
}
FunctionType const* TypeProvider::function(VariableDeclaration const& _varDecl)
{
return createAndGet(_varDecl);
}
FunctionType const* TypeProvider::function(EventDefinition const& _def)
{
return createAndGet(_def);
}
FunctionType const* TypeProvider::function(FunctionTypeName const& _typeName)
{
return createAndGet(_typeName);
}
FunctionType const* TypeProvider::function(
strings const& _parameterTypes,
strings const& _returnParameterTypes,
FunctionType::Kind _kind,
bool _arbitraryParameters,
StateMutability _stateMutability
)
{
return createAndGet(
_parameterTypes, _returnParameterTypes,
_kind, _arbitraryParameters, _stateMutability
);
}
FunctionType const* TypeProvider::function(
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,
bool _saltSet
)
{
return createAndGet(
_parameterTypes,
_returnParameterTypes,
_parameterNames,
_returnParameterNames,
_kind,
_arbitraryParameters,
_stateMutability,
_declaration,
_gasSet,
_valueSet,
_bound,
_saltSet
);
}
RationalNumberType const* TypeProvider::rationalNumber(rational const& _value, Type const* _compatibleBytesType)
{
return createAndGet(_value, _compatibleBytesType);
}
ArrayType const* TypeProvider::array(DataLocation _location, bool _isString)
{
if (_isString)
{
if (_location == DataLocation::Storage)
return stringStorage();
if (_location == DataLocation::Memory)
return stringMemory();
}
else
{
if (_location == DataLocation::Storage)
return bytesStorage();
if (_location == DataLocation::Memory)
return bytesMemory();
}
return createAndGet(_location, _isString);
}
ArrayType const* TypeProvider::array(DataLocation _location, Type const* _baseType)
{
return createAndGet(_location, _baseType);
}
ArrayType const* TypeProvider::array(DataLocation _location, Type const* _baseType, u256 const& _length)
{
return createAndGet(_location, _baseType, _length);
}
ArraySliceType const* TypeProvider::arraySlice(ArrayType const& _arrayType)
{
return createAndGet(_arrayType);
}
ContractType const* TypeProvider::contract(ContractDefinition const& _contractDef, bool _isSuper)
{
return createAndGet(_contractDef, _isSuper);
}
EnumType const* TypeProvider::enumType(EnumDefinition const& _enumDef)
{
return createAndGet(_enumDef);
}
ModuleType const* TypeProvider::module(SourceUnit const& _source)
{
return createAndGet(_source);
}
TypeType const* TypeProvider::typeType(Type const* _actualType)
{
return createAndGet(_actualType);
}
StructType const* TypeProvider::structType(StructDefinition const& _struct, DataLocation _location)
{
return createAndGet(_struct, _location);
}
ModifierType const* TypeProvider::modifier(ModifierDefinition const& _def)
{
return createAndGet(_def);
}
MagicType const* TypeProvider::magic(MagicType::Kind _kind)
{
solAssert(_kind != MagicType::Kind::MetaType, "MetaType is handled separately");
return m_magics.at(static_cast(_kind)).get();
}
MagicType const* TypeProvider::meta(Type const* _type)
{
solAssert(
_type && (
_type->category() == Type::Category::Contract ||
_type->category() == Type::Category::Integer
),
"Only contracts or integer types supported for now."
);
return createAndGet(_type);
}
MappingType const* TypeProvider::mapping(Type const* _keyType, Type const* _valueType)
{
return createAndGet(_keyType, _valueType);
}