mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Type inference draft.
This commit is contained in:
committed by
Nikola Matic
parent
093ec110cf
commit
d8a36a1d58
@@ -38,11 +38,13 @@ namespace solidity::frontend
|
||||
NameAndTypeResolver::NameAndTypeResolver(
|
||||
GlobalContext& _globalContext,
|
||||
langutil::EVMVersion _evmVersion,
|
||||
ErrorReporter& _errorReporter
|
||||
ErrorReporter& _errorReporter,
|
||||
bool _experimentalSolidity
|
||||
):
|
||||
m_evmVersion(_evmVersion),
|
||||
m_errorReporter(_errorReporter),
|
||||
m_globalContext(_globalContext)
|
||||
m_globalContext(_globalContext),
|
||||
m_experimentalSolidity(_experimentalSolidity)
|
||||
{
|
||||
m_scopes[nullptr] = std::make_shared<DeclarationContainer>();
|
||||
for (Declaration const* declaration: _globalContext.declarations())
|
||||
|
||||
@@ -59,7 +59,8 @@ public:
|
||||
NameAndTypeResolver(
|
||||
GlobalContext& _globalContext,
|
||||
langutil::EVMVersion _evmVersion,
|
||||
langutil::ErrorReporter& _errorReporter
|
||||
langutil::ErrorReporter& _errorReporter,
|
||||
bool _experimentalSolidity
|
||||
);
|
||||
/// Registers all declarations found in the AST node, usually a source unit.
|
||||
/// @returns false in case of error.
|
||||
@@ -107,6 +108,7 @@ public:
|
||||
/// Sets the current scope.
|
||||
void setScope(ASTNode const* _node);
|
||||
|
||||
bool experimentalSolidity() const { return m_experimentalSolidity; }
|
||||
private:
|
||||
/// Internal version of @a resolveNamesAndTypes (called from there) throws exceptions on fatal errors.
|
||||
bool resolveNamesAndTypesInternal(ASTNode& _node, bool _resolveInsideCode = true);
|
||||
@@ -132,6 +134,7 @@ private:
|
||||
DeclarationContainer* m_currentScope = nullptr;
|
||||
langutil::ErrorReporter& m_errorReporter;
|
||||
GlobalContext& m_globalContext;
|
||||
bool m_experimentalSolidity = false;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -112,6 +112,21 @@ bool ReferencesResolver::visit(VariableDeclaration const& _varDecl)
|
||||
if (_varDecl.documentation())
|
||||
resolveInheritDoc(*_varDecl.documentation(), _varDecl.annotation());
|
||||
|
||||
if (m_resolver.experimentalSolidity())
|
||||
{
|
||||
solAssert(!_varDecl.hasTypeName());
|
||||
if (_varDecl.typeExpression())
|
||||
{
|
||||
ScopedSaveAndRestore typeContext{m_typeContext, true};
|
||||
_varDecl.typeExpression()->accept(*this);
|
||||
}
|
||||
if (_varDecl.overrides())
|
||||
_varDecl.overrides()->accept(*this);
|
||||
if (_varDecl.value())
|
||||
_varDecl.value()->accept(*this);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -120,6 +135,8 @@ bool ReferencesResolver::visit(Identifier const& _identifier)
|
||||
auto declarations = m_resolver.nameFromCurrentScope(_identifier.name());
|
||||
if (declarations.empty())
|
||||
{
|
||||
if (m_resolver.experimentalSolidity() && m_typeContext)
|
||||
return false;
|
||||
std::string suggestions = m_resolver.similarNameSuggestions(_identifier.name());
|
||||
std::string errorMessage = "Undeclared identifier.";
|
||||
if (!suggestions.empty())
|
||||
@@ -140,7 +157,7 @@ bool ReferencesResolver::visit(Identifier const& _identifier)
|
||||
|
||||
bool ReferencesResolver::visit(FunctionDefinition const& _functionDefinition)
|
||||
{
|
||||
m_returnParameters.push_back(_functionDefinition.returnParameterList().get());
|
||||
m_functionDefinitions.push_back(&_functionDefinition);
|
||||
|
||||
if (_functionDefinition.documentation())
|
||||
resolveInheritDoc(*_functionDefinition.documentation(), _functionDefinition.annotation());
|
||||
@@ -150,13 +167,13 @@ bool ReferencesResolver::visit(FunctionDefinition const& _functionDefinition)
|
||||
|
||||
void ReferencesResolver::endVisit(FunctionDefinition const&)
|
||||
{
|
||||
solAssert(!m_returnParameters.empty(), "");
|
||||
m_returnParameters.pop_back();
|
||||
solAssert(!m_functionDefinitions.empty(), "");
|
||||
m_functionDefinitions.pop_back();
|
||||
}
|
||||
|
||||
bool ReferencesResolver::visit(ModifierDefinition const& _modifierDefinition)
|
||||
{
|
||||
m_returnParameters.push_back(nullptr);
|
||||
m_functionDefinitions.push_back(nullptr);
|
||||
|
||||
if (_modifierDefinition.documentation())
|
||||
resolveInheritDoc(*_modifierDefinition.documentation(), _modifierDefinition.annotation());
|
||||
@@ -166,8 +183,8 @@ bool ReferencesResolver::visit(ModifierDefinition const& _modifierDefinition)
|
||||
|
||||
void ReferencesResolver::endVisit(ModifierDefinition const&)
|
||||
{
|
||||
solAssert(!m_returnParameters.empty(), "");
|
||||
m_returnParameters.pop_back();
|
||||
solAssert(!m_functionDefinitions.empty(), "");
|
||||
m_functionDefinitions.pop_back();
|
||||
}
|
||||
|
||||
void ReferencesResolver::endVisit(IdentifierPath const& _path)
|
||||
@@ -227,11 +244,30 @@ bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly)
|
||||
|
||||
bool ReferencesResolver::visit(Return const& _return)
|
||||
{
|
||||
solAssert(!m_returnParameters.empty(), "");
|
||||
_return.annotation().functionReturnParameters = m_returnParameters.back();
|
||||
solAssert(!m_functionDefinitions.empty(), "");
|
||||
_return.annotation().function = m_functionDefinitions.back();
|
||||
_return.annotation().functionReturnParameters = m_functionDefinitions.back() ? m_functionDefinitions.back()->returnParameterList().get() : nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReferencesResolver::visit(BinaryOperation const& _binaryOperation)
|
||||
{
|
||||
if (m_resolver.experimentalSolidity())
|
||||
{
|
||||
_binaryOperation.leftExpression().accept(*this);
|
||||
if (_binaryOperation.getOperator() == Token::Colon)
|
||||
{
|
||||
ScopedSaveAndRestore typeContext(m_typeContext, !m_typeContext);
|
||||
_binaryOperation.rightExpression().accept(*this);
|
||||
}
|
||||
else
|
||||
_binaryOperation.rightExpression().accept(*this);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return ASTConstVisitor::visit(_binaryOperation);
|
||||
}
|
||||
|
||||
void ReferencesResolver::operator()(yul::FunctionDefinition const& _function)
|
||||
{
|
||||
solAssert(nativeLocationOf(_function) == originLocationOf(_function), "");
|
||||
@@ -252,6 +288,47 @@ void ReferencesResolver::operator()(yul::Identifier const& _identifier)
|
||||
{
|
||||
solAssert(nativeLocationOf(_identifier) == originLocationOf(_identifier), "");
|
||||
|
||||
if (m_resolver.experimentalSolidity())
|
||||
{
|
||||
std::vector<std::string> splitName;
|
||||
boost::split(splitName, _identifier.name.str(), boost::is_any_of("."));
|
||||
solAssert(!splitName.empty());
|
||||
if (splitName.size() > 2)
|
||||
{
|
||||
m_errorReporter.declarationError(
|
||||
0000_error,
|
||||
nativeLocationOf(_identifier),
|
||||
"Unsupported identifier in inline assembly."
|
||||
);
|
||||
return;
|
||||
}
|
||||
std::string name = splitName.front();
|
||||
auto declarations = m_resolver.nameFromCurrentScope(name);
|
||||
switch(declarations.size())
|
||||
{
|
||||
case 0:
|
||||
if (splitName.size() > 1)
|
||||
m_errorReporter.declarationError(
|
||||
0000_error,
|
||||
nativeLocationOf(_identifier),
|
||||
"Unsupported identifier in inline assembly."
|
||||
);
|
||||
break;
|
||||
case 1:
|
||||
m_yulAnnotation->externalReferences[&_identifier].declaration = declarations.front();
|
||||
m_yulAnnotation->externalReferences[&_identifier].suffix = splitName.size() > 1 ? splitName.back() : "";
|
||||
break;
|
||||
default:
|
||||
m_errorReporter.declarationError(
|
||||
0000_error,
|
||||
nativeLocationOf(_identifier),
|
||||
"Multiple matching identifiers. Resolving overloaded identifiers is not supported."
|
||||
);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static std::set<std::string> suffixes{"slot", "offset", "length", "address", "selector"};
|
||||
std::string suffix;
|
||||
for (std::string const& s: suffixes)
|
||||
|
||||
@@ -85,6 +85,7 @@ private:
|
||||
bool visit(InlineAssembly const& _inlineAssembly) override;
|
||||
bool visit(Return const& _return) override;
|
||||
bool visit(UsingForDirective const& _usingFor) override;
|
||||
bool visit(BinaryOperation const& _binaryOperation) override;
|
||||
|
||||
void operator()(yul::FunctionDefinition const& _function) override;
|
||||
void operator()(yul::Identifier const& _identifier) override;
|
||||
@@ -98,12 +99,13 @@ private:
|
||||
langutil::ErrorReporter& m_errorReporter;
|
||||
NameAndTypeResolver& m_resolver;
|
||||
langutil::EVMVersion m_evmVersion;
|
||||
/// Stack of return parameters.
|
||||
std::vector<ParameterList const*> m_returnParameters;
|
||||
/// Stack of function definitions.
|
||||
std::vector<FunctionDefinition const*> m_functionDefinitions;
|
||||
bool const m_resolveInsideCode;
|
||||
|
||||
InlineAssemblyAnnotation* m_yulAnnotation = nullptr;
|
||||
bool m_yulInsideFunction = false;
|
||||
bool m_typeContext = false;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -443,7 +443,9 @@ bool SyntaxChecker::visit(UsingForDirective const& _usingFor)
|
||||
|
||||
bool SyntaxChecker::visit(FunctionDefinition const& _function)
|
||||
{
|
||||
solAssert(_function.isFree() == (m_currentContractKind == std::nullopt), "");
|
||||
if (m_sourceUnit && m_sourceUnit->experimentalSolidity())
|
||||
// Handled in experimental::SyntaxRestrictor instead.
|
||||
return true;
|
||||
|
||||
if (!_function.isFree() && !_function.isConstructor() && _function.noVisibilitySpecified())
|
||||
{
|
||||
@@ -498,3 +500,13 @@ bool SyntaxChecker::visit(StructDefinition const& _struct)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SyntaxChecker::visitNode(ASTNode const& _node)
|
||||
{
|
||||
if (_node.experimentalSolidityOnly())
|
||||
{
|
||||
solAssert(m_sourceUnit);
|
||||
solAssert(m_sourceUnit->experimentalSolidity());
|
||||
}
|
||||
return ASTConstVisitor::visitNode(_node);
|
||||
}
|
||||
|
||||
@@ -97,6 +97,8 @@ private:
|
||||
bool visit(StructDefinition const& _struct) override;
|
||||
bool visit(Literal const& _literal) override;
|
||||
|
||||
bool visitNode(ASTNode const&) override;
|
||||
|
||||
langutil::ErrorReporter& m_errorReporter;
|
||||
|
||||
bool m_useYulOptimizer = false;
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
#include <libsolidity/analysis/experimental/Analysis.h>
|
||||
|
||||
using namespace solidity::langutil;
|
||||
using namespace solidity::frontend::experimental;
|
||||
|
||||
bool Analysis::check(ASTNode const&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
#pragma once
|
||||
|
||||
namespace solidity::frontend
|
||||
{
|
||||
class ASTNode;
|
||||
}
|
||||
|
||||
namespace solidity::langutil
|
||||
{
|
||||
class ErrorReporter;
|
||||
}
|
||||
|
||||
namespace solidity::frontend::experimental
|
||||
{
|
||||
|
||||
class Analysis
|
||||
{
|
||||
public:
|
||||
Analysis(langutil::ErrorReporter& _errorReporter): m_errorReporter(_errorReporter)
|
||||
{}
|
||||
bool check(ASTNode const& _ast);
|
||||
private:
|
||||
langutil::ErrorReporter& m_errorReporter;
|
||||
};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user