/* 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 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. std::unique_ptr TypeProvider::m_bytesStorage; std::unique_ptr TypeProvider::m_bytesMemory; std::unique_ptr TypeProvider::m_bytesCalldata; std::unique_ptr TypeProvider::m_stringStorage; std::unique_ptr TypeProvider::m_stringMemory; TupleType const TypeProvider::m_emptyTuple{}; AddressType const TypeProvider::m_payableAddress{StateMutability::Payable}; AddressType const TypeProvider::m_address{StateMutability::NonPayable}; std::array, 32> const TypeProvider::m_intM{{ {std::make_unique(8 * 1, IntegerType::Modifier::Signed)}, {std::make_unique(8 * 2, IntegerType::Modifier::Signed)}, {std::make_unique(8 * 3, IntegerType::Modifier::Signed)}, {std::make_unique(8 * 4, IntegerType::Modifier::Signed)}, {std::make_unique(8 * 5, IntegerType::Modifier::Signed)}, {std::make_unique(8 * 6, IntegerType::Modifier::Signed)}, {std::make_unique(8 * 7, IntegerType::Modifier::Signed)}, {std::make_unique(8 * 8, IntegerType::Modifier::Signed)}, {std::make_unique(8 * 9, IntegerType::Modifier::Signed)}, {std::make_unique(8 * 10, IntegerType::Modifier::Signed)}, {std::make_unique(8 * 11, IntegerType::Modifier::Signed)}, {std::make_unique(8 * 12, IntegerType::Modifier::Signed)}, {std::make_unique(8 * 13, IntegerType::Modifier::Signed)}, {std::make_unique(8 * 14, IntegerType::Modifier::Signed)}, {std::make_unique(8 * 15, IntegerType::Modifier::Signed)}, {std::make_unique(8 * 16, IntegerType::Modifier::Signed)}, {std::make_unique(8 * 17, IntegerType::Modifier::Signed)}, {std::make_unique(8 * 18, IntegerType::Modifier::Signed)}, {std::make_unique(8 * 19, IntegerType::Modifier::Signed)}, {std::make_unique(8 * 20, IntegerType::Modifier::Signed)}, {std::make_unique(8 * 21, IntegerType::Modifier::Signed)}, {std::make_unique(8 * 22, IntegerType::Modifier::Signed)}, {std::make_unique(8 * 23, IntegerType::Modifier::Signed)}, {std::make_unique(8 * 24, IntegerType::Modifier::Signed)}, {std::make_unique(8 * 25, IntegerType::Modifier::Signed)}, {std::make_unique(8 * 26, IntegerType::Modifier::Signed)}, {std::make_unique(8 * 27, IntegerType::Modifier::Signed)}, {std::make_unique(8 * 28, IntegerType::Modifier::Signed)}, {std::make_unique(8 * 29, IntegerType::Modifier::Signed)}, {std::make_unique(8 * 30, IntegerType::Modifier::Signed)}, {std::make_unique(8 * 31, IntegerType::Modifier::Signed)}, {std::make_unique(8 * 32, IntegerType::Modifier::Signed)} }}; std::array, 32> const TypeProvider::m_uintM{{ {std::make_unique(8 * 1, IntegerType::Modifier::Unsigned)}, {std::make_unique(8 * 2, IntegerType::Modifier::Unsigned)}, {std::make_unique(8 * 3, IntegerType::Modifier::Unsigned)}, {std::make_unique(8 * 4, IntegerType::Modifier::Unsigned)}, {std::make_unique(8 * 5, IntegerType::Modifier::Unsigned)}, {std::make_unique(8 * 6, IntegerType::Modifier::Unsigned)}, {std::make_unique(8 * 7, IntegerType::Modifier::Unsigned)}, {std::make_unique(8 * 8, IntegerType::Modifier::Unsigned)}, {std::make_unique(8 * 9, IntegerType::Modifier::Unsigned)}, {std::make_unique(8 * 10, IntegerType::Modifier::Unsigned)}, {std::make_unique(8 * 11, IntegerType::Modifier::Unsigned)}, {std::make_unique(8 * 12, IntegerType::Modifier::Unsigned)}, {std::make_unique(8 * 13, IntegerType::Modifier::Unsigned)}, {std::make_unique(8 * 14, IntegerType::Modifier::Unsigned)}, {std::make_unique(8 * 15, IntegerType::Modifier::Unsigned)}, {std::make_unique(8 * 16, IntegerType::Modifier::Unsigned)}, {std::make_unique(8 * 17, IntegerType::Modifier::Unsigned)}, {std::make_unique(8 * 18, IntegerType::Modifier::Unsigned)}, {std::make_unique(8 * 19, IntegerType::Modifier::Unsigned)}, {std::make_unique(8 * 20, IntegerType::Modifier::Unsigned)}, {std::make_unique(8 * 21, IntegerType::Modifier::Unsigned)}, {std::make_unique(8 * 22, IntegerType::Modifier::Unsigned)}, {std::make_unique(8 * 23, IntegerType::Modifier::Unsigned)}, {std::make_unique(8 * 24, IntegerType::Modifier::Unsigned)}, {std::make_unique(8 * 25, IntegerType::Modifier::Unsigned)}, {std::make_unique(8 * 26, IntegerType::Modifier::Unsigned)}, {std::make_unique(8 * 27, IntegerType::Modifier::Unsigned)}, {std::make_unique(8 * 28, IntegerType::Modifier::Unsigned)}, {std::make_unique(8 * 29, IntegerType::Modifier::Unsigned)}, {std::make_unique(8 * 30, IntegerType::Modifier::Unsigned)}, {std::make_unique(8 * 31, IntegerType::Modifier::Unsigned)}, {std::make_unique(8 * 32, IntegerType::Modifier::Unsigned)} }}; std::array, 32> const TypeProvider::m_bytesM{{ {std::make_unique(1)}, {std::make_unique(2)}, {std::make_unique(3)}, {std::make_unique(4)}, {std::make_unique(5)}, {std::make_unique(6)}, {std::make_unique(7)}, {std::make_unique(8)}, {std::make_unique(9)}, {std::make_unique(10)}, {std::make_unique(11)}, {std::make_unique(12)}, {std::make_unique(13)}, {std::make_unique(14)}, {std::make_unique(15)}, {std::make_unique(16)}, {std::make_unique(17)}, {std::make_unique(18)}, {std::make_unique(19)}, {std::make_unique(20)}, {std::make_unique(21)}, {std::make_unique(22)}, {std::make_unique(23)}, {std::make_unique(24)}, {std::make_unique(25)}, {std::make_unique(26)}, {std::make_unique(27)}, {std::make_unique(28)}, {std::make_unique(29)}, {std::make_unique(30)}, {std::make_unique(31)}, {std::make_unique(32)} }}; std::array, 4> const TypeProvider::m_magics{{ {std::make_unique(MagicType::Kind::Block)}, {std::make_unique(MagicType::Kind::Message)}, {std::make_unique(MagicType::Kind::Transaction)}, {std::make_unique(MagicType::Kind::ABI)} // MetaType is stored separately }}; inline void clearCache(Type const& type) { type.clearCache(); } template inline void clearCache(std::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(std::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." ); } } Type const* TypeProvider::fromElementaryTypeName(std::string const& _name) { std::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; std::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 = std::make_unique(DataLocation::Storage, false); return m_bytesStorage.get(); } ArrayType const* TypeProvider::bytesMemory() { if (!m_bytesMemory) m_bytesMemory = std::make_unique(DataLocation::Memory, false); return m_bytesMemory.get(); } ArrayType const* TypeProvider::bytesCalldata() { if (!m_bytesCalldata) m_bytesCalldata = std::make_unique(DataLocation::CallData, false); return m_bytesCalldata.get(); } ArrayType const* TypeProvider::stringStorage() { if (!m_stringStorage) m_stringStorage = std::make_unique(DataLocation::Storage, true); return m_stringStorage.get(); } ArrayType const* TypeProvider::stringMemory() { if (!m_stringMemory) m_stringMemory = std::make_unique(DataLocation::Memory, true); return m_stringMemory.get(); } Type const* 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)) { Type const* 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(std::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, std::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(std::make_pair(m, n)); if (i != map.end()) return i->second.get(); return map.emplace( std::make_pair(m, n), std::make_unique(m, n, _modifier) ).first->second.get(); } TupleType const* TypeProvider::tuple(std::vector members) { if (members.empty()) return &m_emptyTuple; return createAndGet(std::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(ErrorDefinition 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, StateMutability _stateMutability, FunctionType::Options _options ) { // Can only use this constructor for "arbitraryParameters". solAssert(!_options.valueSet && !_options.gasSet && !_options.saltSet && !_options.hasBoundFirstArgument); return createAndGet( _parameterTypes, _returnParameterTypes, _kind, _stateMutability, std::move(_options) ); } FunctionType const* TypeProvider::function( TypePointers const& _parameterTypes, TypePointers const& _returnParameterTypes, strings _parameterNames, strings _returnParameterNames, FunctionType::Kind _kind, StateMutability _stateMutability, Declaration const* _declaration, FunctionType::Options _options ) { return createAndGet( _parameterTypes, _returnParameterTypes, _parameterNames, _returnParameterNames, _kind, _stateMutability, _declaration, std::move(_options) ); } 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 || _type->category() == Type::Category::Enum ), "Only enum, contracts or integer types supported for now." ); return createAndGet(_type); } MappingType const* TypeProvider::mapping(Type const* _keyType, ASTString _keyName, Type const* _valueType, ASTString _valueName) { return createAndGet(_keyType, _keyName, _valueType, _valueName); } UserDefinedValueType const* TypeProvider::userDefinedValueType(UserDefinedValueTypeDefinition const& _definition) { return createAndGet(_definition); }