Type inference draft.

This commit is contained in:
Daniel Kirchner
2023-09-13 22:54:02 +02:00
committed by Nikola Matic
parent 093ec110cf
commit d8a36a1d58
51 changed files with 5169 additions and 313 deletions
+4 -2
View File
@@ -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())
+4 -1
View File
@@ -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;
};
/**
+85 -8
View File
@@ -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)
+4 -2
View File
@@ -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;
};
}
+13 -1
View File
@@ -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);
}
+2
View File
@@ -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;
};
}