/* 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." ); } } Type const* 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(); } 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(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(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, 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); }