mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #6417 from ethereum/memleaks
Type System API refactor
This commit is contained in:
commit
b8ad8fb15e
@ -47,6 +47,8 @@ set(sources
|
||||
ast/ExperimentalFeatures.h
|
||||
ast/Types.cpp
|
||||
ast/Types.h
|
||||
ast/TypeProvider.cpp
|
||||
ast/TypeProvider.h
|
||||
codegen/ABIFunctions.cpp
|
||||
codegen/ABIFunctions.h
|
||||
codegen/ArrayUtils.cpp
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <libsolidity/analysis/ConstantEvaluator.h>
|
||||
|
||||
#include <libsolidity/ast/AST.h>
|
||||
#include <libsolidity/ast/TypeProvider.h>
|
||||
#include <liblangutil/ErrorReporter.h>
|
||||
|
||||
using namespace std;
|
||||
@ -56,7 +57,7 @@ void ConstantEvaluator::endVisit(BinaryOperation const& _operation)
|
||||
setType(
|
||||
_operation,
|
||||
TokenTraits::isCompareOp(_operation.getOperator()) ?
|
||||
make_shared<BoolType>() :
|
||||
TypeProvider::boolType() :
|
||||
commonType
|
||||
);
|
||||
}
|
||||
@ -64,7 +65,7 @@ void ConstantEvaluator::endVisit(BinaryOperation const& _operation)
|
||||
|
||||
void ConstantEvaluator::endVisit(Literal const& _literal)
|
||||
{
|
||||
setType(_literal, Type::forLiteral(_literal));
|
||||
setType(_literal, TypeProvider::forLiteral(_literal));
|
||||
}
|
||||
|
||||
void ConstantEvaluator::endVisit(Identifier const& _identifier)
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <libsolidity/analysis/ContractLevelChecker.h>
|
||||
|
||||
#include <libsolidity/ast/AST.h>
|
||||
#include <libsolidity/ast/TypeProvider.h>
|
||||
#include <libsolidity/analysis/TypeChecker.h>
|
||||
#include <liblangutil/ErrorReporter.h>
|
||||
#include <boost/range/adaptor/reversed.hpp>
|
||||
@ -244,13 +245,13 @@ void ContractLevelChecker::checkAbstractFunctions(ContractDefinition const& _con
|
||||
{
|
||||
for (VariableDeclaration const* v: contract->stateVariables())
|
||||
if (v->isPartOfExternalInterface())
|
||||
registerFunction(*v, make_shared<FunctionType>(*v), true);
|
||||
registerFunction(*v, TypeProvider::functionType(*v), true);
|
||||
|
||||
for (FunctionDefinition const* function: contract->definedFunctions())
|
||||
if (!function->isConstructor())
|
||||
registerFunction(
|
||||
*function,
|
||||
make_shared<FunctionType>(*function)->asCallableFunction(false),
|
||||
TypeProvider::functionType(*function)->asCallableFunction(false),
|
||||
function->isImplemented()
|
||||
);
|
||||
}
|
||||
@ -407,7 +408,7 @@ void ContractLevelChecker::checkExternalTypeClashes(ContractDefinition const& _c
|
||||
for (FunctionDefinition const* f: contract->definedFunctions())
|
||||
if (f->isPartOfExternalInterface())
|
||||
{
|
||||
auto functionType = make_shared<FunctionType>(*f);
|
||||
auto functionType = TypeProvider::functionType(*f);
|
||||
// under non error circumstances this should be true
|
||||
if (functionType->interfaceFunctionType())
|
||||
externalDeclarations[functionType->externalSignature()].emplace_back(
|
||||
@ -417,7 +418,7 @@ void ContractLevelChecker::checkExternalTypeClashes(ContractDefinition const& _c
|
||||
for (VariableDeclaration const* v: contract->stateVariables())
|
||||
if (v->isPartOfExternalInterface())
|
||||
{
|
||||
auto functionType = make_shared<FunctionType>(*v);
|
||||
auto functionType = TypeProvider::functionType(*v);
|
||||
// under non error circumstances this should be true
|
||||
if (functionType->interfaceFunctionType())
|
||||
externalDeclarations[functionType->externalSignature()].emplace_back(
|
||||
|
@ -235,7 +235,7 @@ bool ControlFlowBuilder::visit(FunctionCall const& _functionCall)
|
||||
solAssert(!!m_currentNode, "");
|
||||
solAssert(!!_functionCall.expression().annotation().type, "");
|
||||
|
||||
if (auto functionType = dynamic_pointer_cast<FunctionType const>(_functionCall.expression().annotation().type))
|
||||
if (auto functionType = dynamic_cast<FunctionType const*>(_functionCall.expression().annotation().type))
|
||||
switch (functionType->kind())
|
||||
{
|
||||
case FunctionType::Kind::Revert:
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <libsolidity/analysis/GlobalContext.h>
|
||||
|
||||
#include <libsolidity/ast/AST.h>
|
||||
#include <libsolidity/ast/TypeProvider.h>
|
||||
#include <libsolidity/ast/Types.h>
|
||||
#include <memory>
|
||||
|
||||
@ -34,42 +35,50 @@ namespace dev
|
||||
namespace solidity
|
||||
{
|
||||
|
||||
GlobalContext::GlobalContext():
|
||||
m_magicVariables(vector<shared_ptr<MagicVariableDeclaration const>>{
|
||||
make_shared<MagicVariableDeclaration>("abi", make_shared<MagicType>(MagicType::Kind::ABI)),
|
||||
make_shared<MagicVariableDeclaration>("addmod", make_shared<FunctionType>(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Kind::AddMod, false, StateMutability::Pure)),
|
||||
make_shared<MagicVariableDeclaration>("assert", make_shared<FunctionType>(strings{"bool"}, strings{}, FunctionType::Kind::Assert, false, StateMutability::Pure)),
|
||||
make_shared<MagicVariableDeclaration>("block", make_shared<MagicType>(MagicType::Kind::Block)),
|
||||
make_shared<MagicVariableDeclaration>("blockhash", make_shared<FunctionType>(strings{"uint256"}, strings{"bytes32"}, FunctionType::Kind::BlockHash, false, StateMutability::View)),
|
||||
make_shared<MagicVariableDeclaration>("ecrecover", make_shared<FunctionType>(strings{"bytes32", "uint8", "bytes32", "bytes32"}, strings{"address"}, FunctionType::Kind::ECRecover, false, StateMutability::Pure)),
|
||||
make_shared<MagicVariableDeclaration>("gasleft", make_shared<FunctionType>(strings(), strings{"uint256"}, FunctionType::Kind::GasLeft, false, StateMutability::View)),
|
||||
make_shared<MagicVariableDeclaration>("keccak256", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::KECCAK256, false, StateMutability::Pure)),
|
||||
make_shared<MagicVariableDeclaration>("log0", make_shared<FunctionType>(strings{"bytes32"}, strings{}, FunctionType::Kind::Log0)),
|
||||
make_shared<MagicVariableDeclaration>("log1", make_shared<FunctionType>(strings{"bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log1)),
|
||||
make_shared<MagicVariableDeclaration>("log2", make_shared<FunctionType>(strings{"bytes32", "bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log2)),
|
||||
make_shared<MagicVariableDeclaration>("log3", make_shared<FunctionType>(strings{"bytes32", "bytes32", "bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log3)),
|
||||
make_shared<MagicVariableDeclaration>("log4", make_shared<FunctionType>(strings{"bytes32", "bytes32", "bytes32", "bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log4)),
|
||||
make_shared<MagicVariableDeclaration>("msg", make_shared<MagicType>(MagicType::Kind::Message)),
|
||||
make_shared<MagicVariableDeclaration>("mulmod", make_shared<FunctionType>(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Kind::MulMod, false, StateMutability::Pure)),
|
||||
make_shared<MagicVariableDeclaration>("now", make_shared<IntegerType>(256)),
|
||||
make_shared<MagicVariableDeclaration>("require", make_shared<FunctionType>(strings{"bool"}, strings{}, FunctionType::Kind::Require, false, StateMutability::Pure)),
|
||||
make_shared<MagicVariableDeclaration>("require", make_shared<FunctionType>(strings{"bool", "string memory"}, strings{}, FunctionType::Kind::Require, false, StateMutability::Pure)),
|
||||
make_shared<MagicVariableDeclaration>("revert", make_shared<FunctionType>(strings(), strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)),
|
||||
make_shared<MagicVariableDeclaration>("revert", make_shared<FunctionType>(strings{"string memory"}, strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)),
|
||||
make_shared<MagicVariableDeclaration>("ripemd160", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bytes20"}, FunctionType::Kind::RIPEMD160, false, StateMutability::Pure)),
|
||||
make_shared<MagicVariableDeclaration>("selfdestruct", make_shared<FunctionType>(strings{"address payable"}, strings{}, FunctionType::Kind::Selfdestruct)),
|
||||
make_shared<MagicVariableDeclaration>("sha256", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::SHA256, false, StateMutability::Pure)),
|
||||
make_shared<MagicVariableDeclaration>("sha3", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::KECCAK256, false, StateMutability::Pure)),
|
||||
make_shared<MagicVariableDeclaration>("suicide", make_shared<FunctionType>(strings{"address payable"}, strings{}, FunctionType::Kind::Selfdestruct)),
|
||||
make_shared<MagicVariableDeclaration>("tx", make_shared<MagicType>(MagicType::Kind::Transaction)),
|
||||
make_shared<MagicVariableDeclaration>("type", make_shared<FunctionType>(
|
||||
strings{"address"} /* accepts any contract type, handled by the type checker */,
|
||||
strings{} /* returns a MagicType, handled by the type checker */,
|
||||
FunctionType::Kind::MetaType,
|
||||
false,
|
||||
StateMutability::Pure
|
||||
)),
|
||||
})
|
||||
inline vector<shared_ptr<MagicVariableDeclaration const>> constructMagicVariables()
|
||||
{
|
||||
static auto const magicVarDecl = [](string const& _name, Type const* _type) {
|
||||
return make_shared<MagicVariableDeclaration>(_name, _type);
|
||||
};
|
||||
|
||||
return {
|
||||
magicVarDecl("abi", TypeProvider::magicType(MagicType::Kind::ABI)),
|
||||
magicVarDecl("addmod", TypeProvider::functionType(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Kind::AddMod, false, StateMutability::Pure)),
|
||||
magicVarDecl("assert", TypeProvider::functionType(strings{"bool"}, strings{}, FunctionType::Kind::Assert, false, StateMutability::Pure)),
|
||||
magicVarDecl("block", TypeProvider::magicType(MagicType::Kind::Block)),
|
||||
magicVarDecl("blockhash", TypeProvider::functionType(strings{"uint256"}, strings{"bytes32"}, FunctionType::Kind::BlockHash, false, StateMutability::View)),
|
||||
magicVarDecl("ecrecover", TypeProvider::functionType(strings{"bytes32", "uint8", "bytes32", "bytes32"}, strings{"address"}, FunctionType::Kind::ECRecover, false, StateMutability::Pure)),
|
||||
magicVarDecl("gasleft", TypeProvider::functionType(strings(), strings{"uint256"}, FunctionType::Kind::GasLeft, false, StateMutability::View)),
|
||||
magicVarDecl("keccak256", TypeProvider::functionType(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::KECCAK256, false, StateMutability::Pure)),
|
||||
magicVarDecl("log0", TypeProvider::functionType(strings{"bytes32"}, strings{}, FunctionType::Kind::Log0)),
|
||||
magicVarDecl("log1", TypeProvider::functionType(strings{"bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log1)),
|
||||
magicVarDecl("log2", TypeProvider::functionType(strings{"bytes32", "bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log2)),
|
||||
magicVarDecl("log3", TypeProvider::functionType(strings{"bytes32", "bytes32", "bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log3)),
|
||||
magicVarDecl("log4", TypeProvider::functionType(strings{"bytes32", "bytes32", "bytes32", "bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log4)),
|
||||
magicVarDecl("msg", TypeProvider::magicType(MagicType::Kind::Message)),
|
||||
magicVarDecl("mulmod", TypeProvider::functionType(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Kind::MulMod, false, StateMutability::Pure)),
|
||||
magicVarDecl("now", TypeProvider::uint256()),
|
||||
magicVarDecl("require", TypeProvider::functionType(strings{"bool"}, strings{}, FunctionType::Kind::Require, false, StateMutability::Pure)),
|
||||
magicVarDecl("require", TypeProvider::functionType(strings{"bool", "string memory"}, strings{}, FunctionType::Kind::Require, false, StateMutability::Pure)),
|
||||
magicVarDecl("revert", TypeProvider::functionType(strings(), strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)),
|
||||
magicVarDecl("revert", TypeProvider::functionType(strings{"string memory"}, strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)),
|
||||
magicVarDecl("ripemd160", TypeProvider::functionType(strings{"bytes memory"}, strings{"bytes20"}, FunctionType::Kind::RIPEMD160, false, StateMutability::Pure)),
|
||||
magicVarDecl("selfdestruct", TypeProvider::functionType(strings{"address payable"}, strings{}, FunctionType::Kind::Selfdestruct)),
|
||||
magicVarDecl("sha256", TypeProvider::functionType(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::SHA256, false, StateMutability::Pure)),
|
||||
magicVarDecl("sha3", TypeProvider::functionType(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::KECCAK256, false, StateMutability::Pure)),
|
||||
magicVarDecl("suicide", TypeProvider::functionType(strings{"address payable"}, strings{}, FunctionType::Kind::Selfdestruct)),
|
||||
magicVarDecl("tx", TypeProvider::magicType(MagicType::Kind::Transaction)),
|
||||
magicVarDecl("type", TypeProvider::functionType(
|
||||
strings{"address"} /* accepts any contract type, handled by the type checker */,
|
||||
strings{} /* returns a MagicType, handled by the type checker */,
|
||||
FunctionType::Kind::MetaType,
|
||||
false,
|
||||
StateMutability::Pure
|
||||
)),
|
||||
};
|
||||
}
|
||||
|
||||
GlobalContext::GlobalContext(): m_magicVariables{constructMagicVariables()}
|
||||
{
|
||||
}
|
||||
|
||||
@ -90,7 +99,7 @@ vector<Declaration const*> GlobalContext::declarations() const
|
||||
MagicVariableDeclaration const* GlobalContext::currentThis() const
|
||||
{
|
||||
if (!m_thisPointer[m_currentContract])
|
||||
m_thisPointer[m_currentContract] = make_shared<MagicVariableDeclaration>("this", make_shared<ContractType>(*m_currentContract));
|
||||
m_thisPointer[m_currentContract] = make_shared<MagicVariableDeclaration>("this", TypeProvider::contractType(*m_currentContract));
|
||||
return m_thisPointer[m_currentContract].get();
|
||||
|
||||
}
|
||||
@ -98,7 +107,7 @@ MagicVariableDeclaration const* GlobalContext::currentThis() const
|
||||
MagicVariableDeclaration const* GlobalContext::currentSuper() const
|
||||
{
|
||||
if (!m_superPointer[m_currentContract])
|
||||
m_superPointer[m_currentContract] = make_shared<MagicVariableDeclaration>("super", make_shared<ContractType>(*m_currentContract, true));
|
||||
m_superPointer[m_currentContract] = make_shared<MagicVariableDeclaration>("super", TypeProvider::contractType(*m_currentContract, true));
|
||||
return m_superPointer[m_currentContract].get();
|
||||
}
|
||||
|
||||
|
@ -228,7 +228,7 @@ vector<Declaration const*> NameAndTypeResolver::cleanedDeclarations(
|
||||
uniqueFunctions.end(),
|
||||
[&](Declaration const* d)
|
||||
{
|
||||
shared_ptr<FunctionType const> newFunctionType { d->functionType(false) };
|
||||
FunctionType const* newFunctionType = d->functionType(false);
|
||||
if (!newFunctionType)
|
||||
newFunctionType = d->functionType(true);
|
||||
return newFunctionType && functionType->hasEqualParameterTypes(*newFunctionType);
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <libsolidity/analysis/NameAndTypeResolver.h>
|
||||
#include <libsolidity/analysis/ConstantEvaluator.h>
|
||||
#include <libsolidity/ast/AST.h>
|
||||
#include <libsolidity/ast/TypeProvider.h>
|
||||
|
||||
#include <libyul/AsmAnalysis.h>
|
||||
#include <libyul/AsmAnalysisInfo.h>
|
||||
@ -120,7 +121,7 @@ bool ReferencesResolver::visit(ElementaryTypeName const& _typeName)
|
||||
{
|
||||
if (!_typeName.annotation().type)
|
||||
{
|
||||
_typeName.annotation().type = Type::fromElementaryTypeName(_typeName.typeName());
|
||||
_typeName.annotation().type = TypeProvider::fromElementaryTypeName(_typeName.typeName());
|
||||
if (_typeName.stateMutability().is_initialized())
|
||||
{
|
||||
// for non-address types this was already caught by the parser
|
||||
@ -128,8 +129,10 @@ bool ReferencesResolver::visit(ElementaryTypeName const& _typeName)
|
||||
switch(*_typeName.stateMutability())
|
||||
{
|
||||
case StateMutability::Payable:
|
||||
_typeName.annotation().type = TypeProvider::payableAddressType();
|
||||
break;
|
||||
case StateMutability::NonPayable:
|
||||
_typeName.annotation().type = make_shared<AddressType>(*_typeName.stateMutability());
|
||||
_typeName.annotation().type = TypeProvider::addressType();
|
||||
break;
|
||||
default:
|
||||
m_errorReporter.typeError(
|
||||
@ -179,14 +182,14 @@ void ReferencesResolver::endVisit(UserDefinedTypeName const& _typeName)
|
||||
_typeName.annotation().referencedDeclaration = declaration;
|
||||
|
||||
if (StructDefinition const* structDef = dynamic_cast<StructDefinition const*>(declaration))
|
||||
_typeName.annotation().type = make_shared<StructType>(*structDef);
|
||||
_typeName.annotation().type = TypeProvider::structType(*structDef, DataLocation::Storage);
|
||||
else if (EnumDefinition const* enumDef = dynamic_cast<EnumDefinition const*>(declaration))
|
||||
_typeName.annotation().type = make_shared<EnumType>(*enumDef);
|
||||
_typeName.annotation().type = TypeProvider::enumType(*enumDef);
|
||||
else if (ContractDefinition const* contract = dynamic_cast<ContractDefinition const*>(declaration))
|
||||
_typeName.annotation().type = make_shared<ContractType>(*contract);
|
||||
_typeName.annotation().type = TypeProvider::contractType(*contract);
|
||||
else
|
||||
{
|
||||
_typeName.annotation().type = make_shared<TupleType>();
|
||||
_typeName.annotation().type = TypeProvider::emptyTupleType();
|
||||
typeError(_typeName.location(), "Name has to refer to a struct, enum or contract.");
|
||||
}
|
||||
}
|
||||
@ -220,7 +223,7 @@ void ReferencesResolver::endVisit(FunctionTypeName const& _typeName)
|
||||
}
|
||||
}
|
||||
|
||||
_typeName.annotation().type = make_shared<FunctionType>(_typeName);
|
||||
_typeName.annotation().type = TypeProvider::functionType(_typeName);
|
||||
}
|
||||
|
||||
void ReferencesResolver::endVisit(Mapping const& _typeName)
|
||||
@ -231,7 +234,7 @@ void ReferencesResolver::endVisit(Mapping const& _typeName)
|
||||
keyType = ReferenceType::copyForLocationIfReference(DataLocation::Memory, keyType);
|
||||
// Convert value type to storage reference.
|
||||
valueType = ReferenceType::copyForLocationIfReference(DataLocation::Storage, valueType);
|
||||
_typeName.annotation().type = make_shared<MappingType>(keyType, valueType);
|
||||
_typeName.annotation().type = TypeProvider::mappingType(keyType, valueType);
|
||||
}
|
||||
|
||||
void ReferencesResolver::endVisit(ArrayTypeName const& _typeName)
|
||||
@ -249,7 +252,7 @@ void ReferencesResolver::endVisit(ArrayTypeName const& _typeName)
|
||||
TypePointer& lengthTypeGeneric = length->annotation().type;
|
||||
if (!lengthTypeGeneric)
|
||||
lengthTypeGeneric = ConstantEvaluator(m_errorReporter).evaluate(*length);
|
||||
RationalNumberType const* lengthType = dynamic_cast<RationalNumberType const*>(lengthTypeGeneric.get());
|
||||
RationalNumberType const* lengthType = dynamic_cast<RationalNumberType const*>(lengthTypeGeneric);
|
||||
if (!lengthType || !lengthType->mobileType())
|
||||
fatalTypeError(length->location(), "Invalid array length, expected integer literal or constant expression.");
|
||||
else if (lengthType->isZero())
|
||||
@ -259,10 +262,10 @@ void ReferencesResolver::endVisit(ArrayTypeName const& _typeName)
|
||||
else if (lengthType->isNegative())
|
||||
fatalTypeError(length->location(), "Array with negative length specified.");
|
||||
else
|
||||
_typeName.annotation().type = make_shared<ArrayType>(DataLocation::Storage, baseType, lengthType->literalValue(nullptr));
|
||||
_typeName.annotation().type = TypeProvider::arrayType(DataLocation::Storage, baseType, lengthType->literalValue(nullptr));
|
||||
}
|
||||
else
|
||||
_typeName.annotation().type = make_shared<ArrayType>(DataLocation::Storage, baseType);
|
||||
_typeName.annotation().type = TypeProvider::arrayType(DataLocation::Storage, baseType);
|
||||
}
|
||||
|
||||
bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly)
|
||||
@ -436,10 +439,10 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
|
||||
}
|
||||
|
||||
TypePointer type = _variable.typeName()->annotation().type;
|
||||
if (auto ref = dynamic_cast<ReferenceType const*>(type.get()))
|
||||
if (auto ref = dynamic_cast<ReferenceType const*>(type))
|
||||
{
|
||||
bool isPointer = !_variable.isStateVariable();
|
||||
type = ref->copyForLocation(typeLoc, isPointer);
|
||||
type = TypeProvider::withLocation(ref, typeLoc, isPointer);
|
||||
}
|
||||
|
||||
_variable.annotation().type = type;
|
||||
|
@ -190,7 +190,7 @@ bool StaticAnalyzer::visit(ExpressionStatement const& _statement)
|
||||
|
||||
bool StaticAnalyzer::visit(MemberAccess const& _memberAccess)
|
||||
{
|
||||
if (MagicType const* type = dynamic_cast<MagicType const*>(_memberAccess.expression().annotation().type.get()))
|
||||
if (MagicType const* type = dynamic_cast<MagicType const*>(_memberAccess.expression().annotation().type))
|
||||
{
|
||||
if (type->kind() == MagicType::Kind::Message && _memberAccess.memberName() == "gas")
|
||||
m_errorReporter.typeError(
|
||||
@ -217,7 +217,7 @@ bool StaticAnalyzer::visit(MemberAccess const& _memberAccess)
|
||||
}
|
||||
|
||||
if (_memberAccess.memberName() == "callcode")
|
||||
if (auto const* type = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type.get()))
|
||||
if (auto const* type = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type))
|
||||
if (type->kind() == FunctionType::Kind::BareCallCode)
|
||||
m_errorReporter.typeError(
|
||||
_memberAccess.location(),
|
||||
@ -278,7 +278,7 @@ bool StaticAnalyzer::visit(BinaryOperation const& _operation)
|
||||
_operation.rightExpression().annotation().isPure &&
|
||||
(_operation.getOperator() == Token::Div || _operation.getOperator() == Token::Mod)
|
||||
)
|
||||
if (auto rhs = dynamic_pointer_cast<RationalNumberType const>(
|
||||
if (auto rhs = dynamic_cast<RationalNumberType const*>(
|
||||
ConstantEvaluator(m_errorReporter).evaluate(_operation.rightExpression())
|
||||
))
|
||||
if (rhs->isZero())
|
||||
@ -294,13 +294,13 @@ bool StaticAnalyzer::visit(FunctionCall const& _functionCall)
|
||||
{
|
||||
if (_functionCall.annotation().kind == FunctionCallKind::FunctionCall)
|
||||
{
|
||||
auto functionType = dynamic_pointer_cast<FunctionType const>(_functionCall.expression().annotation().type);
|
||||
auto functionType = dynamic_cast<FunctionType const*>(_functionCall.expression().annotation().type);
|
||||
solAssert(functionType, "");
|
||||
if (functionType->kind() == FunctionType::Kind::AddMod || functionType->kind() == FunctionType::Kind::MulMod)
|
||||
{
|
||||
solAssert(_functionCall.arguments().size() == 3, "");
|
||||
if (_functionCall.arguments()[2]->annotation().isPure)
|
||||
if (auto lastArg = dynamic_pointer_cast<RationalNumberType const>(
|
||||
if (auto lastArg = dynamic_cast<RationalNumberType const*>(
|
||||
ConstantEvaluator(m_errorReporter).evaluate(*(_functionCall.arguments())[2])
|
||||
))
|
||||
if (lastArg->isZero())
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include <libsolidity/analysis/TypeChecker.h>
|
||||
#include <libsolidity/ast/AST.h>
|
||||
#include <libsolidity/ast/TypeProvider.h>
|
||||
|
||||
#include <libyul/AsmAnalysis.h>
|
||||
#include <libyul/AsmAnalysisInfo.h>
|
||||
@ -107,7 +108,7 @@ void TypeChecker::checkDoubleStorageAssignment(Assignment const& _assignment)
|
||||
size_t toStorageCopies = 0;
|
||||
for (size_t i = 0; i < lhs.components().size(); ++i)
|
||||
{
|
||||
ReferenceType const* ref = dynamic_cast<ReferenceType const*>(lhs.components()[i].get());
|
||||
ReferenceType const* ref = dynamic_cast<ReferenceType const*>(lhs.components()[i]);
|
||||
if (!ref || !ref->dataStoredIn(DataLocation::Storage) || ref->isPointer())
|
||||
continue;
|
||||
toStorageCopies++;
|
||||
@ -137,7 +138,7 @@ TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall c
|
||||
|
||||
if (arguments.size() >= 1)
|
||||
{
|
||||
BoolResult result = type(*arguments.front())->isImplicitlyConvertibleTo(ArrayType::bytesMemory());
|
||||
BoolResult result = type(*arguments.front())->isImplicitlyConvertibleTo(*TypeProvider::bytesMemoryType());
|
||||
|
||||
if (!result)
|
||||
m_errorReporter.typeErrorConcatenateDescriptions(
|
||||
@ -169,17 +170,17 @@ TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall c
|
||||
for (auto const& typeArgument: tupleExpression->components())
|
||||
{
|
||||
solAssert(typeArgument, "");
|
||||
if (TypeType const* argTypeType = dynamic_cast<TypeType const*>(type(*typeArgument).get()))
|
||||
if (TypeType const* argTypeType = dynamic_cast<TypeType const*>(type(*typeArgument)))
|
||||
{
|
||||
TypePointer actualType = argTypeType->actualType();
|
||||
solAssert(actualType, "");
|
||||
// We force memory because the parser currently cannot handle
|
||||
// data locations. Furthermore, storage can be a little dangerous and
|
||||
// calldata is not really implemented anyway.
|
||||
actualType = ReferenceType::copyForLocationIfReference(DataLocation::Memory, actualType);
|
||||
actualType = TypeProvider::withLocationIfReference(DataLocation::Memory, actualType);
|
||||
// We force address payable for address types.
|
||||
if (actualType->category() == Type::Category::Address)
|
||||
actualType = make_shared<AddressType>(StateMutability::Payable);
|
||||
actualType = TypeProvider::payableAddressType();
|
||||
solAssert(
|
||||
!actualType->dataStoredIn(DataLocation::CallData) &&
|
||||
!actualType->dataStoredIn(DataLocation::Storage),
|
||||
@ -195,7 +196,7 @@ TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall c
|
||||
else
|
||||
{
|
||||
m_errorReporter.typeError(typeArgument->location(), "Argument has to be a type name.");
|
||||
components.push_back(make_shared<TupleType>());
|
||||
components.push_back(TypeProvider::emptyTupleType());
|
||||
}
|
||||
}
|
||||
return components;
|
||||
@ -303,12 +304,12 @@ bool TypeChecker::visit(StructDefinition const& _struct)
|
||||
|
||||
for (ASTPointer<VariableDeclaration> const& member: _struct.members())
|
||||
{
|
||||
Type const* memberType = type(*member).get();
|
||||
Type const* memberType = type(*member);
|
||||
while (auto arrayType = dynamic_cast<ArrayType const*>(memberType))
|
||||
{
|
||||
if (arrayType->isDynamicallySized())
|
||||
break;
|
||||
memberType = arrayType->baseType().get();
|
||||
memberType = arrayType->baseType();
|
||||
}
|
||||
if (auto structType = dynamic_cast<StructType const*>(memberType))
|
||||
if (_cycleDetector.run(structType->structDefinition()))
|
||||
@ -359,7 +360,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
|
||||
{
|
||||
auto iType = type(var)->interfaceType(isLibraryFunction);
|
||||
|
||||
if (!iType.get())
|
||||
if (!iType)
|
||||
{
|
||||
solAssert(!iType.message().empty(), "Expected detailed error message!");
|
||||
m_errorReporter.fatalTypeError(var.location(), iType.message());
|
||||
@ -455,7 +456,7 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
|
||||
if (!_variable.type()->isValueType())
|
||||
{
|
||||
bool allowed = false;
|
||||
if (auto arrayType = dynamic_cast<ArrayType const*>(_variable.type().get()))
|
||||
if (auto arrayType = dynamic_cast<ArrayType const*>(_variable.type()))
|
||||
allowed = arrayType->isByteArray();
|
||||
if (!allowed)
|
||||
m_errorReporter.typeError(_variable.location(), "Constants of non-value type not yet implemented.");
|
||||
@ -498,7 +499,7 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
|
||||
switch (varType->category())
|
||||
{
|
||||
case Type::Category::Array:
|
||||
if (auto arrayType = dynamic_cast<ArrayType const*>(varType.get()))
|
||||
if (auto arrayType = dynamic_cast<ArrayType const*>(varType))
|
||||
if (
|
||||
((arrayType->location() == DataLocation::Memory) ||
|
||||
(arrayType->location() == DataLocation::CallData)) &&
|
||||
@ -584,7 +585,7 @@ bool TypeChecker::visit(EventDefinition const& _eventDef)
|
||||
numIndexed++;
|
||||
if (!type(*var)->canLiveOutsideStorage())
|
||||
m_errorReporter.typeError(var->location(), "Type is required to live outside storage.");
|
||||
if (!type(*var)->interfaceType(false).get())
|
||||
if (!type(*var)->interfaceType(false))
|
||||
m_errorReporter.typeError(var->location(), "Internal or recursive type is not allowed as event parameter type.");
|
||||
if (
|
||||
!_eventDef.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2) &&
|
||||
@ -607,7 +608,7 @@ void TypeChecker::endVisit(FunctionTypeName const& _funType)
|
||||
{
|
||||
FunctionType const& fun = dynamic_cast<FunctionType const&>(*_funType.annotation().type);
|
||||
if (fun.kind() == FunctionType::Kind::External)
|
||||
solAssert(fun.interfaceType(false).get(), "External function type uses internal types.");
|
||||
solAssert(fun.interfaceType(false), "External function type uses internal types.");
|
||||
}
|
||||
|
||||
bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
@ -716,7 +717,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
|
||||
bool TypeChecker::visit(IfStatement const& _ifStatement)
|
||||
{
|
||||
expectType(_ifStatement.condition(), BoolType());
|
||||
expectType(_ifStatement.condition(), *TypeProvider::boolType());
|
||||
_ifStatement.trueStatement().accept(*this);
|
||||
if (_ifStatement.falseStatement())
|
||||
_ifStatement.falseStatement()->accept(*this);
|
||||
@ -725,7 +726,7 @@ bool TypeChecker::visit(IfStatement const& _ifStatement)
|
||||
|
||||
bool TypeChecker::visit(WhileStatement const& _whileStatement)
|
||||
{
|
||||
expectType(_whileStatement.condition(), BoolType());
|
||||
expectType(_whileStatement.condition(), *TypeProvider::boolType());
|
||||
_whileStatement.body().accept(*this);
|
||||
return false;
|
||||
}
|
||||
@ -735,7 +736,7 @@ bool TypeChecker::visit(ForStatement const& _forStatement)
|
||||
if (_forStatement.initializationExpression())
|
||||
_forStatement.initializationExpression()->accept(*this);
|
||||
if (_forStatement.condition())
|
||||
expectType(*_forStatement.condition(), BoolType());
|
||||
expectType(*_forStatement.condition(), *TypeProvider::boolType());
|
||||
if (_forStatement.loopExpression())
|
||||
_forStatement.loopExpression()->accept(*this);
|
||||
_forStatement.body().accept(*this);
|
||||
@ -759,7 +760,7 @@ void TypeChecker::endVisit(Return const& _return)
|
||||
TypePointers returnTypes;
|
||||
for (auto const& var: params->parameters())
|
||||
returnTypes.push_back(type(*var));
|
||||
if (auto tupleType = dynamic_cast<TupleType const*>(type(*_return.expression()).get()))
|
||||
if (auto tupleType = dynamic_cast<TupleType const*>(type(*_return.expression())))
|
||||
{
|
||||
if (tupleType->components().size() != params->parameters().size())
|
||||
m_errorReporter.typeError(_return.location(), "Different number of arguments in return statement than in returns declaration.");
|
||||
@ -841,7 +842,7 @@ bool typeCanBeExpressed(vector<ASTPointer<VariableDeclaration>> const& decls)
|
||||
if (!decl->annotation().type)
|
||||
return false;
|
||||
|
||||
if (auto functionType = dynamic_cast<FunctionType const*>(decl->annotation().type.get()))
|
||||
if (auto functionType = dynamic_cast<FunctionType const*>(decl->annotation().type))
|
||||
if (
|
||||
functionType->kind() != FunctionType::Kind::Internal &&
|
||||
functionType->kind() != FunctionType::Kind::External
|
||||
@ -878,7 +879,7 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
|
||||
if (!varDecl.annotation().type)
|
||||
m_errorReporter.fatalTypeError(_statement.location(), "Use of the \"var\" keyword is disallowed.");
|
||||
|
||||
if (auto ref = dynamic_cast<ReferenceType const*>(type(varDecl).get()))
|
||||
if (auto ref = dynamic_cast<ReferenceType const*>(type(varDecl)))
|
||||
{
|
||||
if (ref->dataStoredIn(DataLocation::Storage))
|
||||
{
|
||||
@ -888,7 +889,7 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
|
||||
m_errorReporter.declarationError(varDecl.location(), errorText);
|
||||
}
|
||||
}
|
||||
else if (dynamic_cast<MappingType const*>(type(varDecl).get()))
|
||||
else if (dynamic_cast<MappingType const*>(type(varDecl)))
|
||||
m_errorReporter.typeError(
|
||||
varDecl.location(),
|
||||
"Uninitialized mapping. Mappings cannot be created dynamically, you have to assign them from a state variable."
|
||||
@ -902,7 +903,7 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
|
||||
|
||||
_statement.initialValue()->accept(*this);
|
||||
TypePointers valueTypes;
|
||||
if (auto tupleType = dynamic_cast<TupleType const*>(type(*_statement.initialValue()).get()))
|
||||
if (auto tupleType = dynamic_cast<TupleType const*>(type(*_statement.initialValue())))
|
||||
valueTypes = tupleType->components();
|
||||
else
|
||||
valueTypes = TypePointers{type(*_statement.initialValue())};
|
||||
@ -950,13 +951,13 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
|
||||
else
|
||||
solAssert(false, "");
|
||||
}
|
||||
else if (*var.annotation().type == TupleType())
|
||||
else if (*var.annotation().type == *TypeProvider::emptyTupleType())
|
||||
solAssert(false, "Cannot declare variable with void (empty tuple) type.");
|
||||
else if (valueComponentType->category() == Type::Category::RationalNumber)
|
||||
{
|
||||
string typeName = var.annotation().type->toString(true);
|
||||
string extension;
|
||||
if (auto type = dynamic_cast<IntegerType const*>(var.annotation().type.get()))
|
||||
if (auto type = dynamic_cast<IntegerType const*>(var.annotation().type))
|
||||
{
|
||||
unsigned numBits = type->numBits();
|
||||
bool isSigned = type->isSigned();
|
||||
@ -974,7 +975,7 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
|
||||
extension = ", which can hold values between " + minValue + " and " + maxValue;
|
||||
}
|
||||
else
|
||||
solAssert(dynamic_cast<FixedPointType const*>(var.annotation().type.get()), "Unknown type.");
|
||||
solAssert(dynamic_cast<FixedPointType const*>(var.annotation().type), "Unknown type.");
|
||||
}
|
||||
|
||||
var.accept(*this);
|
||||
@ -1054,7 +1055,7 @@ void TypeChecker::endVisit(ExpressionStatement const& _statement)
|
||||
|
||||
if (auto call = dynamic_cast<FunctionCall const*>(&_statement.expression()))
|
||||
{
|
||||
if (auto callType = dynamic_cast<FunctionType const*>(type(call->expression()).get()))
|
||||
if (auto callType = dynamic_cast<FunctionType const*>(type(call->expression())))
|
||||
{
|
||||
auto kind = callType->kind();
|
||||
if (
|
||||
@ -1072,7 +1073,7 @@ void TypeChecker::endVisit(ExpressionStatement const& _statement)
|
||||
|
||||
bool TypeChecker::visit(Conditional const& _conditional)
|
||||
{
|
||||
expectType(_conditional.condition(), BoolType());
|
||||
expectType(_conditional.condition(), *TypeProvider::boolType());
|
||||
|
||||
_conditional.trueExpression().accept(*this);
|
||||
_conditional.falseExpression().accept(*this);
|
||||
@ -1080,7 +1081,7 @@ bool TypeChecker::visit(Conditional const& _conditional)
|
||||
TypePointer trueType = type(_conditional.trueExpression())->mobileType();
|
||||
TypePointer falseType = type(_conditional.falseExpression())->mobileType();
|
||||
|
||||
TypePointer commonType;
|
||||
TypePointer commonType = nullptr;
|
||||
|
||||
if (!trueType)
|
||||
m_errorReporter.typeError(_conditional.trueExpression().location(), "Invalid mobile type in true expression.");
|
||||
@ -1134,7 +1135,7 @@ void TypeChecker::checkExpressionAssignment(Type const& _type, Expression const&
|
||||
if (auto const* tupleExpression = dynamic_cast<TupleExpression const*>(&_expression))
|
||||
{
|
||||
auto const* tupleType = dynamic_cast<TupleType const*>(&_type);
|
||||
auto const& types = tupleType ? tupleType->components() : vector<TypePointer> { _type.shared_from_this() };
|
||||
auto const& types = tupleType ? tupleType->components() : vector<TypePointer> { &_type };
|
||||
|
||||
solAssert(
|
||||
tupleExpression->components().size() == types.size() || m_errorReporter.hasErrors(),
|
||||
@ -1168,7 +1169,7 @@ bool TypeChecker::visit(Assignment const& _assignment)
|
||||
|
||||
checkExpressionAssignment(*t, _assignment.leftHandSide());
|
||||
|
||||
if (TupleType const* tupleType = dynamic_cast<TupleType const*>(t.get()))
|
||||
if (TupleType const* tupleType = dynamic_cast<TupleType const*>(t))
|
||||
{
|
||||
if (_assignment.assignmentOperator() != Token::Assign)
|
||||
m_errorReporter.typeError(
|
||||
@ -1176,12 +1177,12 @@ bool TypeChecker::visit(Assignment const& _assignment)
|
||||
"Compound assignment is not allowed for tuple types."
|
||||
);
|
||||
// Sequenced assignments of tuples is not valid, make the result a "void" type.
|
||||
_assignment.annotation().type = make_shared<TupleType>();
|
||||
_assignment.annotation().type = TypeProvider::emptyTupleType();
|
||||
|
||||
expectType(_assignment.rightHandSide(), *tupleType);
|
||||
|
||||
// expectType does not cause fatal errors, so we have to check again here.
|
||||
if (dynamic_cast<TupleType const*>(type(_assignment.rightHandSide()).get()))
|
||||
if (dynamic_cast<TupleType const*>(type(_assignment.rightHandSide())))
|
||||
checkDoubleStorageAssignment(_assignment);
|
||||
}
|
||||
else if (_assignment.assignmentOperator() == Token::Assign)
|
||||
@ -1228,14 +1229,14 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
|
||||
if (components.size() == 1)
|
||||
_tuple.annotation().type = type(*components[0]);
|
||||
else
|
||||
_tuple.annotation().type = make_shared<TupleType>(types);
|
||||
_tuple.annotation().type = TypeProvider::tupleType(move(types));
|
||||
// If some of the components are not LValues, the error is reported above.
|
||||
_tuple.annotation().isLValue = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool isPure = true;
|
||||
TypePointer inlineArrayType;
|
||||
TypePointer inlineArrayType = nullptr;
|
||||
|
||||
for (size_t i = 0; i < components.size(); ++i)
|
||||
{
|
||||
@ -1285,14 +1286,14 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
|
||||
else if (!inlineArrayType->canLiveOutsideStorage())
|
||||
m_errorReporter.fatalTypeError(_tuple.location(), "Type " + inlineArrayType->toString() + " is only valid in storage.");
|
||||
|
||||
_tuple.annotation().type = make_shared<ArrayType>(DataLocation::Memory, inlineArrayType, types.size());
|
||||
_tuple.annotation().type = TypeProvider::arrayType(DataLocation::Memory, inlineArrayType, types.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (components.size() == 1)
|
||||
_tuple.annotation().type = type(*components[0]);
|
||||
else
|
||||
_tuple.annotation().type = make_shared<TupleType>(types);
|
||||
_tuple.annotation().type = TypeProvider::tupleType(move(types));
|
||||
}
|
||||
|
||||
}
|
||||
@ -1349,7 +1350,7 @@ void TypeChecker::endVisit(BinaryOperation const& _operation)
|
||||
_operation.annotation().commonType = commonType;
|
||||
_operation.annotation().type =
|
||||
TokenTraits::isCompareOp(_operation.getOperator()) ?
|
||||
make_shared<BoolType>() :
|
||||
TypeProvider::boolType() :
|
||||
commonType;
|
||||
_operation.annotation().isPure =
|
||||
_operation.leftExpression().annotation().isPure &&
|
||||
@ -1401,20 +1402,20 @@ TypePointer TypeChecker::typeCheckTypeConversionAndRetrieveReturnType(
|
||||
);
|
||||
else
|
||||
{
|
||||
TypePointer const& argType = type(*arguments.front());
|
||||
Type const* argType = type(*arguments.front());
|
||||
// Resulting data location is memory unless we are converting from a reference
|
||||
// type with a different data location.
|
||||
// (data location cannot yet be specified for type conversions)
|
||||
DataLocation dataLoc = DataLocation::Memory;
|
||||
if (auto argRefType = dynamic_cast<ReferenceType const*>(argType.get()))
|
||||
if (auto argRefType = dynamic_cast<ReferenceType const*>(argType))
|
||||
dataLoc = argRefType->location();
|
||||
if (auto type = dynamic_cast<ReferenceType const*>(resultType.get()))
|
||||
resultType = type->copyForLocation(dataLoc, type->isPointer());
|
||||
if (auto type = dynamic_cast<ReferenceType const*>(resultType))
|
||||
resultType = TypeProvider::withLocation(type, dataLoc, type->isPointer());
|
||||
if (argType->isExplicitlyConvertibleTo(*resultType))
|
||||
{
|
||||
if (auto argArrayType = dynamic_cast<ArrayType const*>(argType.get()))
|
||||
if (auto argArrayType = dynamic_cast<ArrayType const*>(argType))
|
||||
{
|
||||
auto resultArrayType = dynamic_cast<ArrayType const*>(resultType.get());
|
||||
auto resultArrayType = dynamic_cast<ArrayType const*>(resultType);
|
||||
solAssert(!!resultArrayType, "");
|
||||
solAssert(
|
||||
argArrayType->location() != DataLocation::Storage ||
|
||||
@ -1436,9 +1437,9 @@ TypePointer TypeChecker::typeCheckTypeConversionAndRetrieveReturnType(
|
||||
argType->category() == Type::Category::Address
|
||||
)
|
||||
{
|
||||
solAssert(dynamic_cast<ContractType const*>(resultType.get())->isPayable(), "");
|
||||
solAssert(dynamic_cast<ContractType const*>(resultType)->isPayable(), "");
|
||||
solAssert(
|
||||
dynamic_cast<AddressType const*>(argType.get())->stateMutability() <
|
||||
dynamic_cast<AddressType const*>(argType)->stateMutability() <
|
||||
StateMutability::Payable,
|
||||
""
|
||||
);
|
||||
@ -1474,10 +1475,8 @@ TypePointer TypeChecker::typeCheckTypeConversionAndRetrieveReturnType(
|
||||
}
|
||||
if (resultType->category() == Type::Category::Address)
|
||||
{
|
||||
bool const payable = argType->isExplicitlyConvertibleTo(AddressType::addressPayable());
|
||||
resultType = make_shared<AddressType>(
|
||||
payable ? StateMutability::Payable : StateMutability::NonPayable
|
||||
);
|
||||
bool const payable = argType->isExplicitlyConvertibleTo(*TypeProvider::payableAddressType());
|
||||
resultType = payable ? TypeProvider::payableAddressType() : TypeProvider::addressType();
|
||||
}
|
||||
}
|
||||
return resultType;
|
||||
@ -1829,17 +1828,17 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
|
||||
|
||||
_functionCall.expression().accept(*this);
|
||||
|
||||
TypePointer const& expressionType = type(_functionCall.expression());
|
||||
Type const* expressionType = type(_functionCall.expression());
|
||||
|
||||
// Determine function call kind and function type for this FunctionCall node
|
||||
FunctionCallAnnotation& funcCallAnno = _functionCall.annotation();
|
||||
FunctionTypePointer functionType;
|
||||
FunctionTypePointer functionType = nullptr;
|
||||
|
||||
// Determine and assign function call kind, purity and function type for this FunctionCall node
|
||||
switch (expressionType->category())
|
||||
{
|
||||
case Type::Category::Function:
|
||||
functionType = dynamic_pointer_cast<FunctionType const>(expressionType);
|
||||
functionType = dynamic_cast<FunctionType const*>(expressionType);
|
||||
funcCallAnno.kind = FunctionCallKind::FunctionCall;
|
||||
|
||||
// Purity for function calls also depends upon the callee and its FunctionType
|
||||
@ -1926,7 +1925,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
|
||||
|
||||
funcCallAnno.type = returnTypes.size() == 1 ?
|
||||
move(returnTypes.front()) :
|
||||
make_shared<TupleType>(move(returnTypes));
|
||||
TypeProvider::tupleType(move(returnTypes));
|
||||
|
||||
break;
|
||||
}
|
||||
@ -1936,7 +1935,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
|
||||
// for non-callables, ensure error reported and annotate node to void function
|
||||
solAssert(m_errorReporter.hasErrors(), "");
|
||||
funcCallAnno.kind = FunctionCallKind::FunctionCall;
|
||||
funcCallAnno.type = make_shared<TupleType>();
|
||||
funcCallAnno.type = TypeProvider::emptyTupleType();
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1999,8 +1998,8 @@ void TypeChecker::endVisit(NewExpression const& _newExpression)
|
||||
"Length has to be placed in parentheses after the array type for new expression."
|
||||
);
|
||||
type = ReferenceType::copyForLocationIfReference(DataLocation::Memory, type);
|
||||
_newExpression.annotation().type = make_shared<FunctionType>(
|
||||
TypePointers{make_shared<IntegerType>(256)},
|
||||
_newExpression.annotation().type = TypeProvider::functionType(
|
||||
TypePointers{TypeProvider::uint256()},
|
||||
TypePointers{type},
|
||||
strings(1, ""),
|
||||
strings(1, ""),
|
||||
@ -2059,7 +2058,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
||||
string errorMsg = "Member \"" + memberName + "\" not found or not visible "
|
||||
"after argument-dependent lookup in " + exprType->toString() + ".";
|
||||
|
||||
if (auto const& funType = dynamic_pointer_cast<FunctionType const>(exprType))
|
||||
if (auto const& funType = dynamic_cast<FunctionType const*>(exprType))
|
||||
{
|
||||
auto const& t = funType->returnParameterTypes();
|
||||
|
||||
@ -2079,7 +2078,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
||||
}
|
||||
else if (exprType->category() == Type::Category::Contract)
|
||||
{
|
||||
for (auto const& addressMember: AddressType::addressPayable().nativeMembers(nullptr))
|
||||
for (auto const& addressMember: TypeProvider::payableAddressType()->nativeMembers(nullptr))
|
||||
if (addressMember.name == memberName)
|
||||
{
|
||||
Identifier const* var = dynamic_cast<Identifier const*>(&_memberAccess.expression());
|
||||
@ -2088,7 +2087,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (auto addressType = dynamic_cast<AddressType const*>(exprType.get()))
|
||||
else if (auto addressType = dynamic_cast<AddressType const*>(exprType))
|
||||
{
|
||||
// Trigger error when using send or transfer with a non-payable fallback function.
|
||||
if (memberName == "send" || memberName == "transfer")
|
||||
@ -2118,14 +2117,14 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
||||
annotation.referencedDeclaration = possibleMembers.front().declaration;
|
||||
annotation.type = possibleMembers.front().type;
|
||||
|
||||
if (auto funType = dynamic_cast<FunctionType const*>(annotation.type.get()))
|
||||
if (auto funType = dynamic_cast<FunctionType const*>(annotation.type))
|
||||
solAssert(
|
||||
!funType->bound() || exprType->isImplicitlyConvertibleTo(*funType->selfType()),
|
||||
"Function \"" + memberName + "\" cannot be called on an object of type " +
|
||||
exprType->toString() + " (expected " + funType->selfType()->toString() + ")."
|
||||
);
|
||||
|
||||
if (auto const* structType = dynamic_cast<StructType const*>(exprType.get()))
|
||||
if (auto const* structType = dynamic_cast<StructType const*>(exprType))
|
||||
annotation.isLValue = !structType->dataStoredIn(DataLocation::CallData);
|
||||
else if (exprType->category() == Type::Category::Array)
|
||||
{
|
||||
@ -2138,18 +2137,18 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
||||
}
|
||||
else if (exprType->category() == Type::Category::FixedBytes)
|
||||
annotation.isLValue = false;
|
||||
else if (TypeType const* typeType = dynamic_cast<decltype(typeType)>(exprType.get()))
|
||||
else if (TypeType const* typeType = dynamic_cast<decltype(typeType)>(exprType))
|
||||
{
|
||||
if (ContractType const* contractType = dynamic_cast<decltype(contractType)>(typeType->actualType().get()))
|
||||
if (ContractType const* contractType = dynamic_cast<decltype(contractType)>(typeType->actualType()))
|
||||
annotation.isLValue = annotation.referencedDeclaration->isLValue();
|
||||
}
|
||||
|
||||
// TODO some members might be pure, but for example `address(0x123).balance` is not pure
|
||||
// although every subexpression is, so leaving this limited for now.
|
||||
if (auto tt = dynamic_cast<TypeType const*>(exprType.get()))
|
||||
if (auto tt = dynamic_cast<TypeType const*>(exprType))
|
||||
if (tt->actualType()->category() == Type::Category::Enum)
|
||||
annotation.isPure = true;
|
||||
if (auto magicType = dynamic_cast<MagicType const*>(exprType.get()))
|
||||
if (auto magicType = dynamic_cast<MagicType const*>(exprType))
|
||||
{
|
||||
if (magicType->kind() == MagicType::Kind::ABI)
|
||||
annotation.isPure = true;
|
||||
@ -2178,7 +2177,7 @@ bool TypeChecker::visit(IndexAccess const& _access)
|
||||
{
|
||||
_access.baseExpression().accept(*this);
|
||||
TypePointer baseType = type(_access.baseExpression());
|
||||
TypePointer resultType;
|
||||
TypePointer resultType = nullptr;
|
||||
bool isLValue = false;
|
||||
bool isPure = _access.baseExpression().annotation().isPure;
|
||||
Expression const* index = _access.indexExpression();
|
||||
@ -2196,9 +2195,9 @@ bool TypeChecker::visit(IndexAccess const& _access)
|
||||
}
|
||||
else
|
||||
{
|
||||
expectType(*index, IntegerType::uint256());
|
||||
expectType(*index, *TypeProvider::uint256());
|
||||
if (!m_errorReporter.hasErrors())
|
||||
if (auto numberType = dynamic_cast<RationalNumberType const*>(type(*index).get()))
|
||||
if (auto numberType = dynamic_cast<RationalNumberType const*>(type(*index)))
|
||||
{
|
||||
solAssert(!numberType->isFractional(), "");
|
||||
if (!actualType.isDynamicallySized() && actualType.length() <= numberType->literalValue(nullptr))
|
||||
@ -2223,16 +2222,16 @@ bool TypeChecker::visit(IndexAccess const& _access)
|
||||
case Type::Category::TypeType:
|
||||
{
|
||||
TypeType const& typeType = dynamic_cast<TypeType const&>(*baseType);
|
||||
if (dynamic_cast<ContractType const*>(typeType.actualType().get()))
|
||||
if (dynamic_cast<ContractType const*>(typeType.actualType()))
|
||||
m_errorReporter.typeError(_access.location(), "Index access for contracts or libraries is not possible.");
|
||||
if (!index)
|
||||
resultType = make_shared<TypeType>(make_shared<ArrayType>(DataLocation::Memory, typeType.actualType()));
|
||||
resultType = TypeProvider::typeType(TypeProvider::arrayType(DataLocation::Memory, typeType.actualType()));
|
||||
else
|
||||
{
|
||||
u256 length = 1;
|
||||
if (expectType(*index, IntegerType::uint256()))
|
||||
if (expectType(*index, *TypeProvider::uint256()))
|
||||
{
|
||||
if (auto indexValue = dynamic_cast<RationalNumberType const*>(type(*index).get()))
|
||||
if (auto indexValue = dynamic_cast<RationalNumberType const*>(type(*index)))
|
||||
length = indexValue->literalValue(nullptr);
|
||||
else
|
||||
m_errorReporter.fatalTypeError(index->location(), "Integer constant expected.");
|
||||
@ -2240,7 +2239,7 @@ bool TypeChecker::visit(IndexAccess const& _access)
|
||||
else
|
||||
solAssert(m_errorReporter.hasErrors(), "Expected errors as expectType returned false");
|
||||
|
||||
resultType = make_shared<TypeType>(make_shared<ArrayType>(
|
||||
resultType = TypeProvider::typeType(TypeProvider::arrayType(
|
||||
DataLocation::Memory,
|
||||
typeType.actualType(),
|
||||
length
|
||||
@ -2255,13 +2254,13 @@ bool TypeChecker::visit(IndexAccess const& _access)
|
||||
m_errorReporter.typeError(_access.location(), "Index expression cannot be omitted.");
|
||||
else
|
||||
{
|
||||
if (!expectType(*index, IntegerType::uint256()))
|
||||
if (!expectType(*index, *TypeProvider::uint256()))
|
||||
m_errorReporter.fatalTypeError(_access.location(), "Index expression cannot be represented as an unsigned integer.");
|
||||
if (auto integerType = dynamic_cast<RationalNumberType const*>(type(*index).get()))
|
||||
if (auto integerType = dynamic_cast<RationalNumberType const*>(type(*index)))
|
||||
if (bytesType.numBytes() <= integerType->literalValue(nullptr))
|
||||
m_errorReporter.typeError(_access.location(), "Out of bounds array access.");
|
||||
}
|
||||
resultType = make_shared<FixedBytesType>(1);
|
||||
resultType = TypeProvider::fixedBytesType(1);
|
||||
isLValue = false; // @todo this heavily depends on how it is embedded
|
||||
break;
|
||||
}
|
||||
@ -2271,7 +2270,7 @@ bool TypeChecker::visit(IndexAccess const& _access)
|
||||
"Indexed expression has to be a type, mapping or array (is " + baseType->toString() + ")"
|
||||
);
|
||||
}
|
||||
_access.annotation().type = move(resultType);
|
||||
_access.annotation().type = resultType;
|
||||
_access.annotation().isLValue = isLValue;
|
||||
if (index && !index->annotation().isPure)
|
||||
isPure = false;
|
||||
@ -2337,16 +2336,16 @@ bool TypeChecker::visit(Identifier const& _identifier)
|
||||
annotation.isPure = annotation.isConstant = variableDeclaration->isConstant();
|
||||
else if (dynamic_cast<MagicVariableDeclaration const*>(annotation.referencedDeclaration))
|
||||
{
|
||||
if (dynamic_cast<FunctionType const*>(annotation.type.get()))
|
||||
if (dynamic_cast<FunctionType const*>(annotation.type))
|
||||
annotation.isPure = true;
|
||||
}
|
||||
else if (dynamic_cast<TypeType const*>(annotation.type.get()))
|
||||
else if (dynamic_cast<TypeType const*>(annotation.type))
|
||||
annotation.isPure = true;
|
||||
|
||||
|
||||
// Check for deprecated function names.
|
||||
// The check is done here for the case without an actual function call.
|
||||
if (FunctionType const* fType = dynamic_cast<FunctionType const*>(_identifier.annotation().type.get()))
|
||||
if (FunctionType const* fType = dynamic_cast<FunctionType const*>(_identifier.annotation().type))
|
||||
{
|
||||
if (_identifier.name() == "sha3" && fType->kind() == FunctionType::Kind::KECCAK256)
|
||||
m_errorReporter.typeError(
|
||||
@ -2365,7 +2364,7 @@ bool TypeChecker::visit(Identifier const& _identifier)
|
||||
|
||||
void TypeChecker::endVisit(ElementaryTypeNameExpression const& _expr)
|
||||
{
|
||||
_expr.annotation().type = make_shared<TypeType>(Type::fromElementaryTypeName(_expr.typeName()));
|
||||
_expr.annotation().type = TypeProvider::typeType(TypeProvider::fromElementaryTypeName(_expr.typeName()));
|
||||
_expr.annotation().isPure = true;
|
||||
}
|
||||
|
||||
@ -2374,7 +2373,7 @@ void TypeChecker::endVisit(Literal const& _literal)
|
||||
if (_literal.looksLikeAddress())
|
||||
{
|
||||
// Assign type here if it even looks like an address. This prevents double errors for invalid addresses
|
||||
_literal.annotation().type = make_shared<AddressType>(StateMutability::Payable);
|
||||
_literal.annotation().type = TypeProvider::payableAddressType();
|
||||
|
||||
string msg;
|
||||
if (_literal.valueWithoutUnderscores().length() != 42) // "0x" + 40 hex digits
|
||||
@ -2413,7 +2412,7 @@ void TypeChecker::endVisit(Literal const& _literal)
|
||||
);
|
||||
|
||||
if (!_literal.annotation().type)
|
||||
_literal.annotation().type = Type::forLiteral(_literal);
|
||||
_literal.annotation().type = TypeProvider::forLiteral(_literal);
|
||||
|
||||
if (!_literal.annotation().type)
|
||||
m_errorReporter.fatalTypeError(_literal.location(), "Invalid literal value.");
|
||||
@ -2460,7 +2459,7 @@ bool TypeChecker::expectType(Expression const& _expression, Type const& _expecte
|
||||
_expectedType.toString();
|
||||
if (
|
||||
type(_expression)->category() == Type::Category::RationalNumber &&
|
||||
dynamic_pointer_cast<RationalNumberType const>(type(_expression))->isFractional() &&
|
||||
dynamic_cast<RationalNumberType const*>(type(_expression))->isFractional() &&
|
||||
type(_expression)->mobileType()
|
||||
)
|
||||
{
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include <libsolidity/ast/ASTVisitor.h>
|
||||
#include <libsolidity/ast/AST_accept.h>
|
||||
#include <libsolidity/ast/TypeProvider.h>
|
||||
#include <libdevcore/Keccak256.h>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
@ -105,7 +106,7 @@ ImportAnnotation& ImportDirective::annotation() const
|
||||
TypePointer ImportDirective::type() const
|
||||
{
|
||||
solAssert(!!annotation().sourceUnit, "");
|
||||
return make_shared<ModuleType>(*annotation().sourceUnit);
|
||||
return TypeProvider::moduleType(*annotation().sourceUnit);
|
||||
}
|
||||
|
||||
map<FixedHash<4>, FunctionTypePointer> ContractDefinition::interfaceFunctions() const
|
||||
@ -188,10 +189,10 @@ vector<pair<FixedHash<4>, FunctionTypePointer>> const& ContractDefinition::inter
|
||||
vector<FunctionTypePointer> functions;
|
||||
for (FunctionDefinition const* f: contract->definedFunctions())
|
||||
if (f->isPartOfExternalInterface())
|
||||
functions.push_back(make_shared<FunctionType>(*f, false));
|
||||
functions.push_back(TypeProvider::functionType(*f, false));
|
||||
for (VariableDeclaration const* v: contract->stateVariables())
|
||||
if (v->isPartOfExternalInterface())
|
||||
functions.push_back(make_shared<FunctionType>(*v));
|
||||
functions.push_back(TypeProvider::functionType(*v));
|
||||
for (FunctionTypePointer const& fun: functions)
|
||||
{
|
||||
if (!fun->interfaceFunctionType())
|
||||
@ -246,7 +247,7 @@ vector<Declaration const*> const& ContractDefinition::inheritableMembers() const
|
||||
|
||||
TypePointer ContractDefinition::type() const
|
||||
{
|
||||
return make_shared<TypeType>(make_shared<ContractType>(*this));
|
||||
return TypeProvider::typeType(TypeProvider::contractType(*this));
|
||||
}
|
||||
|
||||
ContractDefinitionAnnotation& ContractDefinition::annotation() const
|
||||
@ -265,7 +266,7 @@ TypeNameAnnotation& TypeName::annotation() const
|
||||
|
||||
TypePointer StructDefinition::type() const
|
||||
{
|
||||
return make_shared<TypeType>(make_shared<StructType>(*this));
|
||||
return TypeProvider::typeType(TypeProvider::structType(*this, DataLocation::Storage));
|
||||
}
|
||||
|
||||
TypeDeclarationAnnotation& StructDefinition::annotation() const
|
||||
@ -279,12 +280,12 @@ TypePointer EnumValue::type() const
|
||||
{
|
||||
auto parentDef = dynamic_cast<EnumDefinition const*>(scope());
|
||||
solAssert(parentDef, "Enclosing Scope of EnumValue was not set");
|
||||
return make_shared<EnumType>(*parentDef);
|
||||
return TypeProvider::enumType(*parentDef);
|
||||
}
|
||||
|
||||
TypePointer EnumDefinition::type() const
|
||||
{
|
||||
return make_shared<TypeType>(make_shared<EnumType>(*this));
|
||||
return TypeProvider::typeType(TypeProvider::enumType(*this));
|
||||
}
|
||||
|
||||
TypeDeclarationAnnotation& EnumDefinition::annotation() const
|
||||
@ -312,7 +313,7 @@ FunctionTypePointer FunctionDefinition::functionType(bool _internal) const
|
||||
case Declaration::Visibility::Private:
|
||||
case Declaration::Visibility::Internal:
|
||||
case Declaration::Visibility::Public:
|
||||
return make_shared<FunctionType>(*this, _internal);
|
||||
return TypeProvider::functionType(*this, _internal);
|
||||
case Declaration::Visibility::External:
|
||||
return {};
|
||||
}
|
||||
@ -328,7 +329,7 @@ FunctionTypePointer FunctionDefinition::functionType(bool _internal) const
|
||||
return {};
|
||||
case Declaration::Visibility::Public:
|
||||
case Declaration::Visibility::External:
|
||||
return make_shared<FunctionType>(*this, _internal);
|
||||
return TypeProvider::functionType(*this, _internal);
|
||||
}
|
||||
}
|
||||
|
||||
@ -339,12 +340,12 @@ FunctionTypePointer FunctionDefinition::functionType(bool _internal) const
|
||||
TypePointer FunctionDefinition::type() const
|
||||
{
|
||||
solAssert(visibility() != Declaration::Visibility::External, "");
|
||||
return make_shared<FunctionType>(*this);
|
||||
return TypeProvider::functionType(*this);
|
||||
}
|
||||
|
||||
string FunctionDefinition::externalSignature() const
|
||||
{
|
||||
return FunctionType(*this).externalSignature();
|
||||
return TypeProvider::functionType(*this)->externalSignature();
|
||||
}
|
||||
|
||||
FunctionDefinitionAnnotation& FunctionDefinition::annotation() const
|
||||
@ -356,7 +357,7 @@ FunctionDefinitionAnnotation& FunctionDefinition::annotation() const
|
||||
|
||||
TypePointer ModifierDefinition::type() const
|
||||
{
|
||||
return make_shared<ModifierType>(*this);
|
||||
return TypeProvider::modifierType(*this);
|
||||
}
|
||||
|
||||
ModifierDefinitionAnnotation& ModifierDefinition::annotation() const
|
||||
@ -368,15 +369,15 @@ ModifierDefinitionAnnotation& ModifierDefinition::annotation() const
|
||||
|
||||
TypePointer EventDefinition::type() const
|
||||
{
|
||||
return make_shared<FunctionType>(*this);
|
||||
return TypeProvider::functionType(*this);
|
||||
}
|
||||
|
||||
FunctionTypePointer EventDefinition::functionType(bool _internal) const
|
||||
{
|
||||
if (_internal)
|
||||
return make_shared<FunctionType>(*this);
|
||||
return TypeProvider::functionType(*this);
|
||||
else
|
||||
return {};
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
EventDefinitionAnnotation& EventDefinition::annotation() const
|
||||
@ -508,8 +509,8 @@ bool VariableDeclaration::hasReferenceOrMappingType() const
|
||||
{
|
||||
solAssert(typeName(), "");
|
||||
solAssert(typeName()->annotation().type, "Can only be called after reference resolution");
|
||||
TypePointer const& type = typeName()->annotation().type;
|
||||
return type->category() == Type::Category::Mapping || dynamic_cast<ReferenceType const*>(type.get());
|
||||
Type const* type = typeName()->annotation().type;
|
||||
return type->category() == Type::Category::Mapping || dynamic_cast<ReferenceType const*>(type);
|
||||
}
|
||||
|
||||
set<VariableDeclaration::Location> VariableDeclaration::allowedDataLocations() const
|
||||
@ -557,21 +558,21 @@ TypePointer VariableDeclaration::type() const
|
||||
FunctionTypePointer VariableDeclaration::functionType(bool _internal) const
|
||||
{
|
||||
if (_internal)
|
||||
return {};
|
||||
return nullptr;
|
||||
switch (visibility())
|
||||
{
|
||||
case Declaration::Visibility::Default:
|
||||
solAssert(false, "visibility() should not return Default");
|
||||
case Declaration::Visibility::Private:
|
||||
case Declaration::Visibility::Internal:
|
||||
return {};
|
||||
return nullptr;
|
||||
case Declaration::Visibility::Public:
|
||||
case Declaration::Visibility::External:
|
||||
return make_shared<FunctionType>(*this);
|
||||
return TypeProvider::functionType(*this);
|
||||
}
|
||||
|
||||
// To make the compiler happy
|
||||
return {};
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
VariableDeclarationAnnotation& VariableDeclaration::annotation() const
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
541
libsolidity/ast/TypeProvider.cpp
Normal file
541
libsolidity/ast/TypeProvider.cpp
Normal file
@ -0,0 +1,541 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <libsolidity/ast/AST.h>
|
||||
#include <libsolidity/ast/TypeProvider.h>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace dev;
|
||||
using namespace solidity;
|
||||
|
||||
BoolType const TypeProvider::m_boolType{};
|
||||
InaccessibleDynamicType const TypeProvider::m_inaccessibleDynamicType{};
|
||||
|
||||
/// The string and bytes unique_ptrs are initialized when they are first used because
|
||||
/// they rely on `byte` being available which we cannot guarantee in the static init context.
|
||||
std::unique_ptr<ArrayType> TypeProvider::m_bytesStorageType;
|
||||
std::unique_ptr<ArrayType> TypeProvider::m_bytesMemoryType;
|
||||
std::unique_ptr<ArrayType> TypeProvider::m_stringStorageType;
|
||||
std::unique_ptr<ArrayType> TypeProvider::m_stringMemoryType;
|
||||
|
||||
TupleType const TypeProvider::m_emptyTupleType{};
|
||||
AddressType const TypeProvider::m_payableAddressType{StateMutability::Payable};
|
||||
AddressType const TypeProvider::m_addressType{StateMutability::NonPayable};
|
||||
|
||||
array<unique_ptr<IntegerType>, 32> const TypeProvider::m_intM{{
|
||||
{make_unique<IntegerType>(8 * 1, IntegerType::Modifier::Signed)},
|
||||
{make_unique<IntegerType>(8 * 2, IntegerType::Modifier::Signed)},
|
||||
{make_unique<IntegerType>(8 * 3, IntegerType::Modifier::Signed)},
|
||||
{make_unique<IntegerType>(8 * 4, IntegerType::Modifier::Signed)},
|
||||
{make_unique<IntegerType>(8 * 5, IntegerType::Modifier::Signed)},
|
||||
{make_unique<IntegerType>(8 * 6, IntegerType::Modifier::Signed)},
|
||||
{make_unique<IntegerType>(8 * 7, IntegerType::Modifier::Signed)},
|
||||
{make_unique<IntegerType>(8 * 8, IntegerType::Modifier::Signed)},
|
||||
{make_unique<IntegerType>(8 * 9, IntegerType::Modifier::Signed)},
|
||||
{make_unique<IntegerType>(8 * 10, IntegerType::Modifier::Signed)},
|
||||
{make_unique<IntegerType>(8 * 11, IntegerType::Modifier::Signed)},
|
||||
{make_unique<IntegerType>(8 * 12, IntegerType::Modifier::Signed)},
|
||||
{make_unique<IntegerType>(8 * 13, IntegerType::Modifier::Signed)},
|
||||
{make_unique<IntegerType>(8 * 14, IntegerType::Modifier::Signed)},
|
||||
{make_unique<IntegerType>(8 * 15, IntegerType::Modifier::Signed)},
|
||||
{make_unique<IntegerType>(8 * 16, IntegerType::Modifier::Signed)},
|
||||
{make_unique<IntegerType>(8 * 17, IntegerType::Modifier::Signed)},
|
||||
{make_unique<IntegerType>(8 * 18, IntegerType::Modifier::Signed)},
|
||||
{make_unique<IntegerType>(8 * 19, IntegerType::Modifier::Signed)},
|
||||
{make_unique<IntegerType>(8 * 20, IntegerType::Modifier::Signed)},
|
||||
{make_unique<IntegerType>(8 * 21, IntegerType::Modifier::Signed)},
|
||||
{make_unique<IntegerType>(8 * 22, IntegerType::Modifier::Signed)},
|
||||
{make_unique<IntegerType>(8 * 23, IntegerType::Modifier::Signed)},
|
||||
{make_unique<IntegerType>(8 * 24, IntegerType::Modifier::Signed)},
|
||||
{make_unique<IntegerType>(8 * 25, IntegerType::Modifier::Signed)},
|
||||
{make_unique<IntegerType>(8 * 26, IntegerType::Modifier::Signed)},
|
||||
{make_unique<IntegerType>(8 * 27, IntegerType::Modifier::Signed)},
|
||||
{make_unique<IntegerType>(8 * 28, IntegerType::Modifier::Signed)},
|
||||
{make_unique<IntegerType>(8 * 29, IntegerType::Modifier::Signed)},
|
||||
{make_unique<IntegerType>(8 * 30, IntegerType::Modifier::Signed)},
|
||||
{make_unique<IntegerType>(8 * 31, IntegerType::Modifier::Signed)},
|
||||
{make_unique<IntegerType>(8 * 32, IntegerType::Modifier::Signed)}
|
||||
}};
|
||||
|
||||
array<unique_ptr<IntegerType>, 32> const TypeProvider::m_uintM{{
|
||||
{make_unique<IntegerType>(8 * 1, IntegerType::Modifier::Unsigned)},
|
||||
{make_unique<IntegerType>(8 * 2, IntegerType::Modifier::Unsigned)},
|
||||
{make_unique<IntegerType>(8 * 3, IntegerType::Modifier::Unsigned)},
|
||||
{make_unique<IntegerType>(8 * 4, IntegerType::Modifier::Unsigned)},
|
||||
{make_unique<IntegerType>(8 * 5, IntegerType::Modifier::Unsigned)},
|
||||
{make_unique<IntegerType>(8 * 6, IntegerType::Modifier::Unsigned)},
|
||||
{make_unique<IntegerType>(8 * 7, IntegerType::Modifier::Unsigned)},
|
||||
{make_unique<IntegerType>(8 * 8, IntegerType::Modifier::Unsigned)},
|
||||
{make_unique<IntegerType>(8 * 9, IntegerType::Modifier::Unsigned)},
|
||||
{make_unique<IntegerType>(8 * 10, IntegerType::Modifier::Unsigned)},
|
||||
{make_unique<IntegerType>(8 * 11, IntegerType::Modifier::Unsigned)},
|
||||
{make_unique<IntegerType>(8 * 12, IntegerType::Modifier::Unsigned)},
|
||||
{make_unique<IntegerType>(8 * 13, IntegerType::Modifier::Unsigned)},
|
||||
{make_unique<IntegerType>(8 * 14, IntegerType::Modifier::Unsigned)},
|
||||
{make_unique<IntegerType>(8 * 15, IntegerType::Modifier::Unsigned)},
|
||||
{make_unique<IntegerType>(8 * 16, IntegerType::Modifier::Unsigned)},
|
||||
{make_unique<IntegerType>(8 * 17, IntegerType::Modifier::Unsigned)},
|
||||
{make_unique<IntegerType>(8 * 18, IntegerType::Modifier::Unsigned)},
|
||||
{make_unique<IntegerType>(8 * 19, IntegerType::Modifier::Unsigned)},
|
||||
{make_unique<IntegerType>(8 * 20, IntegerType::Modifier::Unsigned)},
|
||||
{make_unique<IntegerType>(8 * 21, IntegerType::Modifier::Unsigned)},
|
||||
{make_unique<IntegerType>(8 * 22, IntegerType::Modifier::Unsigned)},
|
||||
{make_unique<IntegerType>(8 * 23, IntegerType::Modifier::Unsigned)},
|
||||
{make_unique<IntegerType>(8 * 24, IntegerType::Modifier::Unsigned)},
|
||||
{make_unique<IntegerType>(8 * 25, IntegerType::Modifier::Unsigned)},
|
||||
{make_unique<IntegerType>(8 * 26, IntegerType::Modifier::Unsigned)},
|
||||
{make_unique<IntegerType>(8 * 27, IntegerType::Modifier::Unsigned)},
|
||||
{make_unique<IntegerType>(8 * 28, IntegerType::Modifier::Unsigned)},
|
||||
{make_unique<IntegerType>(8 * 29, IntegerType::Modifier::Unsigned)},
|
||||
{make_unique<IntegerType>(8 * 30, IntegerType::Modifier::Unsigned)},
|
||||
{make_unique<IntegerType>(8 * 31, IntegerType::Modifier::Unsigned)},
|
||||
{make_unique<IntegerType>(8 * 32, IntegerType::Modifier::Unsigned)}
|
||||
}};
|
||||
|
||||
array<unique_ptr<FixedBytesType>, 32> const TypeProvider::m_bytesM{{
|
||||
{make_unique<FixedBytesType>(1)},
|
||||
{make_unique<FixedBytesType>(2)},
|
||||
{make_unique<FixedBytesType>(3)},
|
||||
{make_unique<FixedBytesType>(4)},
|
||||
{make_unique<FixedBytesType>(5)},
|
||||
{make_unique<FixedBytesType>(6)},
|
||||
{make_unique<FixedBytesType>(7)},
|
||||
{make_unique<FixedBytesType>(8)},
|
||||
{make_unique<FixedBytesType>(9)},
|
||||
{make_unique<FixedBytesType>(10)},
|
||||
{make_unique<FixedBytesType>(11)},
|
||||
{make_unique<FixedBytesType>(12)},
|
||||
{make_unique<FixedBytesType>(13)},
|
||||
{make_unique<FixedBytesType>(14)},
|
||||
{make_unique<FixedBytesType>(15)},
|
||||
{make_unique<FixedBytesType>(16)},
|
||||
{make_unique<FixedBytesType>(17)},
|
||||
{make_unique<FixedBytesType>(18)},
|
||||
{make_unique<FixedBytesType>(19)},
|
||||
{make_unique<FixedBytesType>(20)},
|
||||
{make_unique<FixedBytesType>(21)},
|
||||
{make_unique<FixedBytesType>(22)},
|
||||
{make_unique<FixedBytesType>(23)},
|
||||
{make_unique<FixedBytesType>(24)},
|
||||
{make_unique<FixedBytesType>(25)},
|
||||
{make_unique<FixedBytesType>(26)},
|
||||
{make_unique<FixedBytesType>(27)},
|
||||
{make_unique<FixedBytesType>(28)},
|
||||
{make_unique<FixedBytesType>(29)},
|
||||
{make_unique<FixedBytesType>(30)},
|
||||
{make_unique<FixedBytesType>(31)},
|
||||
{make_unique<FixedBytesType>(32)}
|
||||
}};
|
||||
|
||||
array<unique_ptr<MagicType>, 4> const TypeProvider::m_magicTypes{{
|
||||
{make_unique<MagicType>(MagicType::Kind::Block)},
|
||||
{make_unique<MagicType>(MagicType::Kind::Message)},
|
||||
{make_unique<MagicType>(MagicType::Kind::Transaction)},
|
||||
{make_unique<MagicType>(MagicType::Kind::ABI)}
|
||||
// MetaType is stored separately
|
||||
}};
|
||||
|
||||
inline void clearCache(Type const& type)
|
||||
{
|
||||
type.clearCache();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void clearCache(unique_ptr<T> const& type)
|
||||
{
|
||||
// Some lazy-initialized types might not exist yet.
|
||||
if (type)
|
||||
type->clearCache();
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
inline void clearCaches(Container& container)
|
||||
{
|
||||
for (auto const& e: container)
|
||||
clearCache(e);
|
||||
}
|
||||
|
||||
void TypeProvider::reset()
|
||||
{
|
||||
clearCache(m_boolType);
|
||||
clearCache(m_inaccessibleDynamicType);
|
||||
clearCache(m_bytesStorageType);
|
||||
clearCache(m_bytesMemoryType);
|
||||
clearCache(m_stringStorageType);
|
||||
clearCache(m_stringMemoryType);
|
||||
clearCache(m_emptyTupleType);
|
||||
clearCache(m_payableAddressType);
|
||||
clearCache(m_addressType);
|
||||
clearCaches(instance().m_intM);
|
||||
clearCaches(instance().m_uintM);
|
||||
clearCaches(instance().m_bytesM);
|
||||
clearCaches(instance().m_magicTypes);
|
||||
|
||||
instance().m_generalTypes.clear();
|
||||
instance().m_stringLiteralTypes.clear();
|
||||
instance().m_ufixedMxN.clear();
|
||||
instance().m_fixedMxN.clear();
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
inline T const* TypeProvider::createAndGet(Args&& ... _args)
|
||||
{
|
||||
instance().m_generalTypes.emplace_back(make_unique<T>(std::forward<Args>(_args)...));
|
||||
return static_cast<T const*>(instance().m_generalTypes.back().get());
|
||||
}
|
||||
|
||||
Type const* TypeProvider::fromElementaryTypeName(ElementaryTypeNameToken const& _type)
|
||||
{
|
||||
solAssert(
|
||||
TokenTraits::isElementaryTypeName(_type.token()),
|
||||
"Expected an elementary type name but got " + _type.toString()
|
||||
);
|
||||
|
||||
unsigned const m = _type.firstNumber();
|
||||
unsigned const n = _type.secondNumber();
|
||||
|
||||
switch (_type.token())
|
||||
{
|
||||
case Token::IntM:
|
||||
return integerType(m, IntegerType::Modifier::Signed);
|
||||
case Token::UIntM:
|
||||
return integerType(m, IntegerType::Modifier::Unsigned);
|
||||
case Token::Byte:
|
||||
return byteType();
|
||||
case Token::BytesM:
|
||||
return fixedBytesType(m);
|
||||
case Token::FixedMxN:
|
||||
return fixedPointType(m, n, FixedPointType::Modifier::Signed);
|
||||
case Token::UFixedMxN:
|
||||
return fixedPointType(m, n, FixedPointType::Modifier::Unsigned);
|
||||
case Token::Int:
|
||||
return integerType(256, IntegerType::Modifier::Signed);
|
||||
case Token::UInt:
|
||||
return integerType(256, IntegerType::Modifier::Unsigned);
|
||||
case Token::Fixed:
|
||||
return fixedPointType(128, 18, FixedPointType::Modifier::Signed);
|
||||
case Token::UFixed:
|
||||
return fixedPointType(128, 18, FixedPointType::Modifier::Unsigned);
|
||||
case Token::Address:
|
||||
return addressType();
|
||||
case Token::Bool:
|
||||
return boolType();
|
||||
case Token::Bytes:
|
||||
return bytesStorageType();
|
||||
case Token::String:
|
||||
return stringStorageType();
|
||||
default:
|
||||
solAssert(
|
||||
false,
|
||||
"Unable to convert elementary typename " + _type.toString() + " to type."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
TypePointer TypeProvider::fromElementaryTypeName(string const& _name)
|
||||
{
|
||||
vector<string> nameParts;
|
||||
boost::split(nameParts, _name, boost::is_any_of(" "));
|
||||
solAssert(nameParts.size() == 1 || nameParts.size() == 2, "Cannot parse elementary type: " + _name);
|
||||
|
||||
Token token;
|
||||
unsigned short firstNum, secondNum;
|
||||
tie(token, firstNum, secondNum) = TokenTraits::fromIdentifierOrKeyword(nameParts[0]);
|
||||
|
||||
auto t = fromElementaryTypeName(ElementaryTypeNameToken(token, firstNum, secondNum));
|
||||
if (auto* ref = dynamic_cast<ReferenceType const*>(t))
|
||||
{
|
||||
DataLocation location = DataLocation::Storage;
|
||||
if (nameParts.size() == 2)
|
||||
{
|
||||
if (nameParts[1] == "storage")
|
||||
location = DataLocation::Storage;
|
||||
else if (nameParts[1] == "calldata")
|
||||
location = DataLocation::CallData;
|
||||
else if (nameParts[1] == "memory")
|
||||
location = DataLocation::Memory;
|
||||
else
|
||||
solAssert(false, "Unknown data location: " + nameParts[1]);
|
||||
}
|
||||
return withLocation(ref, location, true);
|
||||
}
|
||||
else if (t->category() == Type::Category::Address)
|
||||
{
|
||||
if (nameParts.size() == 2)
|
||||
{
|
||||
if (nameParts[1] == "payable")
|
||||
return payableAddressType();
|
||||
else
|
||||
solAssert(false, "Invalid state mutability for address type: " + nameParts[1]);
|
||||
}
|
||||
return addressType();
|
||||
}
|
||||
else
|
||||
{
|
||||
solAssert(nameParts.size() == 1, "Storage location suffix only allowed for reference types");
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
ArrayType const* TypeProvider::bytesStorageType()
|
||||
{
|
||||
if (!m_bytesStorageType)
|
||||
m_bytesStorageType = make_unique<ArrayType>(DataLocation::Storage, false);
|
||||
return m_bytesStorageType.get();
|
||||
}
|
||||
|
||||
ArrayType const* TypeProvider::bytesMemoryType()
|
||||
{
|
||||
if (!m_bytesMemoryType)
|
||||
m_bytesMemoryType = make_unique<ArrayType>(DataLocation::Memory, false);
|
||||
return m_bytesMemoryType.get();
|
||||
}
|
||||
|
||||
ArrayType const* TypeProvider::stringStorageType()
|
||||
{
|
||||
if (!m_stringStorageType)
|
||||
m_stringStorageType = make_unique<ArrayType>(DataLocation::Storage, true);
|
||||
return m_stringStorageType.get();
|
||||
}
|
||||
|
||||
ArrayType const* TypeProvider::stringMemoryType()
|
||||
{
|
||||
if (!m_stringMemoryType)
|
||||
m_stringMemoryType = make_unique<ArrayType>(DataLocation::Memory, true);
|
||||
return m_stringMemoryType.get();
|
||||
}
|
||||
|
||||
TypePointer TypeProvider::forLiteral(Literal const& _literal)
|
||||
{
|
||||
switch (_literal.token())
|
||||
{
|
||||
case Token::TrueLiteral:
|
||||
case Token::FalseLiteral:
|
||||
return boolType();
|
||||
case Token::Number:
|
||||
return rationalNumberType(_literal);
|
||||
case Token::StringLiteral:
|
||||
return stringLiteralType(_literal.value());
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
RationalNumberType const* TypeProvider::rationalNumberType(Literal const& _literal)
|
||||
{
|
||||
solAssert(_literal.token() == Token::Number, "");
|
||||
std::tuple<bool, rational> validLiteral = RationalNumberType::isValidLiteral(_literal);
|
||||
if (std::get<0>(validLiteral))
|
||||
{
|
||||
TypePointer compatibleBytesType = nullptr;
|
||||
if (_literal.isHexNumber())
|
||||
{
|
||||
size_t const digitCount = _literal.valueWithoutUnderscores().length() - 2;
|
||||
if (digitCount % 2 == 0 && (digitCount / 2) <= 32)
|
||||
compatibleBytesType = fixedBytesType(digitCount / 2);
|
||||
}
|
||||
|
||||
return rationalNumberType(std::get<1>(validLiteral), compatibleBytesType);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
StringLiteralType const* TypeProvider::stringLiteralType(string const& literal)
|
||||
{
|
||||
auto i = instance().m_stringLiteralTypes.find(literal);
|
||||
if (i != instance().m_stringLiteralTypes.end())
|
||||
return i->second.get();
|
||||
else
|
||||
return instance().m_stringLiteralTypes.emplace(literal, make_unique<StringLiteralType>(literal)).first->second.get();
|
||||
}
|
||||
|
||||
FixedPointType const* TypeProvider::fixedPointType(unsigned m, unsigned n, FixedPointType::Modifier _modifier)
|
||||
{
|
||||
auto& map = _modifier == FixedPointType::Modifier::Unsigned ? instance().m_ufixedMxN : instance().m_fixedMxN;
|
||||
|
||||
auto i = map.find(make_pair(m, n));
|
||||
if (i != map.end())
|
||||
return i->second.get();
|
||||
|
||||
return map.emplace(
|
||||
make_pair(m, n),
|
||||
make_unique<FixedPointType>(m, n, _modifier)
|
||||
).first->second.get();
|
||||
}
|
||||
|
||||
TupleType const* TypeProvider::tupleType(vector<Type const*> members)
|
||||
{
|
||||
if (members.empty())
|
||||
return &m_emptyTupleType;
|
||||
|
||||
return createAndGet<TupleType>(move(members));
|
||||
}
|
||||
|
||||
ReferenceType const* TypeProvider::withLocation(ReferenceType const* _type, DataLocation _location, bool _isPointer)
|
||||
{
|
||||
if (_type->location() == _location && _type->isPointer() == _isPointer)
|
||||
return _type;
|
||||
|
||||
instance().m_generalTypes.emplace_back(_type->copyForLocation(_location, _isPointer));
|
||||
return static_cast<ReferenceType const*>(instance().m_generalTypes.back().get());
|
||||
}
|
||||
|
||||
FunctionType const* TypeProvider::functionType(FunctionDefinition const& _function, bool _isInternal)
|
||||
{
|
||||
return createAndGet<FunctionType>(_function, _isInternal);
|
||||
}
|
||||
|
||||
FunctionType const* TypeProvider::functionType(VariableDeclaration const& _varDecl)
|
||||
{
|
||||
return createAndGet<FunctionType>(_varDecl);
|
||||
}
|
||||
|
||||
FunctionType const* TypeProvider::functionType(EventDefinition const& _def)
|
||||
{
|
||||
return createAndGet<FunctionType>(_def);
|
||||
}
|
||||
|
||||
FunctionType const* TypeProvider::functionType(FunctionTypeName const& _typeName)
|
||||
{
|
||||
return createAndGet<FunctionType>(_typeName);
|
||||
}
|
||||
|
||||
FunctionType const* TypeProvider::functionType(
|
||||
strings const& _parameterTypes,
|
||||
strings const& _returnParameterTypes,
|
||||
FunctionType::Kind _kind,
|
||||
bool _arbitraryParameters,
|
||||
StateMutability _stateMutability
|
||||
)
|
||||
{
|
||||
return createAndGet<FunctionType>(
|
||||
_parameterTypes, _returnParameterTypes,
|
||||
_kind, _arbitraryParameters, _stateMutability
|
||||
);
|
||||
}
|
||||
|
||||
FunctionType const* TypeProvider::functionType(
|
||||
TypePointers const& _parameterTypes,
|
||||
TypePointers const& _returnParameterTypes,
|
||||
strings _parameterNames,
|
||||
strings _returnParameterNames,
|
||||
FunctionType::Kind _kind,
|
||||
bool _arbitraryParameters,
|
||||
StateMutability _stateMutability,
|
||||
Declaration const* _declaration,
|
||||
bool _gasSet,
|
||||
bool _valueSet,
|
||||
bool _bound
|
||||
)
|
||||
{
|
||||
return createAndGet<FunctionType>(
|
||||
_parameterTypes,
|
||||
_returnParameterTypes,
|
||||
_parameterNames,
|
||||
_returnParameterNames,
|
||||
_kind,
|
||||
_arbitraryParameters,
|
||||
_stateMutability,
|
||||
_declaration,
|
||||
_gasSet,
|
||||
_valueSet,
|
||||
_bound
|
||||
);
|
||||
}
|
||||
|
||||
RationalNumberType const* TypeProvider::rationalNumberType(rational const& _value, Type const* _compatibleBytesType)
|
||||
{
|
||||
return createAndGet<RationalNumberType>(_value, _compatibleBytesType);
|
||||
}
|
||||
|
||||
ArrayType const* TypeProvider::arrayType(DataLocation _location, bool _isString)
|
||||
{
|
||||
if (_isString)
|
||||
{
|
||||
if (_location == DataLocation::Storage)
|
||||
return stringStorageType();
|
||||
if (_location == DataLocation::Memory)
|
||||
return stringMemoryType();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_location == DataLocation::Storage)
|
||||
return bytesStorageType();
|
||||
if (_location == DataLocation::Memory)
|
||||
return bytesMemoryType();
|
||||
}
|
||||
return createAndGet<ArrayType>(_location, _isString);
|
||||
}
|
||||
|
||||
ArrayType const* TypeProvider::arrayType(DataLocation _location, Type const* _baseType)
|
||||
{
|
||||
return createAndGet<ArrayType>(_location, _baseType);
|
||||
}
|
||||
|
||||
ArrayType const* TypeProvider::arrayType(DataLocation _location, Type const* _baseType, u256 const& _length)
|
||||
{
|
||||
return createAndGet<ArrayType>(_location, _baseType, _length);
|
||||
}
|
||||
|
||||
ContractType const* TypeProvider::contractType(ContractDefinition const& _contractDef, bool _isSuper)
|
||||
{
|
||||
return createAndGet<ContractType>(_contractDef, _isSuper);
|
||||
}
|
||||
|
||||
EnumType const* TypeProvider::enumType(EnumDefinition const& _enumDef)
|
||||
{
|
||||
return createAndGet<EnumType>(_enumDef);
|
||||
}
|
||||
|
||||
ModuleType const* TypeProvider::moduleType(SourceUnit const& _source)
|
||||
{
|
||||
return createAndGet<ModuleType>(_source);
|
||||
}
|
||||
|
||||
TypeType const* TypeProvider::typeType(Type const* _actualType)
|
||||
{
|
||||
return createAndGet<TypeType>(_actualType);
|
||||
}
|
||||
|
||||
StructType const* TypeProvider::structType(StructDefinition const& _struct, DataLocation _location)
|
||||
{
|
||||
return createAndGet<StructType>(_struct, _location);
|
||||
}
|
||||
|
||||
ModifierType const* TypeProvider::modifierType(ModifierDefinition const& _def)
|
||||
{
|
||||
return createAndGet<ModifierType>(_def);
|
||||
}
|
||||
|
||||
MagicType const* TypeProvider::magicType(MagicType::Kind _kind)
|
||||
{
|
||||
solAssert(_kind != MagicType::Kind::MetaType, "MetaType is handled separately");
|
||||
return m_magicTypes.at(static_cast<size_t>(_kind)).get();
|
||||
}
|
||||
|
||||
MagicType const* TypeProvider::metaType(Type const* _type)
|
||||
{
|
||||
solAssert(_type && _type->category() == Type::Category::Contract, "Only contracts supported for now.");
|
||||
return createAndGet<MagicType>(_type);
|
||||
}
|
||||
|
||||
MappingType const* TypeProvider::mappingType(Type const* _keyType, Type const* _valueType)
|
||||
{
|
||||
return createAndGet<MappingType>(_keyType, _valueType);
|
||||
}
|
224
libsolidity/ast/TypeProvider.h
Normal file
224
libsolidity/ast/TypeProvider.h
Normal file
@ -0,0 +1,224 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libsolidity/ast/Types.h>
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
namespace dev
|
||||
{
|
||||
namespace solidity
|
||||
{
|
||||
|
||||
/**
|
||||
* API for accessing the Solidity Type System.
|
||||
*
|
||||
* This is the Solidity Compiler's type provider. Use it to request for types. The caller does
|
||||
* <b>not</b> own the types.
|
||||
*
|
||||
* It is not recommended to explicitly instantiate types unless you really know what and why
|
||||
* you are doing it.
|
||||
*/
|
||||
class TypeProvider
|
||||
{
|
||||
public:
|
||||
TypeProvider() = default;
|
||||
TypeProvider(TypeProvider&&) = default;
|
||||
TypeProvider(TypeProvider const&) = delete;
|
||||
TypeProvider& operator=(TypeProvider&&) = default;
|
||||
TypeProvider& operator=(TypeProvider const&) = delete;
|
||||
~TypeProvider() = default;
|
||||
|
||||
/// Resets state of this TypeProvider to initial state, wiping all mutable types.
|
||||
/// This invalidates all dangling pointers to types provided by this TypeProvider.
|
||||
static void reset();
|
||||
|
||||
/// @name Factory functions
|
||||
/// Factory functions that convert an AST @ref TypeName to a Type.
|
||||
static Type const* fromElementaryTypeName(ElementaryTypeNameToken const& _type);
|
||||
|
||||
/// Converts a given elementary type name with optional data location
|
||||
/// suffix " storage", " calldata" or " memory" to a type pointer. If suffix not given, defaults to " storage".
|
||||
static TypePointer fromElementaryTypeName(std::string const& _name);
|
||||
|
||||
/// @returns boolean type.
|
||||
static BoolType const* boolType() noexcept { return &m_boolType; }
|
||||
|
||||
static FixedBytesType const* byteType() { return fixedBytesType(1); }
|
||||
static FixedBytesType const* fixedBytesType(unsigned m) { return m_bytesM.at(m - 1).get(); }
|
||||
|
||||
static ArrayType const* bytesStorageType();
|
||||
static ArrayType const* bytesMemoryType();
|
||||
static ArrayType const* stringStorageType();
|
||||
static ArrayType const* stringMemoryType();
|
||||
|
||||
/// Constructor for a byte array ("bytes") and string.
|
||||
static ArrayType const* arrayType(DataLocation _location, bool _isString = false);
|
||||
|
||||
/// Constructor for a dynamically sized array type ("type[]")
|
||||
static ArrayType const* arrayType(DataLocation _location, Type const* _baseType);
|
||||
|
||||
/// Constructor for a fixed-size array type ("type[20]")
|
||||
static ArrayType const* arrayType(DataLocation _location, Type const* _baseType, u256 const& _length);
|
||||
|
||||
static AddressType const* payableAddressType() noexcept { return &m_payableAddressType; }
|
||||
static AddressType const* addressType() noexcept { return &m_addressType; }
|
||||
|
||||
static IntegerType const* integerType(unsigned _bits, IntegerType::Modifier _modifier)
|
||||
{
|
||||
solAssert((_bits % 8) == 0, "");
|
||||
if (_modifier == IntegerType::Modifier::Unsigned)
|
||||
return m_uintM.at(_bits / 8 - 1).get();
|
||||
else
|
||||
return m_intM.at(_bits / 8 - 1).get();
|
||||
}
|
||||
static IntegerType const* uint(unsigned _bits) { return integerType(_bits, IntegerType::Modifier::Unsigned); }
|
||||
|
||||
static IntegerType const* uint256() { return uint(256); }
|
||||
|
||||
static FixedPointType const* fixedPointType(unsigned m, unsigned n, FixedPointType::Modifier _modifier);
|
||||
|
||||
static StringLiteralType const* stringLiteralType(std::string const& literal);
|
||||
|
||||
/// @param members the member types the tuple type must contain. This is passed by value on purspose.
|
||||
/// @returns a tuple type with the given members.
|
||||
static TupleType const* tupleType(std::vector<Type const*> members);
|
||||
|
||||
static TupleType const* emptyTupleType() noexcept { return &m_emptyTupleType; }
|
||||
|
||||
static ReferenceType const* withLocation(ReferenceType const* _type, DataLocation _location, bool _isPointer);
|
||||
|
||||
/// @returns a copy of @a _type having the same location as this (and is not a pointer type)
|
||||
/// if _type is a reference type and an unmodified copy of _type otherwise.
|
||||
/// This function is mostly useful to modify inner types appropriately.
|
||||
static Type const* withLocationIfReference(DataLocation _location, Type const* _type)
|
||||
{
|
||||
if (auto refType = dynamic_cast<ReferenceType const*>(_type))
|
||||
return withLocation(refType, _location, false);
|
||||
|
||||
return _type;
|
||||
}
|
||||
|
||||
/// @returns the internally-facing or externally-facing type of a function.
|
||||
static FunctionType const* functionType(FunctionDefinition const& _function, bool _isInternal = true);
|
||||
|
||||
/// @returns the accessor function type of a state variable.
|
||||
static FunctionType const* functionType(VariableDeclaration const& _varDecl);
|
||||
|
||||
/// @returns the function type of an event.
|
||||
static FunctionType const* functionType(EventDefinition const& _event);
|
||||
|
||||
/// @returns the type of a function type name.
|
||||
static FunctionType const* functionType(FunctionTypeName const& _typeName);
|
||||
|
||||
/// @returns the function type to be used for a plain type (not derived from a declaration).
|
||||
static FunctionType const* functionType(
|
||||
strings const& _parameterTypes,
|
||||
strings const& _returnParameterTypes,
|
||||
FunctionType::Kind _kind = FunctionType::Kind::Internal,
|
||||
bool _arbitraryParameters = false,
|
||||
StateMutability _stateMutability = StateMutability::NonPayable
|
||||
);
|
||||
|
||||
/// @returns a highly customized FunctionType, use with care.
|
||||
static FunctionType const* functionType(
|
||||
TypePointers const& _parameterTypes,
|
||||
TypePointers const& _returnParameterTypes,
|
||||
strings _parameterNames = strings{},
|
||||
strings _returnParameterNames = strings{},
|
||||
FunctionType::Kind _kind = FunctionType::Kind::Internal,
|
||||
bool _arbitraryParameters = false,
|
||||
StateMutability _stateMutability = StateMutability::NonPayable,
|
||||
Declaration const* _declaration = nullptr,
|
||||
bool _gasSet = false,
|
||||
bool _valueSet = false,
|
||||
bool _bound = false
|
||||
);
|
||||
|
||||
/// Auto-detect the proper type for a literal. @returns an empty pointer if the literal does
|
||||
/// not fit any type.
|
||||
static TypePointer forLiteral(Literal const& _literal);
|
||||
static RationalNumberType const* rationalNumberType(Literal const& _literal);
|
||||
|
||||
static RationalNumberType const* rationalNumberType(
|
||||
rational const& _value,
|
||||
Type const* _compatibleBytesType = nullptr
|
||||
);
|
||||
|
||||
static ContractType const* contractType(ContractDefinition const& _contract, bool _isSuper = false);
|
||||
|
||||
static InaccessibleDynamicType const* inaccessibleDynamicType() noexcept { return &m_inaccessibleDynamicType; }
|
||||
|
||||
/// @returns the type of an enum instance for given definition, there is one distinct type per enum definition.
|
||||
static EnumType const* enumType(EnumDefinition const& _enum);
|
||||
|
||||
/// @returns special type for imported modules. These mainly give access to their scope via members.
|
||||
static ModuleType const* moduleType(SourceUnit const& _source);
|
||||
|
||||
static TypeType const* typeType(Type const* _actualType);
|
||||
|
||||
static StructType const* structType(StructDefinition const& _struct, DataLocation _location);
|
||||
|
||||
static ModifierType const* modifierType(ModifierDefinition const& _modifierDef);
|
||||
|
||||
static MagicType const* magicType(MagicType::Kind _kind);
|
||||
|
||||
static MagicType const* metaType(Type const* _type);
|
||||
|
||||
static MappingType const* mappingType(Type const* _keyType, Type const* _valueType);
|
||||
|
||||
private:
|
||||
/// Global TypeProvider instance.
|
||||
static TypeProvider& instance()
|
||||
{
|
||||
static TypeProvider _provider;
|
||||
return _provider;
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
static inline T const* createAndGet(Args&& ... _args);
|
||||
|
||||
static BoolType const m_boolType;
|
||||
static InaccessibleDynamicType const m_inaccessibleDynamicType;
|
||||
|
||||
/// These are lazy-initialized because they depend on `byte` being available.
|
||||
static std::unique_ptr<ArrayType> m_bytesStorageType;
|
||||
static std::unique_ptr<ArrayType> m_bytesMemoryType;
|
||||
static std::unique_ptr<ArrayType> m_stringStorageType;
|
||||
static std::unique_ptr<ArrayType> m_stringMemoryType;
|
||||
|
||||
static TupleType const m_emptyTupleType;
|
||||
static AddressType const m_payableAddressType;
|
||||
static AddressType const m_addressType;
|
||||
static std::array<std::unique_ptr<IntegerType>, 32> const m_intM;
|
||||
static std::array<std::unique_ptr<IntegerType>, 32> const m_uintM;
|
||||
static std::array<std::unique_ptr<FixedBytesType>, 32> const m_bytesM;
|
||||
static std::array<std::unique_ptr<MagicType>, 4> const m_magicTypes; ///< MagicType's except MetaType
|
||||
|
||||
std::map<std::pair<unsigned, unsigned>, std::unique_ptr<FixedPointType>> m_ufixedMxN{};
|
||||
std::map<std::pair<unsigned, unsigned>, std::unique_ptr<FixedPointType>> m_fixedMxN{};
|
||||
std::map<std::string, std::unique_ptr<StringLiteralType>> m_stringLiteralTypes{};
|
||||
std::vector<std::unique_ptr<Type>> m_generalTypes{};
|
||||
};
|
||||
|
||||
} // namespace solidity
|
||||
} // namespace dev
|
File diff suppressed because it is too large
Load Diff
@ -32,7 +32,6 @@
|
||||
#include <libdevcore/Result.h>
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/rational.hpp>
|
||||
|
||||
#include <map>
|
||||
@ -45,10 +44,11 @@ namespace dev
|
||||
namespace solidity
|
||||
{
|
||||
|
||||
class TypeProvider;
|
||||
class Type; // forward
|
||||
class FunctionType; // forward
|
||||
using TypePointer = std::shared_ptr<Type const>;
|
||||
using FunctionTypePointer = std::shared_ptr<FunctionType const>;
|
||||
using TypePointer = Type const*;
|
||||
using FunctionTypePointer = FunctionType const*;
|
||||
using TypePointers = std::vector<TypePointer>;
|
||||
using rational = boost::rational<dev::bigint>;
|
||||
using TypeResult = Result<TypePointer>;
|
||||
@ -94,7 +94,7 @@ class MemberList
|
||||
public:
|
||||
struct Member
|
||||
{
|
||||
Member(std::string const& _name, TypePointer const& _type, Declaration const* _declaration = nullptr):
|
||||
Member(std::string const& _name, Type const* _type, Declaration const* _declaration = nullptr):
|
||||
name(_name),
|
||||
type(_type),
|
||||
declaration(_declaration)
|
||||
@ -102,17 +102,18 @@ public:
|
||||
}
|
||||
|
||||
std::string name;
|
||||
TypePointer type;
|
||||
Type const* type;
|
||||
Declaration const* declaration = nullptr;
|
||||
};
|
||||
|
||||
using MemberMap = std::vector<Member>;
|
||||
|
||||
explicit MemberList(MemberMap const& _members): m_memberTypes(_members) {}
|
||||
|
||||
void combine(MemberList const& _other);
|
||||
TypePointer memberType(std::string const& _name) const
|
||||
{
|
||||
TypePointer type;
|
||||
TypePointer type = nullptr;
|
||||
for (auto const& it: m_memberTypes)
|
||||
if (it.name == _name)
|
||||
{
|
||||
@ -148,10 +149,16 @@ static_assert(std::is_nothrow_move_constructible<MemberList>::value, "MemberList
|
||||
/**
|
||||
* Abstract base class that forms the root of the type hierarchy.
|
||||
*/
|
||||
class Type: private boost::noncopyable, public std::enable_shared_from_this<Type>
|
||||
class Type
|
||||
{
|
||||
public:
|
||||
Type() = default;
|
||||
Type(Type const&) = delete;
|
||||
Type(Type&&) = delete;
|
||||
Type& operator=(Type const&) = delete;
|
||||
Type& operator=(Type&&) = delete;
|
||||
virtual ~Type() = default;
|
||||
|
||||
enum class Category
|
||||
{
|
||||
Address, Integer, RationalNumber, StringLiteral, Bool, FixedPoint, Array,
|
||||
@ -160,20 +167,8 @@ public:
|
||||
InaccessibleDynamic
|
||||
};
|
||||
|
||||
/// @{
|
||||
/// @name Factory functions
|
||||
/// Factory functions that convert an AST @ref TypeName to a Type.
|
||||
static TypePointer fromElementaryTypeName(ElementaryTypeNameToken const& _type);
|
||||
/// Converts a given elementary type name with optional data location
|
||||
/// suffix " storage", " calldata" or " memory" to a type pointer. If suffix not given, defaults to " storage".
|
||||
static TypePointer fromElementaryTypeName(std::string const& _name);
|
||||
/// @}
|
||||
|
||||
/// Auto-detect the proper type for a literal. @returns an empty pointer if the literal does
|
||||
/// not fit any type.
|
||||
static TypePointer forLiteral(Literal const& _literal);
|
||||
/// @returns a pointer to _a or _b if the other is implicitly convertible to it or nullptr otherwise
|
||||
static TypePointer commonType(TypePointer const& _a, TypePointer const& _b);
|
||||
static TypePointer commonType(Type const* _a, Type const* _b);
|
||||
|
||||
virtual Category category() const = 0;
|
||||
/// @returns a valid solidity identifier such that two types should compare equal if and
|
||||
@ -201,13 +196,13 @@ public:
|
||||
/// @returns the resulting type of applying the given unary operator or an empty pointer if
|
||||
/// this is not possible.
|
||||
/// The default implementation does not allow any unary operator.
|
||||
virtual TypeResult unaryOperatorResult(Token) const { return TypePointer(); }
|
||||
virtual TypeResult unaryOperatorResult(Token) const { return nullptr; }
|
||||
/// @returns the resulting type of applying the given binary operator or an empty pointer if
|
||||
/// this is not possible.
|
||||
/// The default implementation allows comparison operators if a common type exists
|
||||
virtual TypeResult binaryOperatorResult(Token _operator, TypePointer const& _other) const
|
||||
virtual TypeResult binaryOperatorResult(Token _operator, Type const* _other) const
|
||||
{
|
||||
return TokenTraits::isCompareOp(_operator) ? commonType(shared_from_this(), _other) : TypePointer();
|
||||
return TokenTraits::isCompareOp(_operator) ? commonType(this, _other) : nullptr;
|
||||
}
|
||||
|
||||
virtual bool operator==(Type const& _other) const { return category() == _other.category(); }
|
||||
@ -258,14 +253,14 @@ public:
|
||||
/// This returns the corresponding IntegerType or FixedPointType for RationalNumberType
|
||||
/// and the pointer type for storage reference types.
|
||||
/// Might return a null pointer if there is no fitting type.
|
||||
virtual TypePointer mobileType() const { return shared_from_this(); }
|
||||
virtual TypePointer mobileType() const { return this; }
|
||||
/// @returns true if this is a non-value type and the data of this type is stored at the
|
||||
/// given location.
|
||||
virtual bool dataStoredIn(DataLocation) const { return false; }
|
||||
/// @returns the type of a temporary during assignment to a variable of the given type.
|
||||
/// Specifically, returns the requested itself if it can be dynamically allocated (or is a value type)
|
||||
/// and the mobile type otherwise.
|
||||
virtual TypePointer closestTemporaryType(TypePointer const& _targetType) const
|
||||
virtual TypePointer closestTemporaryType(Type const* _targetType) const
|
||||
{
|
||||
return _targetType->dataStoredIn(DataLocation::Storage) ? mobileType() : _targetType;
|
||||
}
|
||||
@ -298,7 +293,7 @@ public:
|
||||
/// @returns a (simpler) type that is encoded in the same way for external function calls.
|
||||
/// This for example returns address for contract types.
|
||||
/// If there is no such type, returns an empty shared pointer.
|
||||
virtual TypePointer encodingType() const { return TypePointer(); }
|
||||
virtual TypePointer encodingType() const { return nullptr; }
|
||||
/// @returns the encoding type used under the given circumstances for the type of an expression
|
||||
/// when used for e.g. abi.encode(...) or the empty pointer if the object
|
||||
/// cannot be encoded.
|
||||
@ -311,7 +306,10 @@ public:
|
||||
/// If there is no such type, returns an empty shared pointer.
|
||||
/// @param _inLibrary if set, returns types as used in a library, e.g. struct and contract types
|
||||
/// are returned without modification.
|
||||
virtual TypeResult interfaceType(bool /*_inLibrary*/) const { return TypePointer(); }
|
||||
virtual TypeResult interfaceType(bool /*_inLibrary*/) const { return nullptr; }
|
||||
|
||||
/// Clears all internally cached values (if any).
|
||||
virtual void clearCache() const;
|
||||
|
||||
private:
|
||||
/// @returns a member list containing all members added to this type by `using for` directives.
|
||||
@ -335,18 +333,15 @@ protected:
|
||||
class AddressType: public Type
|
||||
{
|
||||
public:
|
||||
static AddressType& address() { static std::shared_ptr<AddressType> addr(std::make_shared<AddressType>(StateMutability::NonPayable)); return *addr; }
|
||||
static AddressType& addressPayable() { static std::shared_ptr<AddressType> addr(std::make_shared<AddressType>(StateMutability::Payable)); return *addr; }
|
||||
explicit AddressType(StateMutability _stateMutability);
|
||||
|
||||
Category category() const override { return Category::Address; }
|
||||
|
||||
explicit AddressType(StateMutability _stateMutability);
|
||||
|
||||
std::string richIdentifier() const override;
|
||||
BoolResult isImplicitlyConvertibleTo(Type const& _other) const override;
|
||||
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||
TypeResult unaryOperatorResult(Token _operator) const override;
|
||||
TypeResult binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
|
||||
TypeResult binaryOperatorResult(Token _operator, Type const* _other) const override;
|
||||
|
||||
bool operator==(Type const& _other) const override;
|
||||
|
||||
@ -362,8 +357,8 @@ public:
|
||||
|
||||
u256 literalValue(Literal const* _literal) const override;
|
||||
|
||||
TypePointer encodingType() const override { return shared_from_this(); }
|
||||
TypeResult interfaceType(bool) const override { return shared_from_this(); }
|
||||
TypePointer encodingType() const override { return this; }
|
||||
TypeResult interfaceType(bool) const override { return this; }
|
||||
|
||||
StateMutability stateMutability(void) const { return m_stateMutability; }
|
||||
|
||||
@ -382,17 +377,15 @@ public:
|
||||
Unsigned, Signed
|
||||
};
|
||||
|
||||
static IntegerType& uint256() { static std::shared_ptr<IntegerType> uint256(std::make_shared<IntegerType>(256)); return *uint256; }
|
||||
explicit IntegerType(unsigned _bits, Modifier _modifier = Modifier::Unsigned);
|
||||
|
||||
Category category() const override { return Category::Integer; }
|
||||
|
||||
explicit IntegerType(unsigned _bits, Modifier _modifier = Modifier::Unsigned);
|
||||
|
||||
std::string richIdentifier() const override;
|
||||
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||
TypeResult unaryOperatorResult(Token _operator) const override;
|
||||
TypeResult binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
|
||||
TypeResult binaryOperatorResult(Token _operator, Type const* _other) const override;
|
||||
|
||||
bool operator==(Type const& _other) const override;
|
||||
|
||||
@ -403,8 +396,8 @@ public:
|
||||
|
||||
std::string toString(bool _short) const override;
|
||||
|
||||
TypePointer encodingType() const override { return shared_from_this(); }
|
||||
TypeResult interfaceType(bool) const override { return shared_from_this(); }
|
||||
TypePointer encodingType() const override { return this; }
|
||||
TypeResult interfaceType(bool) const override { return this; }
|
||||
|
||||
unsigned numBits() const { return m_bits; }
|
||||
bool isSigned() const { return m_modifier == Modifier::Signed; }
|
||||
@ -413,8 +406,8 @@ public:
|
||||
bigint maxValue() const;
|
||||
|
||||
private:
|
||||
unsigned m_bits;
|
||||
Modifier m_modifier;
|
||||
unsigned const m_bits;
|
||||
Modifier const m_modifier;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -427,15 +420,15 @@ public:
|
||||
{
|
||||
Unsigned, Signed
|
||||
};
|
||||
Category category() const override { return Category::FixedPoint; }
|
||||
|
||||
explicit FixedPointType(unsigned _totalBits, unsigned _fractionalDigits, Modifier _modifier = Modifier::Unsigned);
|
||||
Category category() const override { return Category::FixedPoint; }
|
||||
|
||||
std::string richIdentifier() const override;
|
||||
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||
TypeResult unaryOperatorResult(Token _operator) const override;
|
||||
TypeResult binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
|
||||
TypeResult binaryOperatorResult(Token _operator, Type const* _other) const override;
|
||||
|
||||
bool operator==(Type const& _other) const override;
|
||||
|
||||
@ -446,8 +439,8 @@ public:
|
||||
|
||||
std::string toString(bool _short) const override;
|
||||
|
||||
TypePointer encodingType() const override { return shared_from_this(); }
|
||||
TypeResult interfaceType(bool) const override { return shared_from_this(); }
|
||||
TypePointer encodingType() const override { return this; }
|
||||
TypeResult interfaceType(bool) const override { return this; }
|
||||
|
||||
/// Number of bits used for this type in total.
|
||||
unsigned numBits() const { return m_totalBits; }
|
||||
@ -462,7 +455,7 @@ public:
|
||||
bigint minIntegerValue() const;
|
||||
|
||||
/// @returns the smallest integer type that can hold this type with fractional parts shifted to integers.
|
||||
std::shared_ptr<IntegerType> asIntegerType() const;
|
||||
IntegerType const* asIntegerType() const;
|
||||
|
||||
private:
|
||||
unsigned m_totalBits;
|
||||
@ -478,18 +471,16 @@ private:
|
||||
class RationalNumberType: public Type
|
||||
{
|
||||
public:
|
||||
explicit RationalNumberType(rational const& _value, Type const* _compatibleBytesType = nullptr):
|
||||
m_value(_value), m_compatibleBytesType(_compatibleBytesType)
|
||||
{}
|
||||
|
||||
Category category() const override { return Category::RationalNumber; }
|
||||
|
||||
static TypePointer forLiteral(Literal const& _literal);
|
||||
|
||||
explicit RationalNumberType(rational const& _value, TypePointer const& _compatibleBytesType = TypePointer()):
|
||||
m_value(_value), m_compatibleBytesType(_compatibleBytesType)
|
||||
{}
|
||||
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||
TypeResult unaryOperatorResult(Token _operator) const override;
|
||||
TypeResult binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
|
||||
TypeResult binaryOperatorResult(Token _operator, Type const* _other) const override;
|
||||
|
||||
std::string richIdentifier() const override;
|
||||
bool operator==(Type const& _other) const override;
|
||||
@ -502,11 +493,11 @@ public:
|
||||
TypePointer mobileType() const override;
|
||||
|
||||
/// @returns the smallest integer type that can hold the value or an empty pointer if not possible.
|
||||
std::shared_ptr<IntegerType const> integerType() const;
|
||||
IntegerType const* integerType() const;
|
||||
/// @returns the smallest fixed type that can hold the value or incurs the least precision loss,
|
||||
/// unless the value was truncated, then a suitable type will be chosen to indicate such event.
|
||||
/// If the integer part does not fit, returns an empty pointer.
|
||||
std::shared_ptr<FixedPointType const> fixedPointType() const;
|
||||
FixedPointType const* fixedPointType() const;
|
||||
|
||||
/// @returns true if the value is not an integer.
|
||||
bool isFractional() const { return m_value.denominator() != 1; }
|
||||
@ -517,6 +508,9 @@ public:
|
||||
/// @returns true if the value is zero.
|
||||
bool isZero() const { return m_value == 0; }
|
||||
|
||||
/// @returns true if the literal is a valid integer.
|
||||
static std::tuple<bool, rational> isValidLiteral(Literal const& _literal);
|
||||
|
||||
private:
|
||||
rational m_value;
|
||||
|
||||
@ -524,9 +518,6 @@ private:
|
||||
/// Empty for all rationals that are not directly parsed from hex literals.
|
||||
TypePointer m_compatibleBytesType;
|
||||
|
||||
/// @returns true if the literal is a valid integer.
|
||||
static std::tuple<bool, rational> isValidLiteral(Literal const& _literal);
|
||||
|
||||
/// @returns true if the literal is a valid rational number.
|
||||
static std::tuple<bool, rational> parseRational(std::string const& _value);
|
||||
|
||||
@ -541,14 +532,15 @@ private:
|
||||
class StringLiteralType: public Type
|
||||
{
|
||||
public:
|
||||
explicit StringLiteralType(Literal const& _literal);
|
||||
explicit StringLiteralType(std::string const& _value);
|
||||
|
||||
Category category() const override { return Category::StringLiteral; }
|
||||
|
||||
explicit StringLiteralType(Literal const& _literal);
|
||||
|
||||
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||
TypeResult binaryOperatorResult(Token, TypePointer const&) const override
|
||||
TypeResult binaryOperatorResult(Token, Type const*) const override
|
||||
{
|
||||
return TypePointer();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string richIdentifier() const override;
|
||||
@ -575,16 +567,16 @@ private:
|
||||
class FixedBytesType: public Type
|
||||
{
|
||||
public:
|
||||
Category category() const override { return Category::FixedBytes; }
|
||||
|
||||
explicit FixedBytesType(unsigned _bytes);
|
||||
|
||||
Category category() const override { return Category::FixedBytes; }
|
||||
|
||||
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||
std::string richIdentifier() const override;
|
||||
bool operator==(Type const& _other) const override;
|
||||
TypeResult unaryOperatorResult(Token _operator) const override;
|
||||
TypeResult binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
|
||||
TypeResult binaryOperatorResult(Token _operator, Type const* _other) const override;
|
||||
|
||||
unsigned calldataEncodedSize(bool _padded) const override { return _padded && m_bytes > 0 ? 32 : m_bytes; }
|
||||
unsigned storageBytes() const override { return m_bytes; }
|
||||
@ -593,8 +585,8 @@ public:
|
||||
|
||||
std::string toString(bool) const override { return "bytes" + dev::toString(m_bytes); }
|
||||
MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
|
||||
TypePointer encodingType() const override { return shared_from_this(); }
|
||||
TypeResult interfaceType(bool) const override { return shared_from_this(); }
|
||||
TypePointer encodingType() const override { return this; }
|
||||
TypeResult interfaceType(bool) const override { return this; }
|
||||
|
||||
unsigned numBytes() const { return m_bytes; }
|
||||
|
||||
@ -611,7 +603,7 @@ public:
|
||||
Category category() const override { return Category::Bool; }
|
||||
std::string richIdentifier() const override { return "t_bool"; }
|
||||
TypeResult unaryOperatorResult(Token _operator) const override;
|
||||
TypeResult binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
|
||||
TypeResult binaryOperatorResult(Token _operator, Type const* _other) const override;
|
||||
|
||||
unsigned calldataEncodedSize(bool _padded) const override{ return _padded ? 32 : 1; }
|
||||
unsigned storageBytes() const override { return 1; }
|
||||
@ -620,8 +612,8 @@ public:
|
||||
|
||||
std::string toString(bool) const override { return "bool"; }
|
||||
u256 literalValue(Literal const* _literal) const override;
|
||||
TypePointer encodingType() const override { return shared_from_this(); }
|
||||
TypeResult interfaceType(bool) const override { return shared_from_this(); }
|
||||
TypePointer encodingType() const override { return this; }
|
||||
TypeResult interfaceType(bool) const override { return this; }
|
||||
};
|
||||
|
||||
/**
|
||||
@ -630,22 +622,24 @@ public:
|
||||
*/
|
||||
class ReferenceType: public Type
|
||||
{
|
||||
public:
|
||||
protected:
|
||||
explicit ReferenceType(DataLocation _location): m_location(_location) {}
|
||||
|
||||
public:
|
||||
DataLocation location() const { return m_location; }
|
||||
|
||||
TypeResult unaryOperatorResult(Token _operator) const override;
|
||||
TypeResult binaryOperatorResult(Token, TypePointer const&) const override
|
||||
TypeResult binaryOperatorResult(Token, Type const*) const override
|
||||
{
|
||||
return TypePointer();
|
||||
return nullptr;
|
||||
}
|
||||
unsigned memoryHeadSize() const override { return 32; }
|
||||
|
||||
/// @returns a copy of this type with location (recursively) changed to @a _location,
|
||||
/// whereas isPointer is only shallowly changed - the deep copy is always a bound reference.
|
||||
virtual TypePointer copyForLocation(DataLocation _location, bool _isPointer) const = 0;
|
||||
virtual std::unique_ptr<ReferenceType> copyForLocation(DataLocation _location, bool _isPointer) const = 0;
|
||||
|
||||
TypePointer mobileType() const override { return copyForLocation(m_location, true); }
|
||||
TypePointer mobileType() const override { return withLocation(m_location, true); }
|
||||
bool dataStoredIn(DataLocation _location) const override { return m_location == _location; }
|
||||
bool hasSimpleZeroValueInMemory() const override { return false; }
|
||||
|
||||
@ -663,10 +657,12 @@ public:
|
||||
/// @returns a copy of @a _type having the same location as this (and is not a pointer type)
|
||||
/// if _type is a reference type and an unmodified copy of _type otherwise.
|
||||
/// This function is mostly useful to modify inner types appropriately.
|
||||
static TypePointer copyForLocationIfReference(DataLocation _location, TypePointer const& _type);
|
||||
static Type const* copyForLocationIfReference(DataLocation _location, Type const* _type);
|
||||
|
||||
Type const* withLocation(DataLocation _location, bool _isPointer) const;
|
||||
|
||||
protected:
|
||||
TypePointer copyForLocationIfReference(TypePointer const& _type) const;
|
||||
Type const* copyForLocationIfReference(Type const* _type) const;
|
||||
/// @returns a human-readable description of the reference part of the type.
|
||||
std::string stringForReferencePart() const;
|
||||
/// @returns the suffix computed from the reference part to be used by identifier();
|
||||
@ -686,32 +682,26 @@ protected:
|
||||
class ArrayType: public ReferenceType
|
||||
{
|
||||
public:
|
||||
static ArrayType& bytesMemory() { static std::shared_ptr<ArrayType> addr(std::make_shared<ArrayType>(DataLocation::Memory)); return *addr; }
|
||||
static ArrayType& stringMemory() { static std::shared_ptr<ArrayType> addr(std::make_shared<ArrayType>(DataLocation::Memory, true)); return *addr; }
|
||||
|
||||
Category category() const override { return Category::Array; }
|
||||
|
||||
/// Constructor for a byte array ("bytes") and string.
|
||||
explicit ArrayType(DataLocation _location, bool _isString = false):
|
||||
ReferenceType(_location),
|
||||
m_arrayKind(_isString ? ArrayKind::String : ArrayKind::Bytes),
|
||||
m_baseType(std::make_shared<FixedBytesType>(1))
|
||||
{
|
||||
}
|
||||
explicit ArrayType(DataLocation _location, bool _isString = false);
|
||||
|
||||
/// Constructor for a dynamically sized array type ("type[]")
|
||||
ArrayType(DataLocation _location, TypePointer const& _baseType):
|
||||
ArrayType(DataLocation _location, Type const* _baseType):
|
||||
ReferenceType(_location),
|
||||
m_baseType(copyForLocationIfReference(_baseType))
|
||||
{
|
||||
}
|
||||
|
||||
/// Constructor for a fixed-size array type ("type[20]")
|
||||
ArrayType(DataLocation _location, TypePointer const& _baseType, u256 const& _length):
|
||||
ArrayType(DataLocation _location, Type const* _baseType, u256 const& _length):
|
||||
ReferenceType(_location),
|
||||
m_baseType(copyForLocationIfReference(_baseType)),
|
||||
m_hasDynamicLength(false),
|
||||
m_length(_length)
|
||||
{}
|
||||
|
||||
Category category() const override { return Category::Array; }
|
||||
|
||||
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||
std::string richIdentifier() const override;
|
||||
@ -737,11 +727,11 @@ public:
|
||||
bool isByteArray() const { return m_arrayKind != ArrayKind::Ordinary; }
|
||||
/// @returns true if this is a string
|
||||
bool isString() const { return m_arrayKind == ArrayKind::String; }
|
||||
TypePointer const& baseType() const { solAssert(!!m_baseType, ""); return m_baseType;}
|
||||
Type const* baseType() const { solAssert(!!m_baseType, ""); return m_baseType; }
|
||||
u256 const& length() const { return m_length; }
|
||||
u256 memorySize() const;
|
||||
|
||||
TypePointer copyForLocation(DataLocation _location, bool _isPointer) const override;
|
||||
std::unique_ptr<ReferenceType> copyForLocation(DataLocation _location, bool _isPointer) const override;
|
||||
|
||||
/// The offset to advance in calldata to move from one array element to the next.
|
||||
unsigned calldataStride() const { return isByteArray() ? 1 : m_baseType->calldataEncodedSize(); }
|
||||
@ -750,6 +740,8 @@ public:
|
||||
/// The offset to advance in storage to move from one array element to the next.
|
||||
unsigned storageStride() const { return isByteArray() ? 1 : m_baseType->storageBytes(); }
|
||||
|
||||
void clearCache() const override;
|
||||
|
||||
private:
|
||||
/// String is interpreted as a subtype of Bytes.
|
||||
enum class ArrayKind { Ordinary, Bytes, String };
|
||||
@ -758,7 +750,7 @@ private:
|
||||
|
||||
///< Byte arrays ("bytes") and strings have different semantics from ordinary arrays.
|
||||
ArrayKind m_arrayKind = ArrayKind::Ordinary;
|
||||
TypePointer m_baseType;
|
||||
Type const* m_baseType;
|
||||
bool m_hasDynamicLength = true;
|
||||
u256 m_length;
|
||||
mutable boost::optional<TypeResult> m_interfaceType;
|
||||
@ -771,9 +763,10 @@ private:
|
||||
class ContractType: public Type
|
||||
{
|
||||
public:
|
||||
Category category() const override { return Category::Contract; }
|
||||
explicit ContractType(ContractDefinition const& _contract, bool _super = false):
|
||||
m_contract(_contract), m_super(_super) {}
|
||||
|
||||
Category category() const override { return Category::Contract; }
|
||||
/// Contracts can be implicitly converted only to base contracts.
|
||||
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||
/// Contracts can only be explicitly converted to address types and base contracts.
|
||||
@ -795,17 +788,14 @@ public:
|
||||
std::string canonicalName() const override;
|
||||
|
||||
MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
|
||||
TypePointer encodingType() const override
|
||||
{
|
||||
if (isSuper())
|
||||
return TypePointer{};
|
||||
return std::make_shared<AddressType>(isPayable() ? StateMutability::Payable : StateMutability::NonPayable);
|
||||
}
|
||||
|
||||
Type const* encodingType() const override;
|
||||
|
||||
TypeResult interfaceType(bool _inLibrary) const override
|
||||
{
|
||||
if (isSuper())
|
||||
return TypePointer{};
|
||||
return _inLibrary ? shared_from_this() : encodingType();
|
||||
return nullptr;
|
||||
return _inLibrary ? this : encodingType();
|
||||
}
|
||||
|
||||
/// See documentation of m_super
|
||||
@ -817,7 +807,7 @@ public:
|
||||
ContractDefinition const& contractDefinition() const { return m_contract; }
|
||||
|
||||
/// Returns the function type of the constructor modified to return an object of the contract's type.
|
||||
FunctionTypePointer const& newExpressionType() const;
|
||||
FunctionType const* newExpressionType() const;
|
||||
|
||||
/// @returns a list of all state variables (including inherited) of the contract and their
|
||||
/// offsets in storage.
|
||||
@ -828,7 +818,7 @@ private:
|
||||
/// If true, this is a special "super" type of m_contract containing only members that m_contract inherited
|
||||
bool m_super = false;
|
||||
/// Type of the constructor, @see constructorType. Lazily initialized.
|
||||
mutable FunctionTypePointer m_constructorType;
|
||||
mutable FunctionType const* m_constructorType = nullptr;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -837,9 +827,10 @@ private:
|
||||
class StructType: public ReferenceType
|
||||
{
|
||||
public:
|
||||
Category category() const override { return Category::Struct; }
|
||||
explicit StructType(StructDefinition const& _struct, DataLocation _location = DataLocation::Storage):
|
||||
ReferenceType(_location), m_struct(_struct) {}
|
||||
|
||||
Category category() const override { return Category::Struct; }
|
||||
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||
std::string richIdentifier() const override;
|
||||
bool operator==(Type const& _other) const override;
|
||||
@ -851,10 +842,8 @@ public:
|
||||
std::string toString(bool _short) const override;
|
||||
|
||||
MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
|
||||
TypePointer encodingType() const override
|
||||
{
|
||||
return location() == DataLocation::Storage ? std::make_shared<IntegerType>(256) : shared_from_this();
|
||||
}
|
||||
|
||||
Type const* encodingType() const override;
|
||||
TypeResult interfaceType(bool _inLibrary) const override;
|
||||
|
||||
bool recursive() const
|
||||
@ -867,14 +856,14 @@ public:
|
||||
return m_recursive.get();
|
||||
}
|
||||
|
||||
TypePointer copyForLocation(DataLocation _location, bool _isPointer) const override;
|
||||
std::unique_ptr<ReferenceType> copyForLocation(DataLocation _location, bool _isPointer) const override;
|
||||
|
||||
std::string canonicalName() const override;
|
||||
std::string signatureInExternalFunction(bool _structsByName) const override;
|
||||
|
||||
/// @returns a function that performs the type conversion between a list of struct members
|
||||
/// and a memory struct of this type.
|
||||
FunctionTypePointer constructorType() const;
|
||||
FunctionType const* constructorType() const;
|
||||
|
||||
std::pair<u256, unsigned> const& storageOffsetsOfMember(std::string const& _name) const;
|
||||
u256 memoryOffsetOfMember(std::string const& _name) const;
|
||||
@ -886,6 +875,9 @@ public:
|
||||
TypePointers memoryMemberTypes() const;
|
||||
/// @returns the set of all members that are removed in the memory version (typically mappings).
|
||||
std::set<std::string> membersMissingInMemory() const;
|
||||
|
||||
void clearCache() const override;
|
||||
|
||||
private:
|
||||
StructDefinition const& m_struct;
|
||||
// Caches for interfaceType(bool)
|
||||
@ -900,8 +892,9 @@ private:
|
||||
class EnumType: public Type
|
||||
{
|
||||
public:
|
||||
Category category() const override { return Category::Enum; }
|
||||
explicit EnumType(EnumDefinition const& _enum): m_enum(_enum) {}
|
||||
|
||||
Category category() const override { return Category::Enum; }
|
||||
TypeResult unaryOperatorResult(Token _operator) const override;
|
||||
std::string richIdentifier() const override;
|
||||
bool operator==(Type const& _other) const override;
|
||||
@ -917,13 +910,10 @@ public:
|
||||
bool isValueType() const override { return true; }
|
||||
|
||||
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||
TypePointer encodingType() const override
|
||||
{
|
||||
return std::make_shared<IntegerType>(8 * int(storageBytes()));
|
||||
}
|
||||
TypePointer encodingType() const override;
|
||||
TypeResult interfaceType(bool _inLibrary) const override
|
||||
{
|
||||
return _inLibrary ? shared_from_this() : encodingType();
|
||||
return _inLibrary ? this : encodingType();
|
||||
}
|
||||
|
||||
EnumDefinition const& enumDefinition() const { return m_enum; }
|
||||
@ -942,12 +932,14 @@ private:
|
||||
class TupleType: public Type
|
||||
{
|
||||
public:
|
||||
explicit TupleType(std::vector<TypePointer> _types = {}): m_components(std::move(_types)) {}
|
||||
|
||||
Category category() const override { return Category::Tuple; }
|
||||
explicit TupleType(std::vector<TypePointer> const& _types = std::vector<TypePointer>()): m_components(_types) {}
|
||||
|
||||
BoolResult isImplicitlyConvertibleTo(Type const& _other) const override;
|
||||
std::string richIdentifier() const override;
|
||||
bool operator==(Type const& _other) const override;
|
||||
TypeResult binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
|
||||
TypeResult binaryOperatorResult(Token, Type const*) const override { return nullptr; }
|
||||
std::string toString(bool) const override;
|
||||
bool canBeStored() const override { return false; }
|
||||
u256 storageSize() const override;
|
||||
@ -956,7 +948,7 @@ public:
|
||||
bool hasSimpleZeroValueInMemory() const override { return false; }
|
||||
TypePointer mobileType() const override;
|
||||
/// Converts components to their temporary types and performs some wildcard matching.
|
||||
TypePointer closestTemporaryType(TypePointer const& _targetType) const override;
|
||||
TypePointer closestTemporaryType(Type const* _targetType) const override;
|
||||
|
||||
std::vector<TypePointer> const& components() const { return m_components; }
|
||||
|
||||
@ -1017,8 +1009,6 @@ public:
|
||||
MetaType ///< type(...)
|
||||
};
|
||||
|
||||
Category category() const override { return Category::Function; }
|
||||
|
||||
/// Creates the type of a function.
|
||||
explicit FunctionType(FunctionDefinition const& _function, bool _isInternal = true);
|
||||
/// Creates the accessor function type of a state variable.
|
||||
@ -1046,9 +1036,6 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
/// @returns the type of the "new Contract" function, i.e. basically the constructor.
|
||||
static FunctionTypePointer newExpressionType(ContractDefinition const& _contract);
|
||||
|
||||
/// Detailed constructor, use with care.
|
||||
FunctionType(
|
||||
TypePointers const& _parameterTypes,
|
||||
@ -1089,6 +1076,11 @@ public:
|
||||
);
|
||||
}
|
||||
|
||||
Category category() const override { return Category::Function; }
|
||||
|
||||
/// @returns the type of the "new Contract" function, i.e. basically the constructor.
|
||||
static FunctionTypePointer newExpressionType(ContractDefinition const& _contract);
|
||||
|
||||
TypePointers parameterTypes() const;
|
||||
std::vector<std::string> parameterNames() const;
|
||||
TypePointers const& returnParameterTypes() const { return m_returnParameterTypes; }
|
||||
@ -1097,14 +1089,14 @@ public:
|
||||
TypePointers returnParameterTypesWithoutDynamicTypes() const;
|
||||
std::vector<std::string> const& returnParameterNames() const { return m_returnParameterNames; }
|
||||
/// @returns the "self" parameter type for a bound function
|
||||
TypePointer const& selfType() const;
|
||||
Type const* selfType() const;
|
||||
|
||||
std::string richIdentifier() const override;
|
||||
bool operator==(Type const& _other) const override;
|
||||
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||
TypeResult unaryOperatorResult(Token _operator) const override;
|
||||
TypeResult binaryOperatorResult(Token, TypePointer const&) const override;
|
||||
TypeResult binaryOperatorResult(Token, Type const*) const override;
|
||||
std::string canonicalName() const override;
|
||||
std::string toString(bool _short) const override;
|
||||
unsigned calldataEncodedSize(bool _padded) const override;
|
||||
@ -1133,7 +1125,7 @@ public:
|
||||
/// expression the function is called on.
|
||||
bool canTakeArguments(
|
||||
FuncCallArguments const& _arguments,
|
||||
TypePointer const& _selfType = TypePointer()
|
||||
Type const* _selfType = nullptr
|
||||
) const;
|
||||
|
||||
/// @returns true if the types of parameters are equal (does not check return parameter types)
|
||||
@ -1229,27 +1221,25 @@ private:
|
||||
class MappingType: public Type
|
||||
{
|
||||
public:
|
||||
Category category() const override { return Category::Mapping; }
|
||||
MappingType(TypePointer const& _keyType, TypePointer const& _valueType):
|
||||
MappingType(Type const* _keyType, Type const* _valueType):
|
||||
m_keyType(_keyType), m_valueType(_valueType) {}
|
||||
|
||||
Category category() const override { return Category::Mapping; }
|
||||
|
||||
std::string richIdentifier() const override;
|
||||
bool operator==(Type const& _other) const override;
|
||||
std::string toString(bool _short) const override;
|
||||
std::string canonicalName() const override;
|
||||
bool canLiveOutsideStorage() const override { return false; }
|
||||
TypeResult binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
|
||||
TypePointer encodingType() const override
|
||||
{
|
||||
return std::make_shared<IntegerType>(256);
|
||||
}
|
||||
TypeResult binaryOperatorResult(Token, Type const*) const override { return nullptr; }
|
||||
Type const* encodingType() const override;
|
||||
TypeResult interfaceType(bool _inLibrary) const override;
|
||||
bool dataStoredIn(DataLocation _location) const override { return _location == DataLocation::Storage; }
|
||||
/// Cannot be stored in memory, but just in case.
|
||||
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
|
||||
|
||||
TypePointer const& keyType() const { return m_keyType; }
|
||||
TypePointer const& valueType() const { return m_valueType; }
|
||||
Type const* keyType() const { return m_keyType; }
|
||||
Type const* valueType() const { return m_valueType; }
|
||||
|
||||
private:
|
||||
TypePointer m_keyType;
|
||||
@ -1264,11 +1254,12 @@ private:
|
||||
class TypeType: public Type
|
||||
{
|
||||
public:
|
||||
Category category() const override { return Category::TypeType; }
|
||||
explicit TypeType(TypePointer const& _actualType): m_actualType(_actualType) {}
|
||||
TypePointer const& actualType() const { return m_actualType; }
|
||||
explicit TypeType(Type const* _actualType): m_actualType(_actualType) {}
|
||||
|
||||
TypeResult binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
|
||||
Category category() const override { return Category::TypeType; }
|
||||
Type const* actualType() const { return m_actualType; }
|
||||
|
||||
TypeResult binaryOperatorResult(Token, Type const*) const override { return nullptr; }
|
||||
std::string richIdentifier() const override;
|
||||
bool operator==(Type const& _other) const override;
|
||||
bool canBeStored() const override { return false; }
|
||||
@ -1290,10 +1281,11 @@ private:
|
||||
class ModifierType: public Type
|
||||
{
|
||||
public:
|
||||
Category category() const override { return Category::Modifier; }
|
||||
explicit ModifierType(ModifierDefinition const& _modifier);
|
||||
|
||||
TypeResult binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
|
||||
Category category() const override { return Category::Modifier; }
|
||||
|
||||
TypeResult binaryOperatorResult(Token, Type const*) const override { return nullptr; }
|
||||
bool canBeStored() const override { return false; }
|
||||
u256 storageSize() const override;
|
||||
bool canLiveOutsideStorage() const override { return false; }
|
||||
@ -1315,11 +1307,11 @@ private:
|
||||
class ModuleType: public Type
|
||||
{
|
||||
public:
|
||||
Category category() const override { return Category::Module; }
|
||||
|
||||
explicit ModuleType(SourceUnit const& _source): m_sourceUnit(_source) {}
|
||||
|
||||
TypeResult binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
|
||||
Category category() const override { return Category::Module; }
|
||||
|
||||
TypeResult binaryOperatorResult(Token, Type const*) const override { return nullptr; }
|
||||
std::string richIdentifier() const override;
|
||||
bool operator==(Type const& _other) const override;
|
||||
bool canBeStored() const override { return false; }
|
||||
@ -1347,15 +1339,19 @@ public:
|
||||
ABI, ///< "abi"
|
||||
MetaType ///< "type(...)"
|
||||
};
|
||||
|
||||
public:
|
||||
explicit MagicType(Kind _kind): m_kind(_kind) {}
|
||||
explicit MagicType(Type const* _metaTypeArg): m_kind{Kind::MetaType}, m_typeArgument{_metaTypeArg} {}
|
||||
|
||||
Category category() const override { return Category::Magic; }
|
||||
|
||||
explicit MagicType(Kind _kind): m_kind(_kind) {}
|
||||
/// Factory function for meta type
|
||||
static std::shared_ptr<MagicType> metaType(TypePointer _type);
|
||||
static MagicType const* metaType(TypePointer _type);
|
||||
|
||||
TypeResult binaryOperatorResult(Token, TypePointer const&) const override
|
||||
TypeResult binaryOperatorResult(Token, Type const*) const override
|
||||
{
|
||||
return TypePointer();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string richIdentifier() const override;
|
||||
@ -1376,7 +1372,6 @@ private:
|
||||
Kind m_kind;
|
||||
/// Contract type used for contract metadata magic.
|
||||
TypePointer m_typeArgument;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1391,7 +1386,7 @@ public:
|
||||
std::string richIdentifier() const override { return "t_inaccessible"; }
|
||||
BoolResult isImplicitlyConvertibleTo(Type const&) const override { return false; }
|
||||
BoolResult isExplicitlyConvertibleTo(Type const&) const override { return false; }
|
||||
TypeResult binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
|
||||
TypeResult binaryOperatorResult(Token, Type const*) const override { return nullptr; }
|
||||
unsigned calldataEncodedSize(bool _padded) const override { (void)_padded; return 32; }
|
||||
bool canBeStored() const override { return false; }
|
||||
bool canLiveOutsideStorage() const override { return false; }
|
||||
@ -1399,7 +1394,7 @@ public:
|
||||
unsigned sizeOnStack() const override { return 1; }
|
||||
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
|
||||
std::string toString(bool) const override { return "inaccessible dynamic type"; }
|
||||
TypePointer decodingType() const override { return std::make_shared<IntegerType>(256); }
|
||||
TypePointer decodingType() const override;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -311,7 +311,7 @@ string ABIFunctions::abiEncodingFunction(
|
||||
case DataLocation::CallData:
|
||||
if (
|
||||
fromArray.isByteArray() ||
|
||||
*fromArray.baseType() == IntegerType::uint256() ||
|
||||
*fromArray.baseType() == *TypeProvider::uint256() ||
|
||||
*fromArray.baseType() == FixedBytesType(32)
|
||||
)
|
||||
return abiEncodingFunctionCalldataArrayWithoutCleanup(fromArray, *toArray, _options);
|
||||
@ -369,7 +369,7 @@ string ABIFunctions::abiEncodingFunction(
|
||||
// possible for library calls where we just forward the storage reference
|
||||
solAssert(_options.encodeAsLibraryTypes, "");
|
||||
solAssert(_options.padded && !_options.dynamicInplace, "Non-padded / inplace encoding for library call requested.");
|
||||
solAssert(to == IntegerType::uint256(), "");
|
||||
solAssert(to == *TypeProvider::uint256(), "");
|
||||
templ("cleanupConvert", "value");
|
||||
}
|
||||
else
|
||||
@ -445,7 +445,7 @@ string ABIFunctions::abiEncodingFunctionCalldataArrayWithoutCleanup(
|
||||
solAssert(fromArrayType.location() == DataLocation::CallData, "");
|
||||
solAssert(
|
||||
fromArrayType.isByteArray() ||
|
||||
*fromArrayType.baseType() == IntegerType::uint256() ||
|
||||
*fromArrayType.baseType() == *TypeProvider::uint256() ||
|
||||
*fromArrayType.baseType() == FixedBytesType(32),
|
||||
"");
|
||||
solAssert(fromArrayType.calldataStride() == toArrayType.memoryStride(), "");
|
||||
@ -1077,7 +1077,7 @@ string ABIFunctions::abiDecodingFunction(Type const& _type, bool _fromMemory, bo
|
||||
TypePointer decodingType = _type.decodingType();
|
||||
solAssert(decodingType, "");
|
||||
|
||||
if (auto arrayType = dynamic_cast<ArrayType const*>(decodingType.get()))
|
||||
if (auto arrayType = dynamic_cast<ArrayType const*>(decodingType))
|
||||
{
|
||||
if (arrayType->dataStoredIn(DataLocation::CallData))
|
||||
{
|
||||
@ -1089,7 +1089,7 @@ string ABIFunctions::abiDecodingFunction(Type const& _type, bool _fromMemory, bo
|
||||
else
|
||||
return abiDecodingFunctionArray(*arrayType, _fromMemory);
|
||||
}
|
||||
else if (auto const* structType = dynamic_cast<StructType const*>(decodingType.get()))
|
||||
else if (auto const* structType = dynamic_cast<StructType const*>(decodingType))
|
||||
{
|
||||
if (structType->dataStoredIn(DataLocation::CallData))
|
||||
{
|
||||
@ -1099,7 +1099,7 @@ string ABIFunctions::abiDecodingFunction(Type const& _type, bool _fromMemory, bo
|
||||
else
|
||||
return abiDecodingFunctionStruct(*structType, _fromMemory);
|
||||
}
|
||||
else if (auto const* functionType = dynamic_cast<FunctionType const*>(decodingType.get()))
|
||||
else if (auto const* functionType = dynamic_cast<FunctionType const*>(decodingType))
|
||||
return abiDecodingFunctionFunctionType(*functionType, _fromMemory, _forUseOnStack);
|
||||
else
|
||||
return abiDecodingFunctionValueType(_type, _fromMemory);
|
||||
|
@ -41,7 +41,7 @@ class Type;
|
||||
class ArrayType;
|
||||
class StructType;
|
||||
class FunctionType;
|
||||
using TypePointer = std::shared_ptr<Type const>;
|
||||
using TypePointer = Type const*;
|
||||
using TypePointers = std::vector<TypePointer>;
|
||||
|
||||
/**
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <libsolidity/codegen/ArrayUtils.h>
|
||||
|
||||
#include <libsolidity/ast/Types.h>
|
||||
#include <libsolidity/ast/TypeProvider.h>
|
||||
#include <libsolidity/codegen/CompilerContext.h>
|
||||
#include <libsolidity/codegen/CompilerUtils.h>
|
||||
#include <libsolidity/codegen/LValue.h>
|
||||
@ -44,7 +45,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
||||
// stack layout: [source_ref] [source length] target_ref (top)
|
||||
solAssert(_targetType.location() == DataLocation::Storage, "");
|
||||
|
||||
TypePointer uint256 = make_shared<IntegerType>(256);
|
||||
TypePointer uint256 = TypeProvider::uint256();
|
||||
TypePointer targetBaseType = _targetType.isByteArray() ? uint256 : _targetType.baseType();
|
||||
TypePointer sourceBaseType = _sourceType.isByteArray() ? uint256 : _sourceType.baseType();
|
||||
|
||||
@ -74,8 +75,8 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
||||
}
|
||||
|
||||
// stack: target_ref source_ref source_length
|
||||
TypePointer targetType = _targetType.shared_from_this();
|
||||
TypePointer sourceType = _sourceType.shared_from_this();
|
||||
TypePointer targetType = &_targetType;
|
||||
TypePointer sourceType = &_sourceType;
|
||||
m_context.callLowLevelFunction(
|
||||
"$copyArrayToStorage_" + sourceType->identifier() + "_to_" + targetType->identifier(),
|
||||
3,
|
||||
@ -336,7 +337,7 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
|
||||
m_context << Instruction::DUP3 << Instruction::DUP5;
|
||||
accessIndex(_sourceType, false);
|
||||
MemoryItem(m_context, *_sourceType.baseType(), true).retrieveValue(SourceLocation(), true);
|
||||
if (auto baseArray = dynamic_cast<ArrayType const*>(_sourceType.baseType().get()))
|
||||
if (auto baseArray = dynamic_cast<ArrayType const*>(_sourceType.baseType()))
|
||||
copyArrayToMemory(*baseArray, _padToWordBoundaries);
|
||||
else
|
||||
utils.storeInMemoryDynamic(*_sourceType.baseType());
|
||||
@ -493,7 +494,7 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
|
||||
else
|
||||
m_context << Instruction::DUP2 << u256(0);
|
||||
StorageItem(m_context, *_sourceType.baseType()).retrieveValue(SourceLocation(), true);
|
||||
if (auto baseArray = dynamic_cast<ArrayType const*>(_sourceType.baseType().get()))
|
||||
if (auto baseArray = dynamic_cast<ArrayType const*>(_sourceType.baseType()))
|
||||
copyArrayToMemory(*baseArray, _padToWordBoundaries);
|
||||
else
|
||||
utils.storeInMemoryDynamic(*_sourceType.baseType());
|
||||
@ -530,7 +531,7 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
|
||||
|
||||
void ArrayUtils::clearArray(ArrayType const& _typeIn) const
|
||||
{
|
||||
TypePointer type = _typeIn.shared_from_this();
|
||||
TypePointer type = &_typeIn;
|
||||
m_context.callLowLevelFunction(
|
||||
"$clearArray_" + _typeIn.identifier(),
|
||||
2,
|
||||
@ -584,7 +585,7 @@ void ArrayUtils::clearArray(ArrayType const& _typeIn) const
|
||||
ArrayUtils(_context).convertLengthToSize(_type);
|
||||
_context << Instruction::ADD << Instruction::SWAP1;
|
||||
if (_type.baseType()->storageBytes() < 32)
|
||||
ArrayUtils(_context).clearStorageLoop(make_shared<IntegerType>(256));
|
||||
ArrayUtils(_context).clearStorageLoop(TypeProvider::uint256());
|
||||
else
|
||||
ArrayUtils(_context).clearStorageLoop(_type.baseType());
|
||||
_context << Instruction::POP;
|
||||
@ -625,7 +626,7 @@ void ArrayUtils::clearDynamicArray(ArrayType const& _type) const
|
||||
<< Instruction::SWAP1;
|
||||
// stack: data_pos_end data_pos
|
||||
if (_type.storageStride() < 32)
|
||||
clearStorageLoop(make_shared<IntegerType>(256));
|
||||
clearStorageLoop(TypeProvider::uint256());
|
||||
else
|
||||
clearStorageLoop(_type.baseType());
|
||||
// cleanup
|
||||
@ -635,7 +636,7 @@ void ArrayUtils::clearDynamicArray(ArrayType const& _type) const
|
||||
|
||||
void ArrayUtils::resizeDynamicArray(ArrayType const& _typeIn) const
|
||||
{
|
||||
TypePointer type = _typeIn.shared_from_this();
|
||||
TypePointer type = &_typeIn;
|
||||
m_context.callLowLevelFunction(
|
||||
"$resizeDynamicArray_" + _typeIn.identifier(),
|
||||
2,
|
||||
@ -732,7 +733,7 @@ void ArrayUtils::resizeDynamicArray(ArrayType const& _typeIn) const
|
||||
ArrayUtils(_context).convertLengthToSize(_type);
|
||||
_context << Instruction::DUP2 << Instruction::ADD << Instruction::SWAP1;
|
||||
// stack: ref new_length current_length first_word data_location_end data_location
|
||||
ArrayUtils(_context).clearStorageLoop(make_shared<IntegerType>(256));
|
||||
ArrayUtils(_context).clearStorageLoop(TypeProvider::uint256());
|
||||
_context << Instruction::POP;
|
||||
// stack: ref new_length current_length first_word
|
||||
solAssert(_context.stackHeight() - stackHeightStart == 4 - 2, "3");
|
||||
@ -771,7 +772,7 @@ void ArrayUtils::resizeDynamicArray(ArrayType const& _typeIn) const
|
||||
_context << Instruction::SWAP2 << Instruction::ADD;
|
||||
// stack: ref new_length delete_end delete_start
|
||||
if (_type.storageStride() < 32)
|
||||
ArrayUtils(_context).clearStorageLoop(make_shared<IntegerType>(256));
|
||||
ArrayUtils(_context).clearStorageLoop(TypeProvider::uint256());
|
||||
else
|
||||
ArrayUtils(_context).clearStorageLoop(_type.baseType());
|
||||
|
||||
@ -911,7 +912,7 @@ void ArrayUtils::popStorageArrayElement(ArrayType const& _type) const
|
||||
}
|
||||
}
|
||||
|
||||
void ArrayUtils::clearStorageLoop(TypePointer const& _type) const
|
||||
void ArrayUtils::clearStorageLoop(TypePointer _type) const
|
||||
{
|
||||
m_context.callLowLevelFunction(
|
||||
"$clearStorageLoop_" + _type->identifier(),
|
||||
|
@ -32,7 +32,7 @@ namespace solidity
|
||||
class CompilerContext;
|
||||
class Type;
|
||||
class ArrayType;
|
||||
using TypePointer = std::shared_ptr<Type const>;
|
||||
using TypePointer = Type const*;
|
||||
|
||||
/**
|
||||
* Class that provides code generation for handling arrays.
|
||||
@ -81,7 +81,7 @@ public:
|
||||
/// Appends a loop that clears a sequence of storage slots of the given type (excluding end).
|
||||
/// Stack pre: end_ref start_ref
|
||||
/// Stack post: end_ref
|
||||
void clearStorageLoop(TypePointer const& _type) const;
|
||||
void clearStorageLoop(TypePointer _type) const;
|
||||
/// Converts length to size (number of storage slots or calldata/memory bytes).
|
||||
/// if @a _pad then add padding to multiples of 32 bytes for calldata/memory.
|
||||
/// Stack pre: length
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <libsolidity/codegen/CompilerUtils.h>
|
||||
|
||||
#include <libsolidity/ast/AST.h>
|
||||
#include <libsolidity/ast/TypeProvider.h>
|
||||
#include <libsolidity/codegen/ABIFunctions.h>
|
||||
#include <libsolidity/codegen/ArrayUtils.h>
|
||||
#include <libsolidity/codegen/LValue.h>
|
||||
@ -83,13 +84,13 @@ void CompilerUtils::toSizeAfterFreeMemoryPointer()
|
||||
|
||||
void CompilerUtils::revertWithStringData(Type const& _argumentType)
|
||||
{
|
||||
solAssert(_argumentType.isImplicitlyConvertibleTo(*Type::fromElementaryTypeName("string memory")), "");
|
||||
solAssert(_argumentType.isImplicitlyConvertibleTo(*TypeProvider::fromElementaryTypeName("string memory")), "");
|
||||
fetchFreeMemoryPointer();
|
||||
m_context << (u256(FixedHash<4>::Arith(FixedHash<4>(dev::keccak256("Error(string)")))) << (256 - 32));
|
||||
m_context << Instruction::DUP2 << Instruction::MSTORE;
|
||||
m_context << u256(4) << Instruction::ADD;
|
||||
// Stack: <string data> <mem pos of encoding start>
|
||||
abiEncode({_argumentType.shared_from_this()}, {make_shared<ArrayType>(DataLocation::Memory, true)});
|
||||
abiEncode({&_argumentType}, {TypeProvider::arrayType(DataLocation::Memory, true)});
|
||||
toSizeAfterFreeMemoryPointer();
|
||||
m_context << Instruction::REVERT;
|
||||
}
|
||||
@ -185,7 +186,7 @@ void CompilerUtils::loadFromMemoryDynamic(
|
||||
|
||||
void CompilerUtils::storeInMemory(unsigned _offset)
|
||||
{
|
||||
unsigned numBytes = prepareMemoryStore(IntegerType::uint256(), true);
|
||||
unsigned numBytes = prepareMemoryStore(*TypeProvider::uint256(), true);
|
||||
if (numBytes > 0)
|
||||
m_context << u256(_offset) << Instruction::MSTORE;
|
||||
}
|
||||
@ -199,7 +200,7 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound
|
||||
ref->location() == DataLocation::Memory,
|
||||
"Only in-memory reference type can be stored."
|
||||
);
|
||||
storeInMemoryDynamic(IntegerType::uint256(), _padToWordBoundaries);
|
||||
storeInMemoryDynamic(*TypeProvider::uint256(), _padToWordBoundaries);
|
||||
}
|
||||
else if (auto str = dynamic_cast<StringLiteralType const*>(&_type))
|
||||
{
|
||||
@ -311,11 +312,11 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem
|
||||
else
|
||||
{
|
||||
// first load from calldata and potentially convert to memory if arrayType is memory
|
||||
TypePointer calldataType = arrayType.copyForLocation(DataLocation::CallData, false);
|
||||
TypePointer calldataType = TypeProvider::withLocation(&arrayType, DataLocation::CallData, false);
|
||||
if (calldataType->isDynamicallySized())
|
||||
{
|
||||
// put on stack: data_pointer length
|
||||
loadFromMemoryDynamic(IntegerType::uint256(), !_fromMemory);
|
||||
loadFromMemoryDynamic(*TypeProvider::uint256(), !_fromMemory);
|
||||
m_context << Instruction::SWAP1;
|
||||
// stack: input_end base_offset next_pointer data_offset
|
||||
m_context.appendInlineAssembly("{ if gt(data_offset, 0x100000000) { revert(0, 0) } }", {"data_offset"});
|
||||
@ -326,7 +327,7 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem
|
||||
{"input_end", "base_offset", "next_ptr", "array_head_ptr"}
|
||||
);
|
||||
// retrieve length
|
||||
loadFromMemoryDynamic(IntegerType::uint256(), !_fromMemory, true);
|
||||
loadFromMemoryDynamic(*TypeProvider::uint256(), !_fromMemory, true);
|
||||
// stack: input_end base_offset next_pointer array_length data_pointer
|
||||
m_context << Instruction::SWAP2;
|
||||
// stack: input_end base_offset data_pointer array_length next_pointer
|
||||
@ -454,7 +455,7 @@ void CompilerUtils::encodeToMemory(
|
||||
type = _givenTypes[i]; // delay conversion
|
||||
else
|
||||
convertType(*_givenTypes[i], *targetType, true);
|
||||
if (auto arrayType = dynamic_cast<ArrayType const*>(type.get()))
|
||||
if (auto arrayType = dynamic_cast<ArrayType const*>(type))
|
||||
ArrayUtils(m_context).copyArrayToMemory(*arrayType, _padToWordBoundaries);
|
||||
else
|
||||
storeInMemoryDynamic(*type, _padToWordBoundaries);
|
||||
@ -482,7 +483,7 @@ void CompilerUtils::encodeToMemory(
|
||||
{
|
||||
auto const& strType = dynamic_cast<StringLiteralType const&>(*_givenTypes[i]);
|
||||
m_context << u256(strType.value().size());
|
||||
storeInMemoryDynamic(IntegerType::uint256(), true);
|
||||
storeInMemoryDynamic(*TypeProvider::uint256(), true);
|
||||
// stack: ... <end_of_mem'>
|
||||
storeInMemoryDynamic(strType, _padToWordBoundaries);
|
||||
}
|
||||
@ -497,7 +498,7 @@ void CompilerUtils::encodeToMemory(
|
||||
m_context << dupInstruction(1 + arrayType.sizeOnStack());
|
||||
ArrayUtils(m_context).retrieveLength(arrayType, 1);
|
||||
// stack: ... <end_of_mem> <value...> <end_of_mem'> <length>
|
||||
storeInMemoryDynamic(IntegerType::uint256(), true);
|
||||
storeInMemoryDynamic(*TypeProvider::uint256(), true);
|
||||
// stack: ... <end_of_mem> <value...> <end_of_mem''>
|
||||
// copy the new memory pointer
|
||||
m_context << swapInstruction(arrayType.sizeOnStack() + 1) << Instruction::POP;
|
||||
@ -868,7 +869,7 @@ void CompilerUtils::convertType(
|
||||
allocateMemory(storageSize);
|
||||
// stack: mempos
|
||||
m_context << Instruction::DUP1 << u256(data.size());
|
||||
storeInMemoryDynamic(IntegerType::uint256());
|
||||
storeInMemoryDynamic(*TypeProvider::uint256());
|
||||
// stack: mempos datapos
|
||||
storeStringData(data);
|
||||
}
|
||||
@ -917,7 +918,7 @@ void CompilerUtils::convertType(
|
||||
if (targetType.isDynamicallySized())
|
||||
{
|
||||
m_context << Instruction::DUP2;
|
||||
storeInMemoryDynamic(IntegerType::uint256());
|
||||
storeInMemoryDynamic(*TypeProvider::uint256());
|
||||
}
|
||||
// stack: <mem start> <source ref> (variably sized) <length> <mem data pos>
|
||||
if (targetType.baseType()->isValueType())
|
||||
@ -988,10 +989,9 @@ void CompilerUtils::convertType(
|
||||
{
|
||||
case DataLocation::Storage:
|
||||
{
|
||||
auto conversionImpl = [
|
||||
typeOnStack = dynamic_pointer_cast<StructType const>(_typeOnStack.shared_from_this()),
|
||||
targetType = dynamic_pointer_cast<StructType const>(targetType.shared_from_this())
|
||||
](CompilerContext& _context) {
|
||||
auto conversionImpl =
|
||||
[typeOnStack = &typeOnStack, targetType = &targetType](CompilerContext& _context)
|
||||
{
|
||||
CompilerUtils utils(_context);
|
||||
// stack: <source ref>
|
||||
utils.allocateMemory(typeOnStack->memorySize());
|
||||
@ -1029,7 +1029,7 @@ void CompilerUtils::convertType(
|
||||
m_context << Instruction::DUP1;
|
||||
m_context << Instruction::CALLDATASIZE;
|
||||
m_context << Instruction::SUB;
|
||||
abiDecode({targetType.shared_from_this()}, false);
|
||||
abiDecode({&targetType}, false);
|
||||
break;
|
||||
}
|
||||
case DataLocation::Memory:
|
||||
@ -1162,7 +1162,7 @@ void CompilerUtils::pushZeroValue(Type const& _type)
|
||||
return;
|
||||
}
|
||||
|
||||
TypePointer type = _type.shared_from_this();
|
||||
TypePointer type = &_type;
|
||||
m_context.callLowLevelFunction(
|
||||
"$pushZeroValue_" + referenceType->identifier(),
|
||||
0,
|
||||
@ -1172,13 +1172,13 @@ void CompilerUtils::pushZeroValue(Type const& _type)
|
||||
utils.allocateMemory(max(32u, type->calldataEncodedSize()));
|
||||
_context << Instruction::DUP1;
|
||||
|
||||
if (auto structType = dynamic_cast<StructType const*>(type.get()))
|
||||
if (auto structType = dynamic_cast<StructType const*>(type))
|
||||
for (auto const& member: structType->members(nullptr))
|
||||
{
|
||||
utils.pushZeroValue(*member.type);
|
||||
utils.storeInMemoryDynamic(*member.type);
|
||||
}
|
||||
else if (auto arrayType = dynamic_cast<ArrayType const*>(type.get()))
|
||||
else if (auto arrayType = dynamic_cast<ArrayType const*>(type))
|
||||
{
|
||||
solAssert(!arrayType->isDynamicallySized(), "");
|
||||
if (arrayType->length() > 0)
|
||||
@ -1275,10 +1275,10 @@ void CompilerUtils::popAndJump(unsigned _toHeight, eth::AssemblyItem const& _jum
|
||||
m_context.adjustStackOffset(amount);
|
||||
}
|
||||
|
||||
unsigned CompilerUtils::sizeOnStack(vector<shared_ptr<Type const>> const& _variableTypes)
|
||||
unsigned CompilerUtils::sizeOnStack(vector<Type const*> const& _variableTypes)
|
||||
{
|
||||
unsigned size = 0;
|
||||
for (shared_ptr<Type const> const& type: _variableTypes)
|
||||
for (Type const* const& type: _variableTypes)
|
||||
size += type->sizeOnStack();
|
||||
return size;
|
||||
}
|
||||
@ -1321,7 +1321,7 @@ void CompilerUtils::storeStringData(bytesConstRef _data)
|
||||
for (unsigned i = 0; i < _data.size(); i += 32)
|
||||
{
|
||||
m_context << h256::Arith(h256(_data.cropped(i), h256::AlignLeft));
|
||||
storeInMemoryDynamic(IntegerType::uint256());
|
||||
storeInMemoryDynamic(*TypeProvider::uint256());
|
||||
}
|
||||
m_context << Instruction::POP;
|
||||
}
|
||||
|
@ -23,6 +23,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <libsolidity/ast/ASTForward.h>
|
||||
#include <libsolidity/ast/TypeProvider.h>
|
||||
#include <libsolidity/codegen/CompilerContext.h>
|
||||
#include <libsolidity/codegen/CompilerContext.h>
|
||||
|
||||
namespace dev {
|
||||
@ -80,7 +82,7 @@ public:
|
||||
/// @returns the number of bytes consumed in memory.
|
||||
unsigned loadFromMemory(
|
||||
unsigned _offset,
|
||||
Type const& _type = IntegerType::uint256(),
|
||||
Type const& _type = *TypeProvider::uint256(),
|
||||
bool _fromCalldata = false,
|
||||
bool _padToWords = false
|
||||
);
|
||||
@ -264,7 +266,7 @@ public:
|
||||
|
||||
template <class T>
|
||||
static unsigned sizeOnStack(std::vector<T> const& _variables);
|
||||
static unsigned sizeOnStack(std::vector<std::shared_ptr<Type const>> const& _variableTypes);
|
||||
static unsigned sizeOnStack(std::vector<Type const*> const& _variableTypes);
|
||||
|
||||
/// Helper function to shift top value on the stack to the left.
|
||||
/// Stack pre: <value> <shift_by_bits>
|
||||
|
@ -21,6 +21,7 @@
|
||||
*/
|
||||
|
||||
#include <libsolidity/ast/AST.h>
|
||||
#include <libsolidity/ast/TypeProvider.h>
|
||||
#include <libsolidity/codegen/CompilerUtils.h>
|
||||
#include <libsolidity/codegen/ContractCompiler.h>
|
||||
#include <libsolidity/codegen/ExpressionCompiler.h>
|
||||
@ -871,7 +872,7 @@ bool ContractCompiler::visit(Return const& _return)
|
||||
|
||||
TypePointer expectedType;
|
||||
if (expression->annotation().type->category() == Type::Category::Tuple || types.size() != 1)
|
||||
expectedType = make_shared<TupleType>(types);
|
||||
expectedType = TypeProvider::tupleType(move(types));
|
||||
else
|
||||
expectedType = types.front();
|
||||
compileExpression(*expression, expectedType);
|
||||
@ -915,7 +916,7 @@ bool ContractCompiler::visit(VariableDeclarationStatement const& _variableDeclar
|
||||
CompilerUtils utils(m_context);
|
||||
compileExpression(*expression);
|
||||
TypePointers valueTypes;
|
||||
if (auto tupleType = dynamic_cast<TupleType const*>(expression->annotation().type.get()))
|
||||
if (auto tupleType = dynamic_cast<TupleType const*>(expression->annotation().type))
|
||||
valueTypes = tupleType->components();
|
||||
else
|
||||
valueTypes = TypePointers{expression->annotation().type};
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <libsolidity/codegen/ExpressionCompiler.h>
|
||||
|
||||
#include <libsolidity/ast/AST.h>
|
||||
#include <libsolidity/ast/TypeProvider.h>
|
||||
#include <libsolidity/codegen/CompilerContext.h>
|
||||
#include <libsolidity/codegen/CompilerUtils.h>
|
||||
#include <libsolidity/codegen/LValue.h>
|
||||
@ -102,7 +103,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
|
||||
|
||||
for (size_t i = 0; i < paramTypes.size(); ++i)
|
||||
{
|
||||
if (auto mappingType = dynamic_cast<MappingType const*>(returnType.get()))
|
||||
if (auto mappingType = dynamic_cast<MappingType const*>(returnType))
|
||||
{
|
||||
solAssert(CompilerUtils::freeMemoryPointer >= 0x40, "");
|
||||
|
||||
@ -152,7 +153,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
|
||||
m_context << u256(0);
|
||||
returnType = mappingType->valueType();
|
||||
}
|
||||
else if (auto arrayType = dynamic_cast<ArrayType const*>(returnType.get()))
|
||||
else if (auto arrayType = dynamic_cast<ArrayType const*>(returnType))
|
||||
{
|
||||
// pop offset
|
||||
m_context << Instruction::POP;
|
||||
@ -176,7 +177,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
|
||||
unsigned retSizeOnStack = 0;
|
||||
auto returnTypes = accessorType.returnParameterTypes();
|
||||
solAssert(returnTypes.size() >= 1, "");
|
||||
if (StructType const* structType = dynamic_cast<StructType const*>(returnType.get()))
|
||||
if (StructType const* structType = dynamic_cast<StructType const*>(returnType))
|
||||
{
|
||||
// remove offset
|
||||
m_context << Instruction::POP;
|
||||
@ -186,7 +187,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
|
||||
{
|
||||
if (returnTypes[i]->category() == Type::Category::Mapping)
|
||||
continue;
|
||||
if (auto arrayType = dynamic_cast<ArrayType const*>(returnTypes[i].get()))
|
||||
if (auto arrayType = dynamic_cast<ArrayType const*>(returnTypes[i]))
|
||||
if (!arrayType->isByteArray())
|
||||
continue;
|
||||
pair<u256, unsigned> const& offsets = structType->storageOffsetsOfMember(names[i]);
|
||||
@ -496,7 +497,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
functionType = structType.constructorType();
|
||||
}
|
||||
else
|
||||
functionType = dynamic_pointer_cast<FunctionType const>(_functionCall.expression().annotation().type);
|
||||
functionType = dynamic_cast<FunctionType const*>(_functionCall.expression().annotation().type);
|
||||
|
||||
TypePointers parameterTypes = functionType->parameterTypes();
|
||||
vector<ASTPointer<Expression const>> const& callArguments = _functionCall.arguments();
|
||||
@ -647,7 +648,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
_functionCall.expression().accept(*this);
|
||||
|
||||
arguments.front()->accept(*this);
|
||||
utils().convertType(*arguments.front()->annotation().type, IntegerType::uint256(), true);
|
||||
utils().convertType(*arguments.front()->annotation().type, *TypeProvider::uint256(), true);
|
||||
// Note that function is not the original function, but the ".gas" function.
|
||||
// Its values of gasSet and valueSet is equal to the original function's though.
|
||||
unsigned stackDepth = (function.gasSet() ? 1 : 0) + (function.valueSet() ? 1 : 0);
|
||||
@ -731,9 +732,9 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
arguments.front()->accept(*this);
|
||||
// Optimization: If type is bytes or string, then do not encode,
|
||||
// but directly compute keccak256 on memory.
|
||||
if (*argType == ArrayType::bytesMemory() || *argType == ArrayType::stringMemory())
|
||||
if (*argType == *TypeProvider::bytesMemoryType() || *argType == *TypeProvider::stringMemoryType())
|
||||
{
|
||||
ArrayUtils(m_context).retrieveLength(ArrayType::bytesMemory());
|
||||
ArrayUtils(m_context).retrieveLength(*TypeProvider::bytesMemoryType());
|
||||
m_context << Instruction::SWAP1 << u256(0x20) << Instruction::ADD;
|
||||
}
|
||||
else
|
||||
@ -780,7 +781,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
{
|
||||
++numIndexed;
|
||||
arguments[arg - 1]->accept(*this);
|
||||
if (auto const& referenceType = dynamic_pointer_cast<ReferenceType const>(paramTypes[arg - 1]))
|
||||
if (auto const& referenceType = dynamic_cast<ReferenceType const*>(paramTypes[arg - 1]))
|
||||
{
|
||||
utils().fetchFreeMemoryPointer();
|
||||
utils().packedEncode(
|
||||
@ -835,13 +836,13 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
case FunctionType::Kind::MulMod:
|
||||
{
|
||||
arguments[2]->accept(*this);
|
||||
utils().convertType(*arguments[2]->annotation().type, IntegerType::uint256());
|
||||
utils().convertType(*arguments[2]->annotation().type, *TypeProvider::uint256());
|
||||
m_context << Instruction::DUP1 << Instruction::ISZERO;
|
||||
m_context.appendConditionalInvalid();
|
||||
for (unsigned i = 1; i < 3; i ++)
|
||||
{
|
||||
arguments[2 - i]->accept(*this);
|
||||
utils().convertType(*arguments[2 - i]->annotation().type, IntegerType::uint256());
|
||||
utils().convertType(*arguments[2 - i]->annotation().type, *TypeProvider::uint256());
|
||||
}
|
||||
if (function.kind() == FunctionType::Kind::AddMod)
|
||||
m_context << Instruction::ADDMOD;
|
||||
@ -872,10 +873,10 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
solAssert(function.parameterTypes().size() == 1, "");
|
||||
solAssert(!!function.parameterTypes()[0], "");
|
||||
TypePointer paramType = function.parameterTypes()[0];
|
||||
shared_ptr<ArrayType> arrayType =
|
||||
ArrayType const* arrayType =
|
||||
function.kind() == FunctionType::Kind::ArrayPush ?
|
||||
make_shared<ArrayType>(DataLocation::Storage, paramType) :
|
||||
make_shared<ArrayType>(DataLocation::Storage);
|
||||
TypeProvider::arrayType(DataLocation::Storage, paramType) :
|
||||
TypeProvider::arrayType(DataLocation::Storage);
|
||||
|
||||
// stack: ArrayReference
|
||||
arguments[0]->accept(*this);
|
||||
@ -927,7 +928,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
|
||||
// Fetch requested length.
|
||||
arguments[0]->accept(*this);
|
||||
utils().convertType(*arguments[0]->annotation().type, IntegerType::uint256());
|
||||
utils().convertType(*arguments[0]->annotation().type, *TypeProvider::uint256());
|
||||
|
||||
// Stack: requested_length
|
||||
utils().fetchFreeMemoryPointer();
|
||||
@ -1057,11 +1058,11 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
if (function.kind() == FunctionType::Kind::ABIEncodeWithSignature)
|
||||
{
|
||||
// hash the signature
|
||||
if (auto const* stringType = dynamic_cast<StringLiteralType const*>(selectorType.get()))
|
||||
if (auto const* stringType = dynamic_cast<StringLiteralType const*>(selectorType))
|
||||
{
|
||||
FixedHash<4> hash(dev::keccak256(stringType->value()));
|
||||
m_context << (u256(FixedHash<4>::Arith(hash)) << (256 - 32));
|
||||
dataOnStack = make_shared<FixedBytesType>(4);
|
||||
dataOnStack = TypeProvider::fixedBytesType(4);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1072,7 +1073,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
m_context << Instruction::KECCAK256;
|
||||
// stack: <memory pointer> <hash>
|
||||
|
||||
dataOnStack = make_shared<FixedBytesType>(32);
|
||||
dataOnStack = TypeProvider::fixedBytesType(32);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -1103,7 +1104,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
arguments.front()->accept(*this);
|
||||
TypePointer firstArgType = arguments.front()->annotation().type;
|
||||
TypePointers targetTypes;
|
||||
if (TupleType const* targetTupleType = dynamic_cast<TupleType const*>(_functionCall.annotation().type.get()))
|
||||
if (TupleType const* targetTupleType = dynamic_cast<TupleType const*>(_functionCall.annotation().type))
|
||||
targetTypes = targetTupleType->components();
|
||||
else
|
||||
targetTypes = TypePointers{_functionCall.annotation().type};
|
||||
@ -1114,7 +1115,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
utils().abiDecode(targetTypes, false);
|
||||
else
|
||||
{
|
||||
utils().convertType(*firstArgType, ArrayType::bytesMemory());
|
||||
utils().convertType(*firstArgType, *TypeProvider::bytesMemoryType());
|
||||
m_context << Instruction::DUP1 << u256(32) << Instruction::ADD;
|
||||
m_context << Instruction::SWAP1 << Instruction::MLOAD;
|
||||
// stack now: <mem_pos> <length>
|
||||
@ -1145,7 +1146,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
||||
CompilerContext::LocationSetter locationSetter(m_context, _memberAccess);
|
||||
// Check whether the member is a bound function.
|
||||
ASTString const& member = _memberAccess.memberName();
|
||||
if (auto funType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type.get()))
|
||||
if (auto funType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type))
|
||||
if (funType->bound())
|
||||
{
|
||||
_memberAccess.expression().accept(*this);
|
||||
@ -1174,14 +1175,14 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
||||
|
||||
// Special processing for TypeType because we do not want to visit the library itself
|
||||
// for internal functions, or enum/struct definitions.
|
||||
if (TypeType const* type = dynamic_cast<TypeType const*>(_memberAccess.expression().annotation().type.get()))
|
||||
if (TypeType const* type = dynamic_cast<TypeType const*>(_memberAccess.expression().annotation().type))
|
||||
{
|
||||
if (dynamic_cast<ContractType const*>(type->actualType().get()))
|
||||
if (dynamic_cast<ContractType const*>(type->actualType()))
|
||||
{
|
||||
solAssert(_memberAccess.annotation().type, "_memberAccess has no type");
|
||||
if (auto variable = dynamic_cast<VariableDeclaration const*>(_memberAccess.annotation().referencedDeclaration))
|
||||
appendVariable(*variable, static_cast<Expression const&>(_memberAccess));
|
||||
else if (auto funType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type.get()))
|
||||
else if (auto funType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type))
|
||||
{
|
||||
switch (funType->kind())
|
||||
{
|
||||
@ -1223,14 +1224,14 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
||||
solAssert(false, "unsupported member function");
|
||||
}
|
||||
}
|
||||
else if (dynamic_cast<TypeType const*>(_memberAccess.annotation().type.get()))
|
||||
else if (dynamic_cast<TypeType const*>(_memberAccess.annotation().type))
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
else
|
||||
_memberAccess.expression().accept(*this);
|
||||
}
|
||||
else if (auto enumType = dynamic_cast<EnumType const*>(type->actualType().get()))
|
||||
else if (auto enumType = dynamic_cast<EnumType const*>(type->actualType()))
|
||||
{
|
||||
_memberAccess.expression().accept(*this);
|
||||
m_context << enumType->memberValue(_memberAccess.memberName());
|
||||
@ -1288,7 +1289,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
||||
identifier = FunctionType(*function).externalIdentifier();
|
||||
else
|
||||
solAssert(false, "Contract member is neither variable nor function.");
|
||||
utils().convertType(type, type.isPayable() ? AddressType::addressPayable() : AddressType::address(), true);
|
||||
utils().convertType(type, type.isPayable() ? *TypeProvider::payableAddressType() : *TypeProvider::addressType(), true);
|
||||
m_context << identifier;
|
||||
}
|
||||
else
|
||||
@ -1306,7 +1307,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
||||
{
|
||||
utils().convertType(
|
||||
*_memberAccess.expression().annotation().type,
|
||||
AddressType::address(),
|
||||
*TypeProvider::addressType(),
|
||||
true
|
||||
);
|
||||
m_context << Instruction::BALANCE;
|
||||
@ -1323,7 +1324,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
||||
else if ((set<string>{"call", "callcode", "delegatecall", "staticcall"}).count(member))
|
||||
utils().convertType(
|
||||
*_memberAccess.expression().annotation().type,
|
||||
AddressType::address(),
|
||||
*TypeProvider::addressType(),
|
||||
true
|
||||
);
|
||||
else
|
||||
@ -1542,7 +1543,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
|
||||
TypePointers{keyType}
|
||||
);
|
||||
m_context << Instruction::SWAP1;
|
||||
utils().storeInMemoryDynamic(IntegerType::uint256());
|
||||
utils().storeInMemoryDynamic(*TypeProvider::uint256());
|
||||
utils().toSizeAfterFreeMemoryPointer();
|
||||
}
|
||||
else
|
||||
@ -1551,7 +1552,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
|
||||
appendExpressionCopyToMemory(*keyType, *_indexAccess.indexExpression());
|
||||
m_context << Instruction::SWAP1;
|
||||
solAssert(CompilerUtils::freeMemoryPointer >= 0x40, "");
|
||||
utils().storeInMemoryDynamic(IntegerType::uint256());
|
||||
utils().storeInMemoryDynamic(*TypeProvider::uint256());
|
||||
m_context << u256(0);
|
||||
}
|
||||
m_context << Instruction::KECCAK256;
|
||||
@ -1564,7 +1565,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
|
||||
solAssert(_indexAccess.indexExpression(), "Index expression expected.");
|
||||
|
||||
_indexAccess.indexExpression()->accept(*this);
|
||||
utils().convertType(*_indexAccess.indexExpression()->annotation().type, IntegerType::uint256(), true);
|
||||
utils().convertType(*_indexAccess.indexExpression()->annotation().type, *TypeProvider::uint256(), true);
|
||||
// stack layout: <base_ref> [<length>] <index>
|
||||
switch (arrayType.location())
|
||||
{
|
||||
@ -1631,7 +1632,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
|
||||
solAssert(_indexAccess.indexExpression(), "Index expression expected.");
|
||||
|
||||
_indexAccess.indexExpression()->accept(*this);
|
||||
utils().convertType(*_indexAccess.indexExpression()->annotation().type, IntegerType::uint256(), true);
|
||||
utils().convertType(*_indexAccess.indexExpression()->annotation().type, *TypeProvider::uint256(), true);
|
||||
// stack layout: <value> <index>
|
||||
// check out-of-bounds access
|
||||
m_context << u256(fixedBytesType.numBytes());
|
||||
@ -2211,7 +2212,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
||||
needToUpdateFreeMemoryPtr = true;
|
||||
else
|
||||
for (auto const& retType: returnTypes)
|
||||
if (dynamic_cast<ReferenceType const*>(retType.get()))
|
||||
if (dynamic_cast<ReferenceType const*>(retType))
|
||||
needToUpdateFreeMemoryPtr = true;
|
||||
|
||||
// Stack: return_data_start
|
||||
|
@ -35,7 +35,7 @@ using namespace langutil;
|
||||
|
||||
|
||||
StackVariable::StackVariable(CompilerContext& _compilerContext, VariableDeclaration const& _declaration):
|
||||
LValue(_compilerContext, _declaration.annotation().type.get()),
|
||||
LValue(_compilerContext, _declaration.annotation().type),
|
||||
m_baseStackOffset(m_context.baseStackOffsetOfVariable(_declaration)),
|
||||
m_size(m_dataType->sizeOnStack())
|
||||
{
|
||||
@ -475,7 +475,7 @@ void StorageByteArrayElement::setToZero(SourceLocation const&, bool _removeRefer
|
||||
}
|
||||
|
||||
StorageArrayLength::StorageArrayLength(CompilerContext& _compilerContext, ArrayType const& _arrayType):
|
||||
LValue(_compilerContext, _arrayType.memberType("length").get()),
|
||||
LValue(_compilerContext, _arrayType.memberType("length")),
|
||||
m_arrayType(_arrayType)
|
||||
{
|
||||
solAssert(m_arrayType.isDynamicallySized(), "");
|
||||
|
@ -145,7 +145,7 @@ string YulUtilFunctions::leftAlignFunction(Type const& _type)
|
||||
templ("body", "aligned := value");
|
||||
break;
|
||||
case Type::Category::Contract:
|
||||
templ("body", "aligned := " + leftAlignFunction(AddressType::address()) + "(value)");
|
||||
templ("body", "aligned := " + leftAlignFunction(*TypeProvider::addressType()) + "(value)");
|
||||
break;
|
||||
case Type::Category::Enum:
|
||||
{
|
||||
|
@ -82,7 +82,7 @@ void IRGeneratorForStatements::endVisit(BinaryOperation const& _binOp)
|
||||
{
|
||||
solUnimplementedAssert(_binOp.getOperator() == Token::Add, "");
|
||||
solUnimplementedAssert(*_binOp.leftExpression().annotation().type == *_binOp.rightExpression().annotation().type, "");
|
||||
if (IntegerType const* type = dynamic_cast<IntegerType const*>(_binOp.annotation().commonType.get()))
|
||||
if (IntegerType const* type = dynamic_cast<IntegerType const*>(_binOp.annotation().commonType))
|
||||
{
|
||||
solUnimplementedAssert(!type->isSigned(), "");
|
||||
m_code <<
|
||||
@ -103,7 +103,7 @@ void IRGeneratorForStatements::endVisit(BinaryOperation const& _binOp)
|
||||
bool IRGeneratorForStatements::visit(FunctionCall const& _functionCall)
|
||||
{
|
||||
solUnimplementedAssert(_functionCall.annotation().kind == FunctionCallKind::FunctionCall, "");
|
||||
FunctionTypePointer functionType = dynamic_pointer_cast<FunctionType const>(_functionCall.expression().annotation().type);
|
||||
FunctionTypePointer functionType = dynamic_cast<FunctionType const*>(_functionCall.expression().annotation().type);
|
||||
|
||||
TypePointers parameterTypes = functionType->parameterTypes();
|
||||
vector<ASTPointer<Expression const>> const& callArguments = _functionCall.arguments();
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include <libsolidity/formal/SMTChecker.h>
|
||||
|
||||
#include <libsolidity/ast/TypeProvider.h>
|
||||
#include <libsolidity/formal/SMTPortfolio.h>
|
||||
#include <libsolidity/formal/SymbolicTypes.h>
|
||||
|
||||
@ -447,7 +448,7 @@ void SMTChecker::checkUnderOverflow()
|
||||
void SMTChecker::checkUnderflow(OverflowTarget& _target)
|
||||
{
|
||||
solAssert(_target.type != OverflowTarget::Type::Overflow, "");
|
||||
auto intType = dynamic_cast<IntegerType const*>(_target.intType.get());
|
||||
auto intType = dynamic_cast<IntegerType const*>(_target.intType);
|
||||
checkCondition(
|
||||
_target.path && _target.value < minValue(*intType),
|
||||
_target.location,
|
||||
@ -460,7 +461,7 @@ void SMTChecker::checkUnderflow(OverflowTarget& _target)
|
||||
void SMTChecker::checkOverflow(OverflowTarget& _target)
|
||||
{
|
||||
solAssert(_target.type != OverflowTarget::Type::Underflow, "");
|
||||
auto intType = dynamic_cast<IntegerType const*>(_target.intType.get());
|
||||
auto intType = dynamic_cast<IntegerType const*>(_target.intType);
|
||||
checkCondition(
|
||||
_target.path && _target.value > maxValue(*intType),
|
||||
_target.location,
|
||||
@ -681,7 +682,7 @@ void SMTChecker::inlineFunctionCall(FunctionCall const& _funCall)
|
||||
{
|
||||
vector<smt::Expression> funArgs;
|
||||
Expression const* calledExpr = &_funCall.expression();
|
||||
auto const& funType = dynamic_cast<FunctionType const*>(calledExpr->annotation().type.get());
|
||||
auto const& funType = dynamic_cast<FunctionType const*>(calledExpr->annotation().type);
|
||||
solAssert(funType, "");
|
||||
if (funType->bound())
|
||||
{
|
||||
@ -803,8 +804,8 @@ void SMTChecker::endVisit(Literal const& _literal)
|
||||
{
|
||||
if (type.category() == Type::Category::StringLiteral)
|
||||
{
|
||||
auto stringType = make_shared<ArrayType>(DataLocation::Memory, true);
|
||||
auto stringLit = dynamic_cast<StringLiteralType const*>(_literal.annotation().type.get());
|
||||
auto stringType = TypeProvider::stringMemoryType();
|
||||
auto stringLit = dynamic_cast<StringLiteralType const*>(_literal.annotation().type);
|
||||
solAssert(stringLit, "");
|
||||
auto result = newSymbolicVariable(*stringType, stringLit->richIdentifier(), *m_interface);
|
||||
m_expressions.emplace(&_literal, result.second);
|
||||
@ -859,7 +860,7 @@ bool SMTChecker::visit(MemberAccess const& _memberAccess)
|
||||
{
|
||||
if (identifier && dynamic_cast<EnumDefinition const*>(identifier->annotation().referencedDeclaration))
|
||||
{
|
||||
auto enumType = dynamic_cast<EnumType const*>(accessType.get());
|
||||
auto enumType = dynamic_cast<EnumType const*>(accessType);
|
||||
solAssert(enumType, "");
|
||||
defineExpr(_memberAccess, enumType->memberValue(_memberAccess.memberName()));
|
||||
}
|
||||
@ -939,13 +940,13 @@ void SMTChecker::arrayIndexAssignment(Expression const& _expr, smt::Expression c
|
||||
return true;
|
||||
if (prefix->category() == Type::Category::Mapping)
|
||||
{
|
||||
auto mapPrefix = dynamic_cast<MappingType const*>(prefix.get());
|
||||
auto mapPrefix = dynamic_cast<MappingType const*>(prefix);
|
||||
solAssert(mapPrefix, "");
|
||||
prefix = mapPrefix->valueType();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto arrayPrefix = dynamic_cast<ArrayType const*>(prefix.get());
|
||||
auto arrayPrefix = dynamic_cast<ArrayType const*>(prefix);
|
||||
solAssert(arrayPrefix, "");
|
||||
prefix = arrayPrefix->baseType();
|
||||
}
|
||||
@ -1017,7 +1018,7 @@ bool SMTChecker::shortcutRationalNumber(Expression const& _expr)
|
||||
{
|
||||
if (_expr.annotation().type->category() == Type::Category::RationalNumber)
|
||||
{
|
||||
auto rationalType = dynamic_cast<RationalNumberType const*>(_expr.annotation().type.get());
|
||||
auto rationalType = dynamic_cast<RationalNumberType const*>(_expr.annotation().type);
|
||||
solAssert(rationalType, "");
|
||||
if (rationalType->isNegative())
|
||||
defineExpr(_expr, smt::Expression(u2s(rationalType->literalValue(nullptr))));
|
||||
@ -1205,7 +1206,7 @@ void SMTChecker::assignment(VariableDeclaration const& _variable, smt::Expressio
|
||||
if (type->category() == Type::Category::Integer)
|
||||
addOverflowTarget(OverflowTarget::Type::All, type, _value, _location);
|
||||
else if (type->category() == Type::Category::Address)
|
||||
addOverflowTarget(OverflowTarget::Type::All, make_shared<IntegerType>(160), _value, _location);
|
||||
addOverflowTarget(OverflowTarget::Type::All, TypeProvider::uint(160), _value, _location);
|
||||
else if (type->category() == Type::Category::Mapping)
|
||||
arrayAssignment();
|
||||
m_interface->addAssertion(newValue(_variable) == _value);
|
||||
@ -1522,7 +1523,7 @@ void SMTChecker::resetVariables(function<bool(VariableDeclaration const&)> const
|
||||
|
||||
TypePointer SMTChecker::typeWithoutPointer(TypePointer const& _type)
|
||||
{
|
||||
if (auto refType = dynamic_cast<ReferenceType const*>(_type.get()))
|
||||
if (auto refType = dynamic_cast<ReferenceType const*>(_type))
|
||||
return ReferenceType::copyForLocationIfReference(refType->location(), _type);
|
||||
return _type;
|
||||
}
|
||||
|
@ -178,7 +178,7 @@ private:
|
||||
location(_location),
|
||||
callStack(move(_callStack))
|
||||
{
|
||||
solAssert(dynamic_cast<IntegerType const*>(intType.get()), "");
|
||||
solAssert(dynamic_cast<IntegerType const*>(intType), "");
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include <libsolidity/formal/SymbolicTypes.h>
|
||||
|
||||
#include <libsolidity/ast/TypeProvider.h>
|
||||
#include <libsolidity/ast/Types.h>
|
||||
#include <memory>
|
||||
|
||||
@ -115,11 +116,11 @@ pair<bool, shared_ptr<SymbolicVariable>> dev::solidity::newSymbolicVariable(
|
||||
{
|
||||
bool abstract = false;
|
||||
shared_ptr<SymbolicVariable> var;
|
||||
TypePointer type = _type.shared_from_this();
|
||||
TypePointer type = &_type;
|
||||
if (!isSupportedTypeDeclaration(_type))
|
||||
{
|
||||
abstract = true;
|
||||
var = make_shared<SymbolicIntVariable>(make_shared<IntegerType>(256), _uniqueName, _solver);
|
||||
var = make_shared<SymbolicIntVariable>(TypeProvider::uint256(), _uniqueName, _solver);
|
||||
}
|
||||
else if (isBool(_type.category()))
|
||||
var = make_shared<SymbolicBoolVariable>(type, _uniqueName, _solver);
|
||||
@ -129,7 +130,7 @@ pair<bool, shared_ptr<SymbolicVariable>> dev::solidity::newSymbolicVariable(
|
||||
var = make_shared<SymbolicIntVariable>(type, _uniqueName, _solver);
|
||||
else if (isFixedBytes(_type.category()))
|
||||
{
|
||||
auto fixedBytesType = dynamic_cast<FixedBytesType const*>(type.get());
|
||||
auto fixedBytesType = dynamic_cast<FixedBytesType const*>(type);
|
||||
solAssert(fixedBytesType, "");
|
||||
var = make_shared<SymbolicFixedBytesVariable>(fixedBytesType->numBytes(), _uniqueName, _solver);
|
||||
}
|
||||
@ -142,7 +143,7 @@ pair<bool, shared_ptr<SymbolicVariable>> dev::solidity::newSymbolicVariable(
|
||||
auto rational = dynamic_cast<RationalNumberType const*>(&_type);
|
||||
solAssert(rational, "");
|
||||
if (rational->isFractional())
|
||||
var = make_shared<SymbolicIntVariable>(make_shared<IntegerType>(256), _uniqueName, _solver);
|
||||
var = make_shared<SymbolicIntVariable>(TypeProvider::uint256(), _uniqueName, _solver);
|
||||
else
|
||||
var = make_shared<SymbolicIntVariable>(type, _uniqueName, _solver);
|
||||
}
|
||||
@ -253,14 +254,14 @@ void dev::solidity::smt::setSymbolicUnknownValue(smt::Expression _expr, TypePoin
|
||||
solAssert(_type, "");
|
||||
if (isEnum(_type->category()))
|
||||
{
|
||||
auto enumType = dynamic_cast<EnumType const*>(_type.get());
|
||||
auto enumType = dynamic_cast<EnumType const*>(_type);
|
||||
solAssert(enumType, "");
|
||||
_interface.addAssertion(_expr >= 0);
|
||||
_interface.addAssertion(_expr < enumType->numberOfMembers());
|
||||
}
|
||||
else if (isInteger(_type->category()))
|
||||
{
|
||||
auto intType = dynamic_cast<IntegerType const*>(_type.get());
|
||||
auto intType = dynamic_cast<IntegerType const*>(_type);
|
||||
solAssert(intType, "");
|
||||
_interface.addAssertion(_expr >= minValue(*intType));
|
||||
_interface.addAssertion(_expr <= maxValue(*intType));
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include <libsolidity/formal/SymbolicTypes.h>
|
||||
#include <libsolidity/ast/AST.h>
|
||||
#include <libsolidity/ast/TypeProvider.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace dev;
|
||||
@ -102,7 +103,7 @@ SymbolicAddressVariable::SymbolicAddressVariable(
|
||||
string _uniqueName,
|
||||
smt::SolverInterface& _interface
|
||||
):
|
||||
SymbolicIntVariable(make_shared<IntegerType>(160), move(_uniqueName), _interface)
|
||||
SymbolicIntVariable(TypeProvider::uint(160), move(_uniqueName), _interface)
|
||||
{
|
||||
}
|
||||
|
||||
@ -111,7 +112,7 @@ SymbolicFixedBytesVariable::SymbolicFixedBytesVariable(
|
||||
string _uniqueName,
|
||||
smt::SolverInterface& _interface
|
||||
):
|
||||
SymbolicIntVariable(make_shared<IntegerType>(_numBytes * 8), move(_uniqueName), _interface)
|
||||
SymbolicIntVariable(TypeProvider::uint(_numBytes * 8), move(_uniqueName), _interface)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,7 @@ namespace solidity
|
||||
// Forward declarations
|
||||
class ContractDefinition;
|
||||
class Type;
|
||||
using TypePointer = std::shared_ptr<Type const>;
|
||||
using TypePointer = Type const*;
|
||||
|
||||
class ABI
|
||||
{
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include <libsolidity/analysis/ViewPureChecker.h>
|
||||
|
||||
#include <libsolidity/ast/AST.h>
|
||||
#include <libsolidity/ast/TypeProvider.h>
|
||||
#include <libsolidity/codegen/Compiler.h>
|
||||
#include <libsolidity/formal/SMTChecker.h>
|
||||
#include <libsolidity/interface/ABI.h>
|
||||
@ -66,6 +67,26 @@ using namespace dev;
|
||||
using namespace langutil;
|
||||
using namespace dev::solidity;
|
||||
|
||||
static int g_compilerStackCounts = 0;
|
||||
|
||||
CompilerStack::CompilerStack(ReadCallback::Callback const& _readFile):
|
||||
m_readFile{_readFile},
|
||||
m_generateIR{false},
|
||||
m_errorList{},
|
||||
m_errorReporter{m_errorList}
|
||||
{
|
||||
// Because TypeProvider is currently a singleton API, we must ensure that
|
||||
// no more than one entity is actually using it at a time.
|
||||
solAssert(g_compilerStackCounts == 0, "You shall not have another CompilerStack aside me.");
|
||||
++g_compilerStackCounts;
|
||||
}
|
||||
|
||||
CompilerStack::~CompilerStack()
|
||||
{
|
||||
--g_compilerStackCounts;
|
||||
TypeProvider::reset();
|
||||
}
|
||||
|
||||
boost::optional<CompilerStack::Remapping> CompilerStack::parseRemapping(string const& _remapping)
|
||||
{
|
||||
auto eq = find(_remapping.begin(), _remapping.end(), '=');
|
||||
@ -157,6 +178,7 @@ void CompilerStack::reset(bool _keepSettings)
|
||||
m_sourceOrder.clear();
|
||||
m_contracts.clear();
|
||||
m_errorReporter.clear();
|
||||
TypeProvider::reset();
|
||||
}
|
||||
|
||||
void CompilerStack::setSources(StringMap const& _sources)
|
||||
|
@ -98,11 +98,9 @@ public:
|
||||
/// Creates a new compiler stack.
|
||||
/// @param _readFile callback to used to read files for import statements. Must return
|
||||
/// and must not emit exceptions.
|
||||
explicit CompilerStack(ReadCallback::Callback const& _readFile = ReadCallback::Callback()):
|
||||
m_readFile(_readFile),
|
||||
m_generateIR(false),
|
||||
m_errorList(),
|
||||
m_errorReporter(m_errorList) {}
|
||||
explicit CompilerStack(ReadCallback::Callback const& _readFile = ReadCallback::Callback());
|
||||
|
||||
~CompilerStack();
|
||||
|
||||
/// @returns the list of errors that occurred during parsing and type checking.
|
||||
langutil::ErrorList const& errors() const { return m_errorReporter.errors(); }
|
||||
|
@ -47,21 +47,21 @@ AnalysisFramework::parseAnalyseAndReturnError(
|
||||
bool _allowMultipleErrors
|
||||
)
|
||||
{
|
||||
m_compiler.reset();
|
||||
m_compiler.setSources({{"", _insertVersionPragma ? "pragma solidity >=0.0;\n" + _source : _source}});
|
||||
m_compiler.setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
if (!m_compiler.parse())
|
||||
compiler().reset();
|
||||
compiler().setSources({{"", _insertVersionPragma ? "pragma solidity >=0.0;\n" + _source : _source}});
|
||||
compiler().setEVMVersion(dev::test::Options::get().evmVersion());
|
||||
if (!compiler().parse())
|
||||
{
|
||||
BOOST_FAIL("Parsing contract failed in analysis test suite:" + formatErrors());
|
||||
}
|
||||
|
||||
m_compiler.analyze();
|
||||
compiler().analyze();
|
||||
|
||||
ErrorList errors = filterErrors(m_compiler.errors(), _reportWarnings);
|
||||
ErrorList errors = filterErrors(compiler().errors(), _reportWarnings);
|
||||
if (errors.size() > 1 && !_allowMultipleErrors)
|
||||
BOOST_FAIL("Multiple errors found: " + formatErrors());
|
||||
|
||||
return make_pair(&m_compiler.ast(""), std::move(errors));
|
||||
return make_pair(&compiler().ast(""), std::move(errors));
|
||||
}
|
||||
|
||||
ErrorList AnalysisFramework::filterErrors(ErrorList const& _errorList, bool _includeWarnings) const
|
||||
@ -118,7 +118,7 @@ ErrorList AnalysisFramework::expectError(std::string const& _source, bool _warni
|
||||
string AnalysisFramework::formatErrors() const
|
||||
{
|
||||
string message;
|
||||
for (auto const& error: m_compiler.errors())
|
||||
for (auto const& error: compiler().errors())
|
||||
message += formatError(*error);
|
||||
return message;
|
||||
}
|
||||
|
@ -35,8 +35,8 @@ namespace solidity
|
||||
|
||||
class Type;
|
||||
class FunctionType;
|
||||
using TypePointer = std::shared_ptr<Type const>;
|
||||
using FunctionTypePointer = std::shared_ptr<FunctionType const>;
|
||||
using TypePointer = Type const*;
|
||||
using FunctionTypePointer = FunctionType const*;
|
||||
|
||||
namespace test
|
||||
{
|
||||
@ -71,7 +71,25 @@ protected:
|
||||
langutil::ErrorList filterErrors(langutil::ErrorList const& _errorList, bool _includeWarnings) const;
|
||||
|
||||
std::vector<std::string> m_warningsToFilter = {"This is a pre-release compiler version"};
|
||||
dev::solidity::CompilerStack m_compiler;
|
||||
|
||||
/// @returns reference to lazy-instanciated CompilerStack.
|
||||
dev::solidity::CompilerStack& compiler()
|
||||
{
|
||||
if (!m_compiler)
|
||||
m_compiler = std::make_unique<dev::solidity::CompilerStack>();
|
||||
return *m_compiler;
|
||||
}
|
||||
|
||||
/// @returns reference to lazy-instanciated CompilerStack.
|
||||
dev::solidity::CompilerStack const& compiler() const
|
||||
{
|
||||
if (!m_compiler)
|
||||
m_compiler = std::make_unique<dev::solidity::CompilerStack>();
|
||||
return *m_compiler;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable std::unique_ptr<dev::solidity::CompilerStack> m_compiler;
|
||||
};
|
||||
|
||||
// Asserts that the compilation down to typechecking
|
||||
|
@ -42,11 +42,11 @@ BOOST_AUTO_TEST_CASE(does_not_include_creation_time_only_internal_functions)
|
||||
function f() internal { for (uint i = 0; i < 10; ++i) x += 3 + i; }
|
||||
}
|
||||
)";
|
||||
m_compiler.setOptimiserSettings(dev::test::Options::get().optimize);
|
||||
compiler().setOptimiserSettings(dev::test::Options::get().optimize);
|
||||
BOOST_REQUIRE(success(sourceCode));
|
||||
BOOST_REQUIRE_MESSAGE(m_compiler.compile(), "Compiling contract failed");
|
||||
bytes const& creationBytecode = dev::test::bytecodeSansMetadata(m_compiler.object("C").bytecode);
|
||||
bytes const& runtimeBytecode = dev::test::bytecodeSansMetadata(m_compiler.runtimeObject("C").bytecode);
|
||||
BOOST_REQUIRE_MESSAGE(compiler().compile(), "Compiling contract failed");
|
||||
bytes const& creationBytecode = dev::test::bytecodeSansMetadata(compiler().object("C").bytecode);
|
||||
bytes const& runtimeBytecode = dev::test::bytecodeSansMetadata(compiler().runtimeObject("C").bytecode);
|
||||
BOOST_CHECK(creationBytecode.size() >= 90);
|
||||
BOOST_CHECK(creationBytecode.size() <= 120);
|
||||
BOOST_CHECK(runtimeBytecode.size() >= 10);
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <libsolidity/codegen/CompilerContext.h>
|
||||
#include <libsolidity/codegen/ExpressionCompiler.h>
|
||||
#include <libsolidity/ast/AST.h>
|
||||
#include <libsolidity/ast/TypeProvider.h>
|
||||
#include <libsolidity/analysis/TypeChecker.h>
|
||||
#include <liblangutil/ErrorReporter.h>
|
||||
#include <test/Options.h>
|
||||
@ -597,7 +598,7 @@ BOOST_AUTO_TEST_CASE(blockhash)
|
||||
}
|
||||
)";
|
||||
|
||||
auto blockhashFun = make_shared<FunctionType>(strings{"uint256"}, strings{"bytes32"},
|
||||
auto blockhashFun = TypeProvider::functionType(strings{"uint256"}, strings{"bytes32"},
|
||||
FunctionType::Kind::BlockHash, false, StateMutability::View);
|
||||
|
||||
bytes code = compileFirstExpression(sourceCode, {}, {}, {make_shared<MagicVariableDeclaration>("blockhash", blockhashFun)});
|
||||
@ -618,7 +619,7 @@ BOOST_AUTO_TEST_CASE(gas_left)
|
||||
)";
|
||||
bytes code = compileFirstExpression(
|
||||
sourceCode, {}, {},
|
||||
{make_shared<MagicVariableDeclaration>("gasleft", make_shared<FunctionType>(strings(), strings{"uint256"}, FunctionType::Kind::GasLeft))}
|
||||
{make_shared<MagicVariableDeclaration>("gasleft", TypeProvider::functionType(strings(), strings{"uint256"}, FunctionType::Kind::GasLeft))}
|
||||
);
|
||||
|
||||
bytes expectation = bytes({uint8_t(Instruction::GAS)});
|
||||
|
@ -436,7 +436,7 @@ BOOST_AUTO_TEST_CASE(getter_is_memory_type)
|
||||
)";
|
||||
CHECK_SUCCESS_NO_WARNINGS(text);
|
||||
// Check that the getters return a memory strings, not a storage strings.
|
||||
ContractDefinition const& c = dynamic_cast<ContractDefinition const&>(*m_compiler.ast("").nodes().at(1));
|
||||
ContractDefinition const& c = dynamic_cast<ContractDefinition const&>(*compiler().ast("").nodes().at(1));
|
||||
BOOST_CHECK(c.interfaceFunctions().size() == 2);
|
||||
for (auto const& f: c.interfaceFunctions())
|
||||
{
|
||||
|
@ -21,6 +21,7 @@
|
||||
*/
|
||||
|
||||
#include <libsolidity/ast/Types.h>
|
||||
#include <libsolidity/ast/TypeProvider.h>
|
||||
#include <libsolidity/ast/AST.h>
|
||||
#include <libdevcore/Keccak256.h>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
@ -39,51 +40,51 @@ BOOST_AUTO_TEST_SUITE(SolidityTypes)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(int_types)
|
||||
{
|
||||
BOOST_CHECK(*Type::fromElementaryTypeName(ElementaryTypeNameToken(Token::Int, 0, 0)) == *make_shared<IntegerType>(256, IntegerType::Modifier::Signed));
|
||||
BOOST_CHECK(*TypeProvider::fromElementaryTypeName(ElementaryTypeNameToken(Token::Int, 0, 0)) == *TypeProvider::integerType(256, IntegerType::Modifier::Signed));
|
||||
for (unsigned i = 8; i <= 256; i += 8)
|
||||
BOOST_CHECK(*Type::fromElementaryTypeName(ElementaryTypeNameToken(Token::IntM, i, 0)) == *make_shared<IntegerType>(i, IntegerType::Modifier::Signed));
|
||||
BOOST_CHECK(*TypeProvider::fromElementaryTypeName(ElementaryTypeNameToken(Token::IntM, i, 0)) == *TypeProvider::integerType(i, IntegerType::Modifier::Signed));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(uint_types)
|
||||
{
|
||||
BOOST_CHECK(*Type::fromElementaryTypeName(ElementaryTypeNameToken(Token::UInt, 0, 0)) == *make_shared<IntegerType>(256, IntegerType::Modifier::Unsigned));
|
||||
BOOST_CHECK(*TypeProvider::fromElementaryTypeName(ElementaryTypeNameToken(Token::UInt, 0, 0)) == *TypeProvider::integerType(256, IntegerType::Modifier::Unsigned));
|
||||
for (unsigned i = 8; i <= 256; i += 8)
|
||||
BOOST_CHECK(*Type::fromElementaryTypeName(ElementaryTypeNameToken(Token::UIntM, i, 0)) == *make_shared<IntegerType>(i, IntegerType::Modifier::Unsigned));
|
||||
BOOST_CHECK(*TypeProvider::fromElementaryTypeName(ElementaryTypeNameToken(Token::UIntM, i, 0)) == *TypeProvider::integerType(i, IntegerType::Modifier::Unsigned));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(byte_types)
|
||||
{
|
||||
BOOST_CHECK(*Type::fromElementaryTypeName(ElementaryTypeNameToken(Token::Byte, 0, 0)) == *make_shared<FixedBytesType>(1));
|
||||
BOOST_CHECK(*TypeProvider::fromElementaryTypeName(ElementaryTypeNameToken(Token::Byte, 0, 0)) == *TypeProvider::fixedBytesType(1));
|
||||
for (unsigned i = 1; i <= 32; i++)
|
||||
BOOST_CHECK(*Type::fromElementaryTypeName(ElementaryTypeNameToken(Token::BytesM, i, 0)) == *make_shared<FixedBytesType>(i));
|
||||
BOOST_CHECK(*TypeProvider::fromElementaryTypeName(ElementaryTypeNameToken(Token::BytesM, i, 0)) == *TypeProvider::fixedBytesType(i));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(fixed_types)
|
||||
{
|
||||
BOOST_CHECK(*Type::fromElementaryTypeName(ElementaryTypeNameToken(Token::Fixed, 0, 0)) == *make_shared<FixedPointType>(128, 18, FixedPointType::Modifier::Signed));
|
||||
BOOST_CHECK(*TypeProvider::fromElementaryTypeName(ElementaryTypeNameToken(Token::Fixed, 0, 0)) == *TypeProvider::fixedPointType(128, 18, FixedPointType::Modifier::Signed));
|
||||
for (unsigned i = 8; i <= 256; i += 8)
|
||||
{
|
||||
BOOST_CHECK(*Type::fromElementaryTypeName(ElementaryTypeNameToken(Token::FixedMxN, i, 0)) == *make_shared<FixedPointType>(i, 0, FixedPointType::Modifier::Signed));
|
||||
BOOST_CHECK(*Type::fromElementaryTypeName(ElementaryTypeNameToken(Token::FixedMxN, i, 2)) == *make_shared<FixedPointType>(i, 2, FixedPointType::Modifier::Signed));
|
||||
BOOST_CHECK(*TypeProvider::fromElementaryTypeName(ElementaryTypeNameToken(Token::FixedMxN, i, 0)) == *TypeProvider::fixedPointType(i, 0, FixedPointType::Modifier::Signed));
|
||||
BOOST_CHECK(*TypeProvider::fromElementaryTypeName(ElementaryTypeNameToken(Token::FixedMxN, i, 2)) == *TypeProvider::fixedPointType(i, 2, FixedPointType::Modifier::Signed));
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(ufixed_types)
|
||||
{
|
||||
BOOST_CHECK(*Type::fromElementaryTypeName(ElementaryTypeNameToken(Token::UFixed, 0, 0)) == *make_shared<FixedPointType>(128, 18, FixedPointType::Modifier::Unsigned));
|
||||
BOOST_CHECK(*TypeProvider::fromElementaryTypeName(ElementaryTypeNameToken(Token::UFixed, 0, 0)) == *TypeProvider::fixedPointType(128, 18, FixedPointType::Modifier::Unsigned));
|
||||
for (unsigned i = 8; i <= 256; i += 8)
|
||||
{
|
||||
BOOST_CHECK(*Type::fromElementaryTypeName(ElementaryTypeNameToken(Token::UFixedMxN, i, 0)) == *make_shared<FixedPointType>(i, 0, FixedPointType::Modifier::Unsigned));
|
||||
BOOST_CHECK(*Type::fromElementaryTypeName(ElementaryTypeNameToken(Token::UFixedMxN, i, 2)) == *make_shared<FixedPointType>(i, 2, FixedPointType::Modifier::Unsigned));
|
||||
BOOST_CHECK(*TypeProvider::fromElementaryTypeName(ElementaryTypeNameToken(Token::UFixedMxN, i, 0)) == *TypeProvider::fixedPointType(i, 0, FixedPointType::Modifier::Unsigned));
|
||||
BOOST_CHECK(*TypeProvider::fromElementaryTypeName(ElementaryTypeNameToken(Token::UFixedMxN, i, 2)) == *TypeProvider::fixedPointType(i, 2, FixedPointType::Modifier::Unsigned));
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(storage_layout_simple)
|
||||
{
|
||||
MemberList members(MemberList::MemberMap({
|
||||
{string("first"), Type::fromElementaryTypeName("uint128")},
|
||||
{string("second"), Type::fromElementaryTypeName("uint120")},
|
||||
{string("wraps"), Type::fromElementaryTypeName("uint16")}
|
||||
{string("first"), TypeProvider::fromElementaryTypeName("uint128")},
|
||||
{string("second"), TypeProvider::fromElementaryTypeName("uint120")},
|
||||
{string("wraps"), TypeProvider::fromElementaryTypeName("uint16")}
|
||||
}));
|
||||
BOOST_REQUIRE_EQUAL(u256(2), members.storageSize());
|
||||
BOOST_REQUIRE(members.memberStorageOffset("first") != nullptr);
|
||||
@ -97,15 +98,15 @@ BOOST_AUTO_TEST_CASE(storage_layout_simple)
|
||||
BOOST_AUTO_TEST_CASE(storage_layout_mapping)
|
||||
{
|
||||
MemberList members(MemberList::MemberMap({
|
||||
{string("first"), Type::fromElementaryTypeName("uint128")},
|
||||
{string("second"), make_shared<MappingType>(
|
||||
Type::fromElementaryTypeName("uint8"),
|
||||
Type::fromElementaryTypeName("uint8")
|
||||
{string("first"), TypeProvider::fromElementaryTypeName("uint128")},
|
||||
{string("second"), TypeProvider::mappingType(
|
||||
TypeProvider::fromElementaryTypeName("uint8"),
|
||||
TypeProvider::fromElementaryTypeName("uint8")
|
||||
)},
|
||||
{string("third"), Type::fromElementaryTypeName("uint16")},
|
||||
{string("final"), make_shared<MappingType>(
|
||||
Type::fromElementaryTypeName("uint8"),
|
||||
Type::fromElementaryTypeName("uint8")
|
||||
{string("third"), TypeProvider::fromElementaryTypeName("uint16")},
|
||||
{string("final"), TypeProvider::mappingType(
|
||||
TypeProvider::fromElementaryTypeName("uint8"),
|
||||
TypeProvider::fromElementaryTypeName("uint8")
|
||||
)},
|
||||
}));
|
||||
BOOST_REQUIRE_EQUAL(u256(4), members.storageSize());
|
||||
@ -121,13 +122,13 @@ BOOST_AUTO_TEST_CASE(storage_layout_mapping)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(storage_layout_arrays)
|
||||
{
|
||||
BOOST_CHECK(ArrayType(DataLocation::Storage, make_shared<FixedBytesType>(1), 32).storageSize() == 1);
|
||||
BOOST_CHECK(ArrayType(DataLocation::Storage, make_shared<FixedBytesType>(1), 33).storageSize() == 2);
|
||||
BOOST_CHECK(ArrayType(DataLocation::Storage, make_shared<FixedBytesType>(2), 31).storageSize() == 2);
|
||||
BOOST_CHECK(ArrayType(DataLocation::Storage, make_shared<FixedBytesType>(7), 8).storageSize() == 2);
|
||||
BOOST_CHECK(ArrayType(DataLocation::Storage, make_shared<FixedBytesType>(7), 9).storageSize() == 3);
|
||||
BOOST_CHECK(ArrayType(DataLocation::Storage, make_shared<FixedBytesType>(31), 9).storageSize() == 9);
|
||||
BOOST_CHECK(ArrayType(DataLocation::Storage, make_shared<FixedBytesType>(32), 9).storageSize() == 9);
|
||||
BOOST_CHECK(ArrayType(DataLocation::Storage, TypeProvider::fixedBytesType(1), 32).storageSize() == 1);
|
||||
BOOST_CHECK(ArrayType(DataLocation::Storage, TypeProvider::fixedBytesType(1), 33).storageSize() == 2);
|
||||
BOOST_CHECK(ArrayType(DataLocation::Storage, TypeProvider::fixedBytesType(2), 31).storageSize() == 2);
|
||||
BOOST_CHECK(ArrayType(DataLocation::Storage, TypeProvider::fixedBytesType(7), 8).storageSize() == 2);
|
||||
BOOST_CHECK(ArrayType(DataLocation::Storage, TypeProvider::fixedBytesType(7), 9).storageSize() == 3);
|
||||
BOOST_CHECK(ArrayType(DataLocation::Storage, TypeProvider::fixedBytesType(31), 9).storageSize() == 9);
|
||||
BOOST_CHECK(ArrayType(DataLocation::Storage, TypeProvider::fixedBytesType(32), 9).storageSize() == 9);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(type_identifier_escaping)
|
||||
@ -149,12 +150,12 @@ BOOST_AUTO_TEST_CASE(type_identifier_escaping)
|
||||
BOOST_AUTO_TEST_CASE(type_identifiers)
|
||||
{
|
||||
ASTNode::resetID();
|
||||
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("uint128")->identifier(), "t_uint128");
|
||||
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("int128")->identifier(), "t_int128");
|
||||
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("address")->identifier(), "t_address");
|
||||
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("uint8")->identifier(), "t_uint8");
|
||||
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("ufixed64x2")->identifier(), "t_ufixed64x2");
|
||||
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("fixed128x8")->identifier(), "t_fixed128x8");
|
||||
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("uint128")->identifier(), "t_uint128");
|
||||
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("int128")->identifier(), "t_int128");
|
||||
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("address")->identifier(), "t_address");
|
||||
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("uint8")->identifier(), "t_uint8");
|
||||
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("ufixed64x2")->identifier(), "t_ufixed64x2");
|
||||
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("fixed128x8")->identifier(), "t_fixed128x8");
|
||||
BOOST_CHECK_EQUAL(RationalNumberType(rational(7, 1)).identifier(), "t_rational_7_by_1");
|
||||
BOOST_CHECK_EQUAL(RationalNumberType(rational(200, 77)).identifier(), "t_rational_200_by_77");
|
||||
BOOST_CHECK_EQUAL(RationalNumberType(rational(2 * 200, 2 * 77)).identifier(), "t_rational_200_by_77");
|
||||
@ -163,22 +164,22 @@ BOOST_AUTO_TEST_CASE(type_identifiers)
|
||||
StringLiteralType(Literal(SourceLocation{}, Token::StringLiteral, make_shared<string>("abc - def"))).identifier(),
|
||||
"t_stringliteral_196a9142ee0d40e274a6482393c762b16dd8315713207365e1e13d8d85b74fc4"
|
||||
);
|
||||
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("byte")->identifier(), "t_bytes1");
|
||||
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("bytes8")->identifier(), "t_bytes8");
|
||||
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("bytes32")->identifier(), "t_bytes32");
|
||||
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("bool")->identifier(), "t_bool");
|
||||
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("bytes")->identifier(), "t_bytes_storage_ptr");
|
||||
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("bytes memory")->identifier(), "t_bytes_memory_ptr");
|
||||
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("bytes storage")->identifier(), "t_bytes_storage_ptr");
|
||||
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("bytes calldata")->identifier(), "t_bytes_calldata_ptr");
|
||||
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("string")->identifier(), "t_string_storage_ptr");
|
||||
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("string memory")->identifier(), "t_string_memory_ptr");
|
||||
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("string storage")->identifier(), "t_string_storage_ptr");
|
||||
BOOST_CHECK_EQUAL(Type::fromElementaryTypeName("string calldata")->identifier(), "t_string_calldata_ptr");
|
||||
ArrayType largeintArray(DataLocation::Memory, Type::fromElementaryTypeName("int128"), u256("2535301200456458802993406410752"));
|
||||
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("byte")->identifier(), "t_bytes1");
|
||||
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("bytes8")->identifier(), "t_bytes8");
|
||||
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("bytes32")->identifier(), "t_bytes32");
|
||||
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("bool")->identifier(), "t_bool");
|
||||
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("bytes")->identifier(), "t_bytes_storage_ptr");
|
||||
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("bytes memory")->identifier(), "t_bytes_memory_ptr");
|
||||
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("bytes storage")->identifier(), "t_bytes_storage_ptr");
|
||||
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("bytes calldata")->identifier(), "t_bytes_calldata_ptr");
|
||||
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("string")->identifier(), "t_string_storage_ptr");
|
||||
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("string memory")->identifier(), "t_string_memory_ptr");
|
||||
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("string storage")->identifier(), "t_string_storage_ptr");
|
||||
BOOST_CHECK_EQUAL(TypeProvider::fromElementaryTypeName("string calldata")->identifier(), "t_string_calldata_ptr");
|
||||
ArrayType largeintArray(DataLocation::Memory, TypeProvider::fromElementaryTypeName("int128"), u256("2535301200456458802993406410752"));
|
||||
BOOST_CHECK_EQUAL(largeintArray.identifier(), "t_array$_t_int128_$2535301200456458802993406410752_memory_ptr");
|
||||
TypePointer stringArray = make_shared<ArrayType>(DataLocation::Storage, Type::fromElementaryTypeName("string"), u256("20"));
|
||||
TypePointer multiArray = make_shared<ArrayType>(DataLocation::Storage, stringArray);
|
||||
TypePointer stringArray = TypeProvider::arrayType(DataLocation::Storage, TypeProvider::fromElementaryTypeName("string"), u256("20"));
|
||||
TypePointer multiArray = TypeProvider::arrayType(DataLocation::Storage, stringArray);
|
||||
BOOST_CHECK_EQUAL(multiArray->identifier(), "t_array$_t_array$_t_string_storage_$20_storage_$dyn_storage_ptr");
|
||||
|
||||
ContractDefinition c(SourceLocation{}, make_shared<string>("MyContract$"), {}, {}, {}, ContractDefinition::ContractKind::Contract);
|
||||
@ -194,14 +195,14 @@ BOOST_AUTO_TEST_CASE(type_identifiers)
|
||||
TupleType t({e.type(), s.type(), stringArray, nullptr});
|
||||
BOOST_CHECK_EQUAL(t.identifier(), "t_tuple$_t_type$_t_enum$_Enum_$4_$_$_t_type$_t_struct$_Struct_$3_storage_ptr_$_$_t_array$_t_string_storage_$20_storage_ptr_$__$");
|
||||
|
||||
TypePointer keccak256fun = make_shared<FunctionType>(strings{}, strings{}, FunctionType::Kind::KECCAK256);
|
||||
TypePointer keccak256fun = TypeProvider::functionType(strings{}, strings{}, FunctionType::Kind::KECCAK256);
|
||||
BOOST_CHECK_EQUAL(keccak256fun->identifier(), "t_function_keccak256_nonpayable$__$returns$__$");
|
||||
|
||||
FunctionType metaFun(TypePointers{keccak256fun}, TypePointers{s.type()}, strings{""}, strings{""});
|
||||
BOOST_CHECK_EQUAL(metaFun.identifier(), "t_function_internal_nonpayable$_t_function_keccak256_nonpayable$__$returns$__$_$returns$_t_type$_t_struct$_Struct_$3_storage_ptr_$_$");
|
||||
|
||||
TypePointer m = make_shared<MappingType>(Type::fromElementaryTypeName("bytes32"), s.type());
|
||||
MappingType m2(Type::fromElementaryTypeName("uint64"), m);
|
||||
TypePointer m = TypeProvider::mappingType(TypeProvider::fromElementaryTypeName("bytes32"), s.type());
|
||||
MappingType m2(TypeProvider::fromElementaryTypeName("uint64"), m);
|
||||
BOOST_CHECK_EQUAL(m2.identifier(), "t_mapping$_t_uint64_$_t_mapping$_t_bytes32_$_t_type$_t_struct$_Struct_$3_storage_ptr_$_$_$");
|
||||
|
||||
// TypeType is tested with contract
|
||||
@ -230,9 +231,9 @@ BOOST_AUTO_TEST_CASE(encoded_sizes)
|
||||
BOOST_CHECK_EQUAL(BoolType().calldataEncodedSize(true), 32);
|
||||
BOOST_CHECK_EQUAL(BoolType().calldataEncodedSize(false), 1);
|
||||
|
||||
shared_ptr<ArrayType> uint24Array = make_shared<ArrayType>(
|
||||
ArrayType const* uint24Array = TypeProvider::arrayType(
|
||||
DataLocation::Memory,
|
||||
make_shared<IntegerType>(24),
|
||||
TypeProvider::uint(24),
|
||||
9
|
||||
);
|
||||
BOOST_CHECK_EQUAL(uint24Array->calldataEncodedSize(true), 9 * 32);
|
||||
|
@ -66,14 +66,14 @@ SyntaxTest::SyntaxTest(string const& _filename, langutil::EVMVersion _evmVersion
|
||||
bool SyntaxTest::run(ostream& _stream, string const& _linePrefix, bool _formatted)
|
||||
{
|
||||
string const versionPragma = "pragma solidity >=0.0;\n";
|
||||
m_compiler.reset();
|
||||
m_compiler.setSources({{"", versionPragma + m_source}});
|
||||
m_compiler.setEVMVersion(m_evmVersion);
|
||||
compiler().reset();
|
||||
compiler().setSources({{"", versionPragma + m_source}});
|
||||
compiler().setEVMVersion(m_evmVersion);
|
||||
|
||||
if (m_compiler.parse())
|
||||
m_compiler.analyze();
|
||||
if (compiler().parse())
|
||||
compiler().analyze();
|
||||
|
||||
for (auto const& currentError: filterErrors(m_compiler.errors(), true))
|
||||
for (auto const& currentError: filterErrors(compiler().errors(), true))
|
||||
{
|
||||
int locationStart = -1, locationEnd = -1;
|
||||
if (auto location = boost::get_error_info<errinfo_sourceLocation>(*currentError))
|
||||
|
Loading…
Reference in New Issue
Block a user