Merge pull request #9208 from ethereum/develop

Merge develop into breaking.
This commit is contained in:
chriseth
2020-06-16 16:11:41 +02:00
committed by GitHub
48 changed files with 822 additions and 411 deletions
+9 -8
View File
@@ -123,11 +123,13 @@ bool NameAndTypeResolver::performImports(SourceUnit& _sourceUnit, map<string, So
return !error;
}
bool NameAndTypeResolver::resolveNamesAndTypes(ASTNode& _node, bool _resolveInsideCode)
bool NameAndTypeResolver::resolveNamesAndTypes(SourceUnit& _source)
{
try
{
return resolveNamesAndTypesInternal(_node, _resolveInsideCode);
for (shared_ptr<ASTNode> const& node: _source.nodes())
if (!resolveNamesAndTypesInternal(*node, true))
return false;
}
catch (langutil::FatalError const&)
{
@@ -135,6 +137,7 @@ bool NameAndTypeResolver::resolveNamesAndTypes(ASTNode& _node, bool _resolveInsi
throw; // Something is weird here, rather throw again.
return false;
}
return true;
}
bool NameAndTypeResolver::updateDeclaration(Declaration const& _declaration)
@@ -227,13 +230,14 @@ bool NameAndTypeResolver::resolveNamesAndTypesInternal(ASTNode& _node, bool _res
bool success = true;
setScope(contract->scope());
solAssert(!!m_currentScope, "");
solAssert(_resolveInsideCode, "");
m_globalContext.setCurrentContract(*contract);
updateDeclaration(*m_globalContext.currentSuper());
updateDeclaration(*m_globalContext.currentThis());
for (ASTPointer<InheritanceSpecifier> const& baseContract: contract->baseContracts())
if (!resolveNamesAndTypes(*baseContract, true))
if (!resolveNamesAndTypesInternal(*baseContract, true))
success = false;
setScope(contract);
@@ -254,23 +258,20 @@ bool NameAndTypeResolver::resolveNamesAndTypesInternal(ASTNode& _node, bool _res
for (ASTPointer<ASTNode> const& node: contract->subNodes())
{
setScope(contract);
if (!resolveNamesAndTypes(*node, false))
if (!resolveNamesAndTypesInternal(*node, false))
success = false;
}
if (!success)
return false;
if (!_resolveInsideCode)
return success;
setScope(contract);
// now resolve references inside the code
for (ASTPointer<ASTNode> const& node: contract->subNodes())
{
setScope(contract);
if (!resolveNamesAndTypes(*node, true))
if (!resolveNamesAndTypesInternal(*node, true))
success = false;
}
return success;
+2 -5
View File
@@ -65,12 +65,9 @@ public:
bool registerDeclarations(SourceUnit& _sourceUnit, ASTNode const* _currentScope = nullptr);
/// Applies the effect of import directives.
bool performImports(SourceUnit& _sourceUnit, std::map<std::string, SourceUnit const*> const& _sourceUnits);
/// Resolves all names and types referenced from the given AST Node.
/// This is usually only called at the contract level, but with a bit of care, it can also
/// be called at deeper levels.
/// @param _resolveInsideCode if false, does not descend into nodes that contain code.
/// Resolves all names and types referenced from the given Source Node.
/// @returns false in case of error.
bool resolveNamesAndTypes(ASTNode& _node, bool _resolveInsideCode = true);
bool resolveNamesAndTypes(SourceUnit& _source);
/// Updates the given global declaration (used for "this"). Not to be used with declarations
/// that create their own scope.
/// @returns false in case of error.
+46 -38
View File
@@ -62,9 +62,11 @@ bool TypeChecker::typeSupportedByOldABIEncoder(Type const& _type, bool _isLibrar
return true;
}
bool TypeChecker::checkTypeRequirements(ASTNode const& _contract)
bool TypeChecker::checkTypeRequirements(SourceUnit const& _source)
{
_contract.accept(*this);
m_currentSourceUnit = &_source;
_source.accept(*this);
m_currentSourceUnit = nullptr;
return Error::containsOnlyWarnings(m_errorReporter.errors());
}
@@ -375,7 +377,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
}
if (
_function.isPublic() &&
!_function.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2) &&
!experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2) &&
!typeSupportedByOldABIEncoder(*type(var), _function.libraryFunction())
)
m_errorReporter.typeError(
@@ -513,7 +515,7 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
else if (_variable.visibility() >= Visibility::Public)
{
FunctionType getter(_variable);
if (!_variable.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2))
if (!experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2))
{
vector<string> unsupportedTypes;
for (auto const& param: getter.parameterTypes() + getter.returnParameterTypes())
@@ -624,7 +626,7 @@ bool TypeChecker::visit(EventDefinition const& _eventDef)
if (!type(*var)->interfaceType(false))
m_errorReporter.typeError(3417_error, var->location(), "Internal or recursive type is not allowed as event parameter type.");
if (
!_eventDef.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2) &&
!experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2) &&
!typeSupportedByOldABIEncoder(*type(*var), false /* isLibrary */)
)
m_errorReporter.typeError(
@@ -668,17 +670,18 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
{
auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier);
if (ref == _inlineAssembly.annotation().externalReferences.end())
return numeric_limits<size_t>::max();
Declaration const* declaration = ref->second.declaration;
return false;
InlineAssemblyAnnotation::ExternalIdentifierInfo& identifierInfo = ref->second;
Declaration const* declaration = identifierInfo.declaration;
solAssert(!!declaration, "");
bool requiresStorage = ref->second.isSlot || ref->second.isOffset;
bool requiresStorage = identifierInfo.isSlot || identifierInfo.isOffset;
if (auto var = dynamic_cast<VariableDeclaration const*>(declaration))
{
solAssert(var->type(), "Expected variable type!");
if (var->immutable())
{
m_errorReporter.typeError(3773_error, _identifier.location, "Assembly access to immutable variables is not supported.");
return numeric_limits<size_t>::max();
return false;
}
if (var->isConstant())
{
@@ -687,17 +690,17 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
if (var && !var->value())
{
m_errorReporter.typeError(3224_error, _identifier.location, "Constant has no value.");
return numeric_limits<size_t>::max();
return false;
}
else if (_context == yul::IdentifierContext::LValue)
{
m_errorReporter.typeError(6252_error, _identifier.location, "Constant variables cannot be assigned to.");
return numeric_limits<size_t>::max();
return false;
}
else if (requiresStorage)
{
m_errorReporter.typeError(6617_error, _identifier.location, "The suffixes _offset and _slot can only be used on non-constant storage variables.");
return numeric_limits<size_t>::max();
return false;
}
else if (var && var->value() && !var->value()->annotation().type && !dynamic_cast<Literal const*>(var->value().get()))
{
@@ -706,7 +709,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
_identifier.location,
"Constant variables with non-literal values cannot be forward referenced from inline assembly."
);
return size_t(-1);
return false;
}
else if (!var || !type(*var)->isValueType() || (
!dynamic_cast<Literal const*>(var->value().get()) &&
@@ -714,7 +717,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
))
{
m_errorReporter.typeError(7615_error, _identifier.location, "Only direct number constants and references to such constants are supported by inline assembly.");
return size_t(-1);
return false;
}
}
@@ -725,33 +728,33 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
if (!var->isStateVariable() && !var->type()->dataStoredIn(DataLocation::Storage))
{
m_errorReporter.typeError(3622_error, _identifier.location, "The suffixes _offset and _slot can only be used on storage variables.");
return numeric_limits<size_t>::max();
return false;
}
else if (_context == yul::IdentifierContext::LValue)
{
if (var->isStateVariable())
{
m_errorReporter.typeError(4713_error, _identifier.location, "State variables cannot be assigned to - you have to use \"sstore()\".");
return numeric_limits<size_t>::max();
return false;
}
else if (ref->second.isOffset)
else if (identifierInfo.isOffset)
{
m_errorReporter.typeError(9739_error, _identifier.location, "Only _slot can be assigned to.");
return numeric_limits<size_t>::max();
return false;
}
else
solAssert(ref->second.isSlot, "");
solAssert(identifierInfo.isSlot, "");
}
}
else if (!var->isConstant() && var->isStateVariable())
{
m_errorReporter.typeError(1408_error, _identifier.location, "Only local variables are supported. To access storage variables, use the _slot and _offset suffixes.");
return numeric_limits<size_t>::max();
return false;
}
else if (var->type()->dataStoredIn(DataLocation::Storage))
{
m_errorReporter.typeError(9068_error, _identifier.location, "You have to use the _slot or _offset suffix to access storage reference variables.");
return numeric_limits<size_t>::max();
return false;
}
else if (var->type()->sizeOnStack() != 1)
{
@@ -759,21 +762,21 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
m_errorReporter.typeError(2370_error, _identifier.location, "Call data elements cannot be accessed directly. Copy to a local variable first or use \"calldataload\" or \"calldatacopy\" with manually determined offsets and sizes.");
else
m_errorReporter.typeError(9857_error, _identifier.location, "Only types that use one stack slot are supported.");
return numeric_limits<size_t>::max();
return false;
}
}
else if (requiresStorage)
{
m_errorReporter.typeError(7944_error, _identifier.location, "The suffixes _offset and _slot can only be used on storage variables.");
return numeric_limits<size_t>::max();
return false;
}
else if (_context == yul::IdentifierContext::LValue)
{
if (dynamic_cast<MagicVariableDeclaration const*>(declaration))
return numeric_limits<size_t>::max();
return false;
m_errorReporter.typeError(1990_error, _identifier.location, "Only local variables can be assigned to in inline assembly.");
return numeric_limits<size_t>::max();
return false;
}
if (_context == yul::IdentifierContext::RValue)
@@ -782,7 +785,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
if (dynamic_cast<FunctionDefinition const*>(declaration))
{
m_errorReporter.declarationError(2025_error, _identifier.location, "Access to functions is not allowed in inline assembly.");
return numeric_limits<size_t>::max();
return false;
}
else if (dynamic_cast<VariableDeclaration const*>(declaration))
{
@@ -792,14 +795,14 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
if (!contract->isLibrary())
{
m_errorReporter.typeError(4977_error, _identifier.location, "Expected a library.");
return numeric_limits<size_t>::max();
return false;
}
}
else
return numeric_limits<size_t>::max();
return false;
}
ref->second.valueSize = 1;
return size_t(1);
identifierInfo.valueSize = 1;
return true;
};
solAssert(!_inlineAssembly.annotation().analysisInfo, "");
_inlineAssembly.annotation().analysisInfo = make_shared<yul::AsmAnalysisInfo>();
@@ -1914,9 +1917,7 @@ void TypeChecker::typeCheckABIEncodeFunctions(
bool const isPacked = _functionType->kind() == FunctionType::Kind::ABIEncodePacked;
solAssert(_functionType->padArguments() != isPacked, "ABI function with unexpected padding");
bool const abiEncoderV2 = m_currentContract->sourceUnit().annotation().experimentalFeatures.count(
ExperimentalFeature::ABIEncoderV2
);
bool const abiEncoderV2 = experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2);
// Check for named arguments
if (!_functionCall.names().empty())
@@ -2313,11 +2314,10 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
{
case FunctionType::Kind::ABIDecode:
{
bool const abiEncoderV2 =
m_currentContract->sourceUnit().annotation().experimentalFeatures.count(
ExperimentalFeature::ABIEncoderV2
);
returnTypes = typeCheckABIDecodeAndRetrieveReturnType(_functionCall, abiEncoderV2);
returnTypes = typeCheckABIDecodeAndRetrieveReturnType(
_functionCall,
experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2)
);
break;
}
case FunctionType::Kind::ABIEncode:
@@ -3272,3 +3272,11 @@ void TypeChecker::requireLValue(Expression const& _expression, bool _ordinaryAss
m_errorReporter.typeError(errorId, _expression.location(), description);
}
bool TypeChecker::experimentalFeatureActive(ExperimentalFeature _feature) const
{
solAssert(m_currentSourceUnit, "");
if (m_currentContract)
solAssert(m_currentSourceUnit == &m_currentContract->sourceUnit(), "");
return m_currentSourceUnit->annotation().experimentalFeatures.count(_feature);
}
+5 -2
View File
@@ -51,9 +51,9 @@ public:
m_errorReporter(_errorReporter)
{}
/// Performs type checking on the given contract and all of its sub-nodes.
/// Performs type checking on the given source and all of its sub-nodes.
/// @returns true iff all checks passed. Note even if all checks passed, errors() can still contain warnings
bool checkTypeRequirements(ASTNode const& _contract);
bool checkTypeRequirements(SourceUnit const& _source);
/// @returns the type of an expression and asserts that it is present.
TypePointer const& type(Expression const& _expression) const;
@@ -165,6 +165,9 @@ private:
/// Runs type checks on @a _expression to infer its type and then checks that it is an LValue.
void requireLValue(Expression const& _expression, bool _ordinaryAssignment);
bool experimentalFeatureActive(ExperimentalFeature _feature) const;
SourceUnit const* m_currentSourceUnit = nullptr;
ContractDefinition const* m_currentContract = nullptr;
langutil::EVMVersion m_evmVersion;
+63 -45
View File
@@ -311,10 +311,15 @@ TypePointer Type::commonType(Type const* _a, Type const* _b)
return nullptr;
}
MemberList const& Type::members(ContractDefinition const* _currentScope) const
MemberList const& Type::members(ASTNode const* _currentScope) const
{
if (!m_members[_currentScope])
{
solAssert(
_currentScope == nullptr ||
dynamic_cast<SourceUnit const*>(_currentScope) ||
dynamic_cast<ContractDefinition const*>(_currentScope),
"");
MemberList::MemberMap members = nativeMembers(_currentScope);
if (_currentScope)
members += boundFunctions(*this, *_currentScope);
@@ -344,8 +349,20 @@ TypePointer Type::fullEncodingType(bool _inLibraryCall, bool _encoderV2, bool) c
return encodingType;
}
MemberList::MemberMap Type::boundFunctions(Type const& _type, ContractDefinition const& _scope)
MemberList::MemberMap Type::boundFunctions(Type const& _type, ASTNode const& _scope)
{
vector<UsingForDirective const*> usingForDirectives;
if (auto const* sourceUnit = dynamic_cast<SourceUnit const*>(&_scope))
usingForDirectives += ASTNode::filteredNodes<UsingForDirective>(sourceUnit->nodes());
else if (auto const* contract = dynamic_cast<ContractDefinition const*>(&_scope))
{
for (ContractDefinition const* contract: contract->annotation().linearizedBaseContracts)
usingForDirectives += contract->usingForDirectives();
usingForDirectives += ASTNode::filteredNodes<UsingForDirective>(contract->sourceUnit().nodes());
}
else
solAssert(false, "");
// Normalise data location of type.
DataLocation typeLocation = DataLocation::Storage;
if (auto refType = dynamic_cast<ReferenceType const*>(&_type))
@@ -353,38 +370,39 @@ MemberList::MemberMap Type::boundFunctions(Type const& _type, ContractDefinition
set<Declaration const*> seenFunctions;
MemberList::MemberMap members;
for (ContractDefinition const* contract: _scope.annotation().linearizedBaseContracts)
for (UsingForDirective const* ufd: contract->usingForDirectives())
{
// Convert both types to pointers for comparison to see if the `using for`
// directive applies.
// Further down, we check more detailed for each function if `_type` is
// convertible to the function parameter type.
if (ufd->typeName() &&
*TypeProvider::withLocationIfReference(typeLocation, &_type, true) !=
*TypeProvider::withLocationIfReference(
typeLocation,
ufd->typeName()->annotation().type,
true
)
for (UsingForDirective const* ufd: usingForDirectives)
{
// Convert both types to pointers for comparison to see if the `using for`
// directive applies.
// Further down, we check more detailed for each function if `_type` is
// convertible to the function parameter type.
if (ufd->typeName() &&
*TypeProvider::withLocationIfReference(typeLocation, &_type, true) !=
*TypeProvider::withLocationIfReference(
typeLocation,
ufd->typeName()->annotation().type,
true
)
)
continue;
auto const& library = dynamic_cast<ContractDefinition const&>(
*ufd->libraryName().annotation().referencedDeclaration
);
for (FunctionDefinition const* function: library.definedFunctions())
{
if (!function->isVisibleAsLibraryMember() || seenFunctions.count(function))
continue;
auto const& library = dynamic_cast<ContractDefinition const&>(
*ufd->libraryName().annotation().referencedDeclaration
);
for (FunctionDefinition const* function: library.definedFunctions())
{
if (!function->isVisibleAsLibraryMember() || seenFunctions.count(function))
continue;
seenFunctions.insert(function);
if (function->parameters().empty())
continue;
FunctionTypePointer fun =
dynamic_cast<FunctionType const&>(*function->typeViaContractName()).asBoundFunction();
if (_type.isImplicitlyConvertibleTo(*fun->selfType()))
members.emplace_back(function->name(), fun, function);
}
seenFunctions.insert(function);
if (function->parameters().empty())
continue;
FunctionTypePointer fun =
dynamic_cast<FunctionType const&>(*function->typeViaContractName()).asBoundFunction();
if (_type.isImplicitlyConvertibleTo(*fun->selfType()))
members.emplace_back(function->name(), fun, function);
}
}
return members;
}
@@ -464,7 +482,7 @@ bool AddressType::operator==(Type const& _other) const
return other.m_stateMutability == m_stateMutability;
}
MemberList::MemberMap AddressType::nativeMembers(ContractDefinition const*) const
MemberList::MemberMap AddressType::nativeMembers(ASTNode const*) const
{
MemberList::MemberMap members = {
{"balance", TypeProvider::uint256()},
@@ -1428,7 +1446,7 @@ TypeResult FixedBytesType::binaryOperatorResult(Token _operator, Type const* _ot
return nullptr;
}
MemberList::MemberMap FixedBytesType::nativeMembers(ContractDefinition const*) const
MemberList::MemberMap FixedBytesType::nativeMembers(ASTNode const*) const
{
return MemberList::MemberMap{MemberList::Member{"length", TypeProvider::uint(8)}};
}
@@ -1884,7 +1902,7 @@ string ArrayType::signatureInExternalFunction(bool _structsByName) const
}
}
MemberList::MemberMap ArrayType::nativeMembers(ContractDefinition const*) const
MemberList::MemberMap ArrayType::nativeMembers(ASTNode const*) const
{
MemberList::MemberMap members;
if (!isString())
@@ -2057,10 +2075,9 @@ string ContractType::canonicalName() const
return m_contract.annotation().canonicalName;
}
MemberList::MemberMap ContractType::nativeMembers(ContractDefinition const* _contract) const
MemberList::MemberMap ContractType::nativeMembers(ASTNode const*) const
{
MemberList::MemberMap members;
solAssert(_contract, "");
if (m_super)
{
// add the most derived of all functions which are visible in derived contracts
@@ -2091,14 +2108,13 @@ MemberList::MemberMap ContractType::nativeMembers(ContractDefinition const* _con
}
}
else if (!m_contract.isLibrary())
{
for (auto const& it: m_contract.interfaceFunctions())
members.emplace_back(
it.second->declaration().name(),
it.second->asExternallyCallableFunction(m_contract.isLibrary()),
&it.second->declaration()
);
}
return members;
}
@@ -2269,7 +2285,7 @@ string StructType::toString(bool _short) const
return ret;
}
MemberList::MemberMap StructType::nativeMembers(ContractDefinition const*) const
MemberList::MemberMap StructType::nativeMembers(ASTNode const*) const
{
MemberList::MemberMap members;
for (ASTPointer<VariableDeclaration> const& variable: m_struct.members())
@@ -3174,7 +3190,7 @@ FunctionTypePointer FunctionType::interfaceFunctionType() const
);
}
MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const* _scope) const
MemberList::MemberMap FunctionType::nativeMembers(ASTNode const* _scope) const
{
switch (m_kind)
{
@@ -3193,7 +3209,8 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const* _sco
functionDefinition->isPartOfExternalInterface()
)
{
solAssert(_scope->derivesFrom(*functionDefinition->annotation().contract), "");
auto const* contractScope = dynamic_cast<ContractDefinition const*>(_scope);
solAssert(contractScope && contractScope->derivesFrom(*functionDefinition->annotation().contract), "");
return {{"selector", TypeProvider::fixedBytes(4)}};
}
else
@@ -3668,13 +3685,14 @@ vector<tuple<string, TypePointer>> TypeType::makeStackItems() const
return {};
}
MemberList::MemberMap TypeType::nativeMembers(ContractDefinition const* _currentScope) const
MemberList::MemberMap TypeType::nativeMembers(ASTNode const* _currentScope) const
{
MemberList::MemberMap members;
if (m_actualType->category() == Category::Contract)
{
auto const* contractScope = dynamic_cast<ContractDefinition const*>(_currentScope);
ContractDefinition const& contract = dynamic_cast<ContractType const&>(*m_actualType).contractDefinition();
bool inDerivingScope = _currentScope && _currentScope->derivesFrom(contract);
bool inDerivingScope = contractScope && contractScope->derivesFrom(contract);
for (auto const* declaration: contract.declarations())
{
@@ -3776,7 +3794,7 @@ bool ModuleType::operator==(Type const& _other) const
return &m_sourceUnit == &dynamic_cast<ModuleType const&>(_other).m_sourceUnit;
}
MemberList::MemberMap ModuleType::nativeMembers(ContractDefinition const*) const
MemberList::MemberMap ModuleType::nativeMembers(ASTNode const*) const
{
MemberList::MemberMap symbols;
for (auto const& symbolName: m_sourceUnit.annotation().exportedSymbols)
@@ -3817,7 +3835,7 @@ bool MagicType::operator==(Type const& _other) const
return other.m_kind == m_kind;
}
MemberList::MemberMap MagicType::nativeMembers(ContractDefinition const*) const
MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const
{
switch (m_kind)
{
+14 -14
View File
@@ -315,9 +315,9 @@ public:
/// Returns the list of all members of this type. Default implementation: no members apart from bound.
/// @param _currentScope scope in which the members are accessed.
MemberList const& members(ContractDefinition const* _currentScope) const;
MemberList const& members(ASTNode const* _currentScope) const;
/// Convenience method, returns the type of the given named member or an empty pointer if no such member exists.
TypePointer memberType(std::string const& _name, ContractDefinition const* _currentScope = nullptr) const
TypePointer memberType(std::string const& _name, ASTNode const* _currentScope = nullptr) const
{
return members(_currentScope).memberType(_name);
}
@@ -361,12 +361,12 @@ public:
private:
/// @returns a member list containing all members added to this type by `using for` directives.
static MemberList::MemberMap boundFunctions(Type const& _type, ContractDefinition const& _scope);
static MemberList::MemberMap boundFunctions(Type const& _type, ASTNode const& _scope);
protected:
/// @returns the members native to this type depending on the given context. This function
/// is used (in conjunction with boundFunctions to fill m_members below.
virtual MemberList::MemberMap nativeMembers(ContractDefinition const* /*_currentScope*/) const
virtual MemberList::MemberMap nativeMembers(ASTNode const* /*_currentScope*/) const
{
return MemberList::MemberMap();
}
@@ -379,7 +379,7 @@ protected:
/// List of member types (parameterised by scape), will be lazy-initialized.
mutable std::map<ContractDefinition const*, std::unique_ptr<MemberList>> m_members;
mutable std::map<ASTNode const*, std::unique_ptr<MemberList>> m_members;
mutable std::optional<std::vector<std::tuple<std::string, TypePointer>>> m_stackItems;
mutable std::optional<size_t> m_stackSize;
};
@@ -408,7 +408,7 @@ public:
bool isValueType() const override { return true; }
bool nameable() const override { return true; }
MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
MemberList::MemberMap nativeMembers(ASTNode const*) const override;
std::string toString(bool _short) const override;
std::string canonicalName() const override;
@@ -649,7 +649,7 @@ public:
bool nameable() const override { return true; }
std::string toString(bool) const override { return "bytes" + util::toString(m_bytes); }
MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
MemberList::MemberMap nativeMembers(ASTNode const*) const override;
TypePointer encodingType() const override { return this; }
TypeResult interfaceType(bool) const override { return this; }
@@ -786,7 +786,7 @@ public:
std::string toString(bool _short) const override;
std::string canonicalName() const override;
std::string signatureInExternalFunction(bool _structsByName) const override;
MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
MemberList::MemberMap nativeMembers(ASTNode const* _currentScope) const override;
TypePointer encodingType() const override;
TypePointer decodingType() const override;
TypeResult interfaceType(bool _inLibrary) const override;
@@ -889,7 +889,7 @@ public:
std::string toString(bool _short) const override;
std::string canonicalName() const override;
MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
MemberList::MemberMap nativeMembers(ASTNode const* _currentScope) const override;
Type const* encodingType() const override;
@@ -949,7 +949,7 @@ public:
bool nameable() const override { return true; }
std::string toString(bool _short) const override;
MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
MemberList::MemberMap nativeMembers(ASTNode const* _currentScope) const override;
Type const* encodingType() const override;
TypeResult interfaceType(bool _inLibrary) const override;
@@ -1220,7 +1220,7 @@ public:
bool nameable() const override;
bool canLiveOutsideStorage() const override { return m_kind == Kind::Internal || m_kind == Kind::External; }
bool hasSimpleZeroValueInMemory() const override { return false; }
MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
MemberList::MemberMap nativeMembers(ASTNode const* _currentScope) const override;
TypePointer encodingType() const override;
TypeResult interfaceType(bool _inLibrary) const override;
@@ -1389,7 +1389,7 @@ public:
bool canLiveOutsideStorage() const override { return false; }
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
std::string toString(bool _short) const override { return "type(" + m_actualType->toString(_short) + ")"; }
MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
MemberList::MemberMap nativeMembers(ASTNode const* _currentScope) const override;
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
protected:
@@ -1441,7 +1441,7 @@ public:
bool canBeStored() const override { return false; }
bool canLiveOutsideStorage() const override { return true; }
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
MemberList::MemberMap nativeMembers(ASTNode const*) const override;
std::string toString(bool _short) const override;
@@ -1481,7 +1481,7 @@ public:
bool canBeStored() const override { return false; }
bool canLiveOutsideStorage() const override { return true; }
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
MemberList::MemberMap nativeMembers(ASTNode const*) const override;
std::string toString(bool _short) const override;
+3 -4
View File
@@ -384,12 +384,11 @@ void CompilerContext::appendInlineAssembly(
yul::Identifier const& _identifier,
yul::IdentifierContext,
bool _insideFunction
) -> size_t
) -> bool
{
if (_insideFunction)
return numeric_limits<size_t>::max();
auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name.str());
return it == _localVariables.end() ? numeric_limits<size_t>::max() : 1;
return false;
return contains(_localVariables, _identifier.name.str());
};
identifierAccess.generateCode = [&](
yul::Identifier const& _identifier,
+21 -24
View File
@@ -326,28 +326,28 @@ bool CompilerStack::analyze()
if (source->ast && !resolver.performImports(*source->ast, sourceUnitsByName))
return false;
// This is the main name and type resolution loop. Needs to be run for every contract, because
// the special variables "this" and "super" must be set appropriately.
for (Source const* source: m_sourceOrder)
if (source->ast && !resolver.resolveNamesAndTypes(*source->ast))
return false;
// Store contract definitions.
for (Source const* source: m_sourceOrder)
if (source->ast)
for (ASTPointer<ASTNode> const& node: source->ast->nodes())
for (
ContractDefinition const* contract:
ASTNode::filteredNodes<ContractDefinition>(source->ast->nodes())
)
{
if (!resolver.resolveNamesAndTypes(*node))
return false;
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
{
// Note that we now reference contracts by their fully qualified names, and
// thus contracts can only conflict if declared in the same source file. This
// should already cause a double-declaration error elsewhere.
if (m_contracts.find(contract->fullyQualifiedName()) == m_contracts.end())
m_contracts[contract->fullyQualifiedName()].contract = contract;
else
solAssert(
m_errorReporter.hasErrors(),
"Contract already present (name clash?), but no error was reported."
);
}
// Note that we now reference contracts by their fully qualified names, and
// thus contracts can only conflict if declared in the same source file. This
// should already cause a double-declaration error elsewhere.
if (!m_contracts.count(contract->fullyQualifiedName()))
m_contracts[contract->fullyQualifiedName()].contract = contract;
else
solAssert(
m_errorReporter.hasErrors(),
"Contract already present (name clash?), but no error was reported."
);
}
DeclarationTypeChecker declarationTypeChecker(m_errorReporter, m_evmVersion);
@@ -376,11 +376,8 @@ bool CompilerStack::analyze()
// which is only done one step later.
TypeChecker typeChecker(m_evmVersion, m_errorReporter);
for (Source const* source: m_sourceOrder)
if (source->ast)
for (ASTPointer<ASTNode> const& node: source->ast->nodes())
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
if (!typeChecker.checkTypeRequirements(*contract))
noErrors = false;
if (source->ast && !typeChecker.checkTypeRequirements(*source->ast))
noErrors = false;
if (noErrors)
{