mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge remote-tracking branch 'origin/develop' into breaking
This commit is contained in:
@@ -27,6 +27,8 @@
|
||||
#include <libsolidity/ast/TypeProvider.h>
|
||||
#include <liblangutil/ErrorReporter.h>
|
||||
|
||||
#include <limits>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity;
|
||||
using namespace solidity::frontend;
|
||||
|
||||
@@ -71,7 +71,7 @@ bool ContractLevelChecker::check(SourceUnit const& _sourceUnit)
|
||||
findDuplicateDefinitions(
|
||||
filterDeclarations<EventDefinition>(*_sourceUnit.annotation().exportedSymbols)
|
||||
);
|
||||
if (!Error::containsOnlyWarnings(m_errorReporter.errors()))
|
||||
if (Error::containsErrors(m_errorReporter.errors()))
|
||||
noErrors = false;
|
||||
for (ASTPointer<ASTNode> const& node: _sourceUnit.nodes())
|
||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||
@@ -97,7 +97,7 @@ bool ContractLevelChecker::check(ContractDefinition const& _contract)
|
||||
checkPayableFallbackWithoutReceive(_contract);
|
||||
checkStorageSize(_contract);
|
||||
|
||||
return Error::containsOnlyWarnings(m_errorReporter.errors());
|
||||
return !Error::containsErrors(m_errorReporter.errors());
|
||||
}
|
||||
|
||||
void ContractLevelChecker::checkDuplicateFunctions(ContractDefinition const& _contract)
|
||||
|
||||
@@ -36,7 +36,7 @@ bool ControlFlowAnalyzer::run()
|
||||
for (auto& [pair, flow]: m_cfg.allFunctionFlows())
|
||||
analyze(*pair.function, pair.contract, *flow);
|
||||
|
||||
return Error::containsOnlyWarnings(m_errorReporter.errors());
|
||||
return !Error::containsErrors(m_errorReporter.errors());
|
||||
}
|
||||
|
||||
void ControlFlowAnalyzer::analyze(FunctionDefinition const& _function, ContractDefinition const* _contract, FunctionFlow const& _flow)
|
||||
|
||||
@@ -409,7 +409,8 @@ bool ControlFlowBuilder::visit(InlineAssembly const& _inlineAssembly)
|
||||
void ControlFlowBuilder::visit(yul::Statement const& _statement)
|
||||
{
|
||||
solAssert(m_currentNode && m_inlineAssembly, "");
|
||||
m_currentNode->location = langutil::SourceLocation::smallestCovering(m_currentNode->location, locationOf(_statement));
|
||||
solAssert(nativeLocationOf(_statement) == originLocationOf(_statement), "");
|
||||
m_currentNode->location = langutil::SourceLocation::smallestCovering(m_currentNode->location, nativeLocationOf(_statement));
|
||||
ASTWalker::visit(_statement);
|
||||
}
|
||||
|
||||
@@ -496,14 +497,15 @@ void ControlFlowBuilder::operator()(yul::Identifier const& _identifier)
|
||||
solAssert(m_currentNode && m_inlineAssembly, "");
|
||||
auto const& externalReferences = m_inlineAssembly->annotation().externalReferences;
|
||||
if (externalReferences.count(&_identifier))
|
||||
{
|
||||
if (auto const* declaration = dynamic_cast<VariableDeclaration const*>(externalReferences.at(&_identifier).declaration))
|
||||
{
|
||||
solAssert(nativeLocationOf(_identifier) == originLocationOf(_identifier), "");
|
||||
m_currentNode->variableOccurrences.emplace_back(
|
||||
*declaration,
|
||||
VariableOccurrence::Kind::Access,
|
||||
_identifier.debugData->location
|
||||
nativeLocationOf(_identifier)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ControlFlowBuilder::operator()(yul::Assignment const& _assignment)
|
||||
@@ -514,11 +516,14 @@ void ControlFlowBuilder::operator()(yul::Assignment const& _assignment)
|
||||
for (auto const& variable: _assignment.variableNames)
|
||||
if (externalReferences.count(&variable))
|
||||
if (auto const* declaration = dynamic_cast<VariableDeclaration const*>(externalReferences.at(&variable).declaration))
|
||||
{
|
||||
solAssert(nativeLocationOf(variable) == originLocationOf(variable), "");
|
||||
m_currentNode->variableOccurrences.emplace_back(
|
||||
*declaration,
|
||||
VariableOccurrence::Kind::Assignment,
|
||||
variable.debugData->location
|
||||
nativeLocationOf(variable)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void ControlFlowBuilder::operator()(yul::FunctionCall const& _functionCall)
|
||||
@@ -548,7 +553,7 @@ void ControlFlowBuilder::operator()(yul::FunctionDefinition const&)
|
||||
void ControlFlowBuilder::operator()(yul::Leave const&)
|
||||
{
|
||||
// This has to be implemented, if we ever decide to visit functions.
|
||||
solUnimplementedAssert(false, "");
|
||||
solUnimplemented("");
|
||||
}
|
||||
|
||||
bool ControlFlowBuilder::visit(VariableDeclaration const& _variableDeclaration)
|
||||
|
||||
@@ -27,7 +27,7 @@ using namespace solidity::frontend;
|
||||
bool CFG::constructFlow(ASTNode const& _astRoot)
|
||||
{
|
||||
_astRoot.accept(*this);
|
||||
return Error::containsOnlyWarnings(m_errorReporter.errors());
|
||||
return !Error::containsErrors(m_errorReporter.errors());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -140,6 +140,30 @@ bool DeclarationTypeChecker::visit(StructDefinition const& _struct)
|
||||
return false;
|
||||
}
|
||||
|
||||
void DeclarationTypeChecker::endVisit(UserDefinedValueTypeDefinition const& _userDefined)
|
||||
{
|
||||
TypeName const* typeName = _userDefined.underlyingType();
|
||||
solAssert(typeName, "");
|
||||
if (!dynamic_cast<ElementaryTypeName const*>(typeName))
|
||||
m_errorReporter.fatalTypeError(
|
||||
8657_error,
|
||||
typeName->location(),
|
||||
"The underlying type for a user defined value type has to be an elementary value type."
|
||||
);
|
||||
|
||||
Type const* type = typeName->annotation().type;
|
||||
solAssert(type, "");
|
||||
solAssert(!dynamic_cast<UserDefinedValueType const*>(type), "");
|
||||
if (!type->isValueType())
|
||||
m_errorReporter.typeError(
|
||||
8129_error,
|
||||
_userDefined.location(),
|
||||
"The underlying type of the user defined value type \"" +
|
||||
_userDefined.name() +
|
||||
"\" is not a value type."
|
||||
);
|
||||
}
|
||||
|
||||
void DeclarationTypeChecker::endVisit(UserDefinedTypeName const& _typeName)
|
||||
{
|
||||
if (_typeName.annotation().type)
|
||||
@@ -158,6 +182,8 @@ void DeclarationTypeChecker::endVisit(UserDefinedTypeName const& _typeName)
|
||||
_typeName.annotation().type = TypeProvider::enumType(*enumDef);
|
||||
else if (ContractDefinition const* contract = dynamic_cast<ContractDefinition const*>(declaration))
|
||||
_typeName.annotation().type = TypeProvider::contract(*contract);
|
||||
else if (auto userDefinedValueType = dynamic_cast<UserDefinedValueTypeDefinition const*>(declaration))
|
||||
_typeName.annotation().type = TypeProvider::userDefinedValueType(*userDefinedValueType);
|
||||
else
|
||||
{
|
||||
_typeName.annotation().type = TypeProvider::emptyTuple();
|
||||
@@ -227,12 +253,13 @@ void DeclarationTypeChecker::endVisit(Mapping const& _mapping)
|
||||
{
|
||||
case Type::Category::Enum:
|
||||
case Type::Category::Contract:
|
||||
case Type::Category::UserDefinedValueType:
|
||||
break;
|
||||
default:
|
||||
m_errorReporter.fatalTypeError(
|
||||
7804_error,
|
||||
typeName->location(),
|
||||
"Only elementary types, contract types or enums are allowed as mapping keys."
|
||||
"Only elementary types, user defined value types, contract types or enums are allowed as mapping keys."
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -60,6 +60,7 @@ private:
|
||||
void endVisit(VariableDeclaration const& _variable) override;
|
||||
bool visit(EnumDefinition const& _enum) override;
|
||||
bool visit(StructDefinition const& _struct) override;
|
||||
void endVisit(UserDefinedValueTypeDefinition const& _userDefined) override;
|
||||
bool visit(UsingForDirective const& _usingForDirective) override;
|
||||
bool visit(InheritanceSpecifier const& _inheritanceSpecifier) override;
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include <regex>
|
||||
#include <string_view>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity;
|
||||
@@ -233,7 +234,7 @@ void DocStringTagParser::parseDocStrings(
|
||||
|
||||
for (auto const& [tagName, tagValue]: _annotation.docTags)
|
||||
{
|
||||
string static const customPrefix("custom:");
|
||||
string_view static constexpr customPrefix("custom:");
|
||||
if (tagName == "custom" || tagName == "custom:")
|
||||
m_errorReporter.docstringParsingError(
|
||||
6564_error,
|
||||
|
||||
@@ -102,7 +102,12 @@ bool NameAndTypeResolver::performImports(SourceUnit& _sourceUnit, map<string, So
|
||||
else
|
||||
for (Declaration const* declaration: declarations)
|
||||
if (!DeclarationRegistrationHelper::registerDeclaration(
|
||||
target, *declaration, alias.alias.get(), &alias.location, false, m_errorReporter
|
||||
target,
|
||||
*declaration,
|
||||
alias.alias ? alias.alias.get() : &alias.symbol->name(),
|
||||
&alias.location,
|
||||
false,
|
||||
m_errorReporter
|
||||
))
|
||||
error = true;
|
||||
}
|
||||
@@ -607,13 +612,31 @@ bool DeclarationRegistrationHelper::visitNode(ASTNode& _node)
|
||||
|
||||
if (auto* declaration = dynamic_cast<Declaration*>(&_node))
|
||||
registerDeclaration(*declaration);
|
||||
|
||||
if (auto* annotation = dynamic_cast<TypeDeclarationAnnotation*>(&_node.annotation()))
|
||||
{
|
||||
string canonicalName = dynamic_cast<Declaration const&>(_node).name();
|
||||
solAssert(!canonicalName.empty(), "");
|
||||
|
||||
for (
|
||||
ASTNode const* scope = m_currentScope;
|
||||
scope != nullptr;
|
||||
scope = m_scopes[scope]->enclosingNode()
|
||||
)
|
||||
if (auto decl = dynamic_cast<Declaration const*>(scope))
|
||||
{
|
||||
solAssert(!decl->name().empty(), "");
|
||||
canonicalName = decl->name() + "." + canonicalName;
|
||||
}
|
||||
|
||||
annotation->canonicalName = canonicalName;
|
||||
}
|
||||
|
||||
if (dynamic_cast<ScopeOpener const*>(&_node))
|
||||
enterNewSubScope(_node);
|
||||
|
||||
if (auto* variableScope = dynamic_cast<VariableScope*>(&_node))
|
||||
m_currentFunction = variableScope;
|
||||
if (auto* annotation = dynamic_cast<TypeDeclarationAnnotation*>(&_node.annotation()))
|
||||
annotation->canonicalName = currentCanonicalName();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -663,23 +686,4 @@ void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaratio
|
||||
solAssert(_declaration.annotation().contract == m_currentContract, "");
|
||||
}
|
||||
|
||||
string DeclarationRegistrationHelper::currentCanonicalName() const
|
||||
{
|
||||
string ret;
|
||||
for (
|
||||
ASTNode const* scope = m_currentScope;
|
||||
scope != nullptr;
|
||||
scope = m_scopes[scope]->enclosingNode()
|
||||
)
|
||||
{
|
||||
if (auto decl = dynamic_cast<Declaration const*>(scope))
|
||||
{
|
||||
if (!ret.empty())
|
||||
ret = "." + ret;
|
||||
ret = decl->name() + ret;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -176,9 +176,6 @@ private:
|
||||
|
||||
static bool isOverloadedFunction(Declaration const& _declaration1, Declaration const& _declaration2);
|
||||
|
||||
/// @returns the canonical name of the current scope.
|
||||
std::string currentCanonicalName() const;
|
||||
|
||||
std::map<ASTNode const*, std::shared_ptr<DeclarationContainer>>& m_scopes;
|
||||
ASTNode const* m_currentScope = nullptr;
|
||||
VariableScope* m_currentFunction = nullptr;
|
||||
|
||||
@@ -86,7 +86,8 @@ private:
|
||||
int currentNode = static_cast<int>(numNodes++);
|
||||
nodes[_function] = currentNode;
|
||||
nodeInv[currentNode] = _function;
|
||||
if (_function.overrides())
|
||||
|
||||
if (!_function.baseFunctions().empty())
|
||||
for (auto const& baseFunction: _function.baseFunctions())
|
||||
addEdge(currentNode, visit(baseFunction));
|
||||
else
|
||||
@@ -518,7 +519,7 @@ void OverrideChecker::checkOverride(OverrideProxy const& _overriding, OverridePr
|
||||
"Override changes modifier signature."
|
||||
);
|
||||
|
||||
if (!_overriding.overrides())
|
||||
if (!_overriding.overrides() && !(_super.isFunction() && _super.contract().isInterface()))
|
||||
overrideError(
|
||||
_overriding,
|
||||
_super,
|
||||
|
||||
@@ -36,14 +36,14 @@ using namespace solidity::frontend;
|
||||
bool PostTypeChecker::check(ASTNode const& _astRoot)
|
||||
{
|
||||
_astRoot.accept(*this);
|
||||
return Error::containsOnlyWarnings(m_errorReporter.errors());
|
||||
return !Error::containsErrors(m_errorReporter.errors());
|
||||
}
|
||||
|
||||
bool PostTypeChecker::finalize()
|
||||
{
|
||||
for (auto& checker: m_checkers)
|
||||
checker->finalize();
|
||||
return Error::containsOnlyWarnings(m_errorReporter.errors());
|
||||
return !Error::containsErrors(m_errorReporter.errors());
|
||||
}
|
||||
|
||||
bool PostTypeChecker::visit(ContractDefinition const& _contractDefinition)
|
||||
|
||||
@@ -68,5 +68,5 @@ bool PostTypeContractLevelChecker::check(ContractDefinition const& _contract)
|
||||
errorHashes[hash][signature] = error->location();
|
||||
}
|
||||
|
||||
return Error::containsOnlyWarnings(m_errorReporter.errors());
|
||||
return !Error::containsErrors(m_errorReporter.errors());
|
||||
}
|
||||
|
||||
@@ -201,9 +201,13 @@ bool ReferencesResolver::visit(Return const& _return)
|
||||
|
||||
void ReferencesResolver::operator()(yul::FunctionDefinition const& _function)
|
||||
{
|
||||
validateYulIdentifierName(_function.name, _function.debugData->location);
|
||||
solAssert(nativeLocationOf(_function) == originLocationOf(_function), "");
|
||||
validateYulIdentifierName(_function.name, nativeLocationOf(_function));
|
||||
for (yul::TypedName const& varName: _function.parameters + _function.returnVariables)
|
||||
validateYulIdentifierName(varName.name, varName.debugData->location);
|
||||
{
|
||||
solAssert(nativeLocationOf(varName) == originLocationOf(varName), "");
|
||||
validateYulIdentifierName(varName.name, nativeLocationOf(varName));
|
||||
}
|
||||
|
||||
bool wasInsideFunction = m_yulInsideFunction;
|
||||
m_yulInsideFunction = true;
|
||||
@@ -213,13 +217,17 @@ void ReferencesResolver::operator()(yul::FunctionDefinition const& _function)
|
||||
|
||||
void ReferencesResolver::operator()(yul::Identifier const& _identifier)
|
||||
{
|
||||
static set<string> suffixes{"slot", "offset", "length"};
|
||||
solAssert(nativeLocationOf(_identifier) == originLocationOf(_identifier), "");
|
||||
|
||||
static set<string> suffixes{"slot", "offset", "length", "address", "selector"};
|
||||
string suffix;
|
||||
for (string const& s: suffixes)
|
||||
if (boost::algorithm::ends_with(_identifier.name.str(), "." + s))
|
||||
suffix = s;
|
||||
|
||||
// Could also use `pathFromCurrentScope`, split by '.'
|
||||
// Could also use `pathFromCurrentScope`, split by '.'.
|
||||
// If we do that, suffix should only be set for when it has a special
|
||||
// meaning, not for normal identifierPaths.
|
||||
auto declarations = m_resolver.nameFromCurrentScope(_identifier.name.str());
|
||||
if (!suffix.empty())
|
||||
{
|
||||
@@ -238,7 +246,7 @@ void ReferencesResolver::operator()(yul::Identifier const& _identifier)
|
||||
{
|
||||
m_errorReporter.declarationError(
|
||||
4718_error,
|
||||
_identifier.debugData->location,
|
||||
nativeLocationOf(_identifier),
|
||||
"Multiple matching identifiers. Resolving overloaded identifiers is not supported."
|
||||
);
|
||||
return;
|
||||
@@ -251,7 +259,7 @@ void ReferencesResolver::operator()(yul::Identifier const& _identifier)
|
||||
)
|
||||
m_errorReporter.declarationError(
|
||||
9467_error,
|
||||
_identifier.debugData->location,
|
||||
nativeLocationOf(_identifier),
|
||||
"Identifier not found. Use \".slot\" and \".offset\" to access storage variables."
|
||||
);
|
||||
return;
|
||||
@@ -261,7 +269,7 @@ void ReferencesResolver::operator()(yul::Identifier const& _identifier)
|
||||
{
|
||||
m_errorReporter.declarationError(
|
||||
6578_error,
|
||||
_identifier.debugData->location,
|
||||
nativeLocationOf(_identifier),
|
||||
"Cannot access local Solidity variables from inside an inline assembly function."
|
||||
);
|
||||
return;
|
||||
@@ -274,7 +282,10 @@ void ReferencesResolver::operator()(yul::Identifier const& _identifier)
|
||||
void ReferencesResolver::operator()(yul::VariableDeclaration const& _varDecl)
|
||||
{
|
||||
for (auto const& identifier: _varDecl.variables)
|
||||
validateYulIdentifierName(identifier.name, identifier.debugData->location);
|
||||
{
|
||||
solAssert(nativeLocationOf(identifier) == originLocationOf(identifier), "");
|
||||
validateYulIdentifierName(identifier.name, nativeLocationOf(identifier));
|
||||
}
|
||||
|
||||
if (_varDecl.value)
|
||||
visit(*_varDecl.value);
|
||||
|
||||
@@ -86,7 +86,7 @@ StaticAnalyzer::~StaticAnalyzer()
|
||||
bool StaticAnalyzer::analyze(SourceUnit const& _sourceUnit)
|
||||
{
|
||||
_sourceUnit.accept(*this);
|
||||
return Error::containsOnlyWarnings(m_errorReporter.errors());
|
||||
return !Error::containsErrors(m_errorReporter.errors());
|
||||
}
|
||||
|
||||
bool StaticAnalyzer::visit(ContractDefinition const& _contract)
|
||||
|
||||
@@ -41,7 +41,7 @@ using namespace solidity::util;
|
||||
bool SyntaxChecker::checkSyntax(ASTNode const& _astRoot)
|
||||
{
|
||||
_astRoot.accept(*this);
|
||||
return Error::containsOnlyWarnings(m_errorReporter.errors());
|
||||
return !Error::containsErrors(m_errorReporter.errors());
|
||||
}
|
||||
|
||||
bool SyntaxChecker::visit(SourceUnit const& _sourceUnit)
|
||||
|
||||
@@ -73,7 +73,7 @@ bool TypeChecker::checkTypeRequirements(SourceUnit const& _source)
|
||||
m_currentSourceUnit = &_source;
|
||||
_source.accept(*this);
|
||||
m_currentSourceUnit = nullptr;
|
||||
return Error::containsOnlyWarnings(m_errorReporter.errors());
|
||||
return !Error::containsErrors(m_errorReporter.errors());
|
||||
}
|
||||
|
||||
Type const* TypeChecker::type(Expression const& _expression) const
|
||||
@@ -246,7 +246,10 @@ TypePointers TypeChecker::typeCheckMetaTypeFunctionAndRetrieveReturnType(Functio
|
||||
Type::Category typeCategory = typeTypePtr->actualType()->category();
|
||||
if (auto const* contractType = dynamic_cast<ContractType const*>(typeTypePtr->actualType()))
|
||||
wrongType = contractType->isSuper();
|
||||
else if (typeCategory != Type::Category::Integer)
|
||||
else if (
|
||||
typeCategory != Type::Category::Integer &&
|
||||
typeCategory != Type::Category::Enum
|
||||
)
|
||||
wrongType = true;
|
||||
}
|
||||
else
|
||||
@@ -257,7 +260,7 @@ TypePointers TypeChecker::typeCheckMetaTypeFunctionAndRetrieveReturnType(Functio
|
||||
4259_error,
|
||||
arguments.front()->location(),
|
||||
"Invalid type for argument in the function call. "
|
||||
"A contract type or an integer type is required, but " +
|
||||
"An enum type, contract type or an integer type is required, but " +
|
||||
type(*arguments.front())->toString(true) + " provided."
|
||||
);
|
||||
|
||||
@@ -314,14 +317,22 @@ void TypeChecker::endVisit(InheritanceSpecifier const& _inheritance)
|
||||
|
||||
void TypeChecker::endVisit(ModifierDefinition const& _modifier)
|
||||
{
|
||||
if (_modifier.virtualSemantics())
|
||||
if (auto const* contractDef = dynamic_cast<ContractDefinition const*>(_modifier.scope()))
|
||||
if (contractDef->isLibrary())
|
||||
m_errorReporter.typeError(
|
||||
3275_error,
|
||||
_modifier.location(),
|
||||
"Modifiers in a library cannot be virtual."
|
||||
);
|
||||
if (auto const* contractDef = dynamic_cast<ContractDefinition const*>(_modifier.scope()))
|
||||
{
|
||||
if (_modifier.virtualSemantics() && contractDef->isLibrary())
|
||||
m_errorReporter.typeError(
|
||||
3275_error,
|
||||
_modifier.location(),
|
||||
"Modifiers in a library cannot be virtual."
|
||||
);
|
||||
|
||||
if (contractDef->isInterface())
|
||||
m_errorReporter.typeError(
|
||||
6408_error,
|
||||
_modifier.location(),
|
||||
"Modifiers cannot be defined or declared in interfaces."
|
||||
);
|
||||
}
|
||||
|
||||
if (!_modifier.isImplemented() && !_modifier.virtualSemantics())
|
||||
m_errorReporter.typeError(8063_error, _modifier.location(), "Modifiers without implementation must be marked virtual.");
|
||||
@@ -754,7 +765,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
solAssert(var->type(), "Expected variable type!");
|
||||
if (var->immutable())
|
||||
{
|
||||
m_errorReporter.typeError(3773_error, _identifier.debugData->location, "Assembly access to immutable variables is not supported.");
|
||||
m_errorReporter.typeError(3773_error, nativeLocationOf(_identifier), "Assembly access to immutable variables is not supported.");
|
||||
return false;
|
||||
}
|
||||
if (var->isConstant())
|
||||
@@ -763,7 +774,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
{
|
||||
m_errorReporter.typeError(
|
||||
3558_error,
|
||||
_identifier.debugData->location,
|
||||
nativeLocationOf(_identifier),
|
||||
"Constant variable is circular."
|
||||
);
|
||||
return false;
|
||||
@@ -773,24 +784,24 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
|
||||
if (var && !var->value())
|
||||
{
|
||||
m_errorReporter.typeError(3224_error, _identifier.debugData->location, "Constant has no value.");
|
||||
m_errorReporter.typeError(3224_error, nativeLocationOf(_identifier), "Constant has no value.");
|
||||
return false;
|
||||
}
|
||||
else if (_context == yul::IdentifierContext::LValue)
|
||||
{
|
||||
m_errorReporter.typeError(6252_error, _identifier.debugData->location, "Constant variables cannot be assigned to.");
|
||||
m_errorReporter.typeError(6252_error, nativeLocationOf(_identifier), "Constant variables cannot be assigned to.");
|
||||
return false;
|
||||
}
|
||||
else if (!identifierInfo.suffix.empty())
|
||||
else if (identifierInfo.suffix == "slot" || identifierInfo.suffix == "offset")
|
||||
{
|
||||
m_errorReporter.typeError(6617_error, _identifier.debugData->location, "The suffixes .offset and .slot can only be used on non-constant storage variables.");
|
||||
m_errorReporter.typeError(6617_error, nativeLocationOf(_identifier), "The suffixes .offset and .slot can only be used on non-constant storage variables.");
|
||||
return false;
|
||||
}
|
||||
else if (var && var->value() && !var->value()->annotation().type && !dynamic_cast<Literal const*>(var->value().get()))
|
||||
{
|
||||
m_errorReporter.typeError(
|
||||
2249_error,
|
||||
_identifier.debugData->location,
|
||||
nativeLocationOf(_identifier),
|
||||
"Constant variables with non-literal values cannot be forward referenced from inline assembly."
|
||||
);
|
||||
return false;
|
||||
@@ -800,7 +811,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
type(*var->value())->category() != Type::Category::RationalNumber
|
||||
))
|
||||
{
|
||||
m_errorReporter.typeError(7615_error, _identifier.debugData->location, "Only direct number constants and references to such constants are supported by inline assembly.");
|
||||
m_errorReporter.typeError(7615_error, nativeLocationOf(_identifier), "Only direct number constants and references to such constants are supported by inline assembly.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -810,24 +821,24 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
if (!identifierInfo.suffix.empty())
|
||||
{
|
||||
string const& suffix = identifierInfo.suffix;
|
||||
solAssert((set<string>{"offset", "slot", "length"}).count(suffix), "");
|
||||
if (var->isStateVariable() || var->type()->dataStoredIn(DataLocation::Storage))
|
||||
solAssert((set<string>{"offset", "slot", "length", "selector", "address"}).count(suffix), "");
|
||||
if (!var->isConstant() && (var->isStateVariable() || var->type()->dataStoredIn(DataLocation::Storage)))
|
||||
{
|
||||
if (suffix != "slot" && suffix != "offset")
|
||||
{
|
||||
m_errorReporter.typeError(4656_error, _identifier.debugData->location, "State variables only support \".slot\" and \".offset\".");
|
||||
m_errorReporter.typeError(4656_error, nativeLocationOf(_identifier), "State variables only support \".slot\" and \".offset\".");
|
||||
return false;
|
||||
}
|
||||
else if (_context == yul::IdentifierContext::LValue)
|
||||
{
|
||||
if (var->isStateVariable())
|
||||
{
|
||||
m_errorReporter.typeError(4713_error, _identifier.debugData->location, "State variables cannot be assigned to - you have to use \"sstore()\".");
|
||||
m_errorReporter.typeError(4713_error, nativeLocationOf(_identifier), "State variables cannot be assigned to - you have to use \"sstore()\".");
|
||||
return false;
|
||||
}
|
||||
else if (suffix != "slot")
|
||||
{
|
||||
m_errorReporter.typeError(9739_error, _identifier.debugData->location, "Only .slot can be assigned to.");
|
||||
m_errorReporter.typeError(9739_error, nativeLocationOf(_identifier), "Only .slot can be assigned to.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -839,13 +850,26 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
{
|
||||
if (suffix != "offset" && suffix != "length")
|
||||
{
|
||||
m_errorReporter.typeError(1536_error, _identifier.debugData->location, "Calldata variables only support \".offset\" and \".length\".");
|
||||
m_errorReporter.typeError(1536_error, nativeLocationOf(_identifier), "Calldata variables only support \".offset\" and \".length\".");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (auto const* fpType = dynamic_cast<FunctionTypePointer>(var->type()))
|
||||
{
|
||||
if (suffix != "selector" && suffix != "address")
|
||||
{
|
||||
m_errorReporter.typeError(9272_error, nativeLocationOf(_identifier), "Variables of type function pointer only support \".selector\" and \".address\".");
|
||||
return false;
|
||||
}
|
||||
if (fpType->kind() != FunctionType::Kind::External)
|
||||
{
|
||||
m_errorReporter.typeError(8533_error, nativeLocationOf(_identifier), "Only Variables of type external function pointer support \".selector\" and \".address\".");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_errorReporter.typeError(3622_error, _identifier.debugData->location, "The suffix \"." + suffix + "\" is not supported by this variable or type.");
|
||||
m_errorReporter.typeError(3622_error, nativeLocationOf(_identifier), "The suffix \"." + suffix + "\" is not supported by this variable or type.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -853,14 +877,14 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
{
|
||||
m_errorReporter.typeError(
|
||||
1408_error,
|
||||
_identifier.debugData->location,
|
||||
nativeLocationOf(_identifier),
|
||||
"Only local variables are supported. To access storage variables, use the \".slot\" and \".offset\" suffixes."
|
||||
);
|
||||
return false;
|
||||
}
|
||||
else if (var->type()->dataStoredIn(DataLocation::Storage))
|
||||
{
|
||||
m_errorReporter.typeError(9068_error, _identifier.debugData->location, "You have to use the \".slot\" or \".offset\" suffix to access storage reference variables.");
|
||||
m_errorReporter.typeError(9068_error, nativeLocationOf(_identifier), "You have to use the \".slot\" or \".offset\" suffix to access storage reference variables.");
|
||||
return false;
|
||||
}
|
||||
else if (var->type()->sizeOnStack() != 1)
|
||||
@@ -869,18 +893,18 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
auto const* arrayType = dynamic_cast<ArrayType const*>(var->type());
|
||||
arrayType && arrayType->isDynamicallySized() && arrayType->dataStoredIn(DataLocation::CallData)
|
||||
)
|
||||
m_errorReporter.typeError(1397_error, _identifier.debugData->location, "Call data elements cannot be accessed directly. Use \".offset\" and \".length\" to access the calldata offset and length of this array and then use \"calldatacopy\".");
|
||||
m_errorReporter.typeError(1397_error, nativeLocationOf(_identifier), "Call data elements cannot be accessed directly. Use \".offset\" and \".length\" to access the calldata offset and length of this array and then use \"calldatacopy\".");
|
||||
else
|
||||
{
|
||||
solAssert(!var->type()->dataStoredIn(DataLocation::CallData), "");
|
||||
m_errorReporter.typeError(9857_error, _identifier.debugData->location, "Only types that use one stack slot are supported.");
|
||||
m_errorReporter.typeError(9857_error, nativeLocationOf(_identifier), "Only types that use one stack slot are supported.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!identifierInfo.suffix.empty())
|
||||
{
|
||||
m_errorReporter.typeError(7944_error, _identifier.debugData->location, "The suffixes \".offset\", \".slot\" and \".length\" can only be used with variables.");
|
||||
m_errorReporter.typeError(7944_error, nativeLocationOf(_identifier), "The suffixes \".offset\", \".slot\" and \".length\" can only be used with variables.");
|
||||
return false;
|
||||
}
|
||||
else if (_context == yul::IdentifierContext::LValue)
|
||||
@@ -888,7 +912,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
if (dynamic_cast<MagicVariableDeclaration const*>(declaration))
|
||||
return false;
|
||||
|
||||
m_errorReporter.typeError(1990_error, _identifier.debugData->location, "Only local variables can be assigned to in inline assembly.");
|
||||
m_errorReporter.typeError(1990_error, nativeLocationOf(_identifier), "Only local variables can be assigned to in inline assembly.");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -897,7 +921,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
solAssert(!!declaration->type(), "Type of declaration required but not yet determined.");
|
||||
if (dynamic_cast<FunctionDefinition const*>(declaration))
|
||||
{
|
||||
m_errorReporter.declarationError(2025_error, _identifier.debugData->location, "Access to functions is not allowed in inline assembly.");
|
||||
m_errorReporter.declarationError(2025_error, nativeLocationOf(_identifier), "Access to functions is not allowed in inline assembly.");
|
||||
return false;
|
||||
}
|
||||
else if (dynamic_cast<VariableDeclaration const*>(declaration))
|
||||
@@ -907,7 +931,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
{
|
||||
if (!contract->isLibrary())
|
||||
{
|
||||
m_errorReporter.typeError(4977_error, _identifier.debugData->location, "Expected a library.");
|
||||
m_errorReporter.typeError(4977_error, nativeLocationOf(_identifier), "Expected a library.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -2470,6 +2494,13 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
|
||||
returnTypes = functionType->returnParameterTypes();
|
||||
break;
|
||||
}
|
||||
case FunctionType::Kind::Wrap:
|
||||
case FunctionType::Kind::Unwrap:
|
||||
{
|
||||
typeCheckFunctionGeneralChecks(_functionCall, functionType);
|
||||
returnTypes = functionType->returnParameterTypes();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
typeCheckFunctionCall(_functionCall, functionType);
|
||||
@@ -2907,7 +2938,10 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
||||
// 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))
|
||||
if (tt->actualType()->category() == Type::Category::Enum)
|
||||
if (
|
||||
tt->actualType()->category() == Type::Category::Enum ||
|
||||
tt->actualType()->category() == Type::Category::UserDefinedValueType
|
||||
)
|
||||
annotation.isPure = true;
|
||||
if (
|
||||
auto const* functionType = dynamic_cast<FunctionType const*>(exprType);
|
||||
|
||||
@@ -69,7 +69,7 @@ public:
|
||||
if (yul::EVMDialect const* dialect = dynamic_cast<decltype(dialect)>(&m_dialect))
|
||||
if (yul::BuiltinFunctionForEVM const* fun = dialect->builtin(_funCall.functionName.name))
|
||||
if (fun->instruction)
|
||||
checkInstruction(_funCall.debugData->location, *fun->instruction);
|
||||
checkInstruction(nativeLocationOf(_funCall), *fun->instruction);
|
||||
|
||||
for (auto const& arg: _funCall.arguments)
|
||||
std::visit(*this, arg);
|
||||
|
||||
Reference in New Issue
Block a user