mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
tmp
This commit is contained in:
parent
14a34ae088
commit
315270f3bb
@ -50,6 +50,8 @@ set(sources
|
|||||||
analysis/experimental/Analysis.h
|
analysis/experimental/Analysis.h
|
||||||
analysis/experimental/TypeInference.cpp
|
analysis/experimental/TypeInference.cpp
|
||||||
analysis/experimental/TypeInference.h
|
analysis/experimental/TypeInference.h
|
||||||
|
analysis/experimental/TypeRegistration.cpp
|
||||||
|
analysis/experimental/TypeRegistration.h
|
||||||
analysis/experimental/SyntaxRestrictor.cpp
|
analysis/experimental/SyntaxRestrictor.cpp
|
||||||
analysis/experimental/SyntaxRestrictor.h
|
analysis/experimental/SyntaxRestrictor.h
|
||||||
ast/AST.cpp
|
ast/AST.cpp
|
||||||
|
@ -19,26 +19,87 @@
|
|||||||
|
|
||||||
#include <libsolidity/analysis/experimental/SyntaxRestrictor.h>
|
#include <libsolidity/analysis/experimental/SyntaxRestrictor.h>
|
||||||
#include <libsolidity/analysis/experimental/TypeInference.h>
|
#include <libsolidity/analysis/experimental/TypeInference.h>
|
||||||
|
#include <libsolidity/analysis/experimental/TypeRegistration.h>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace solidity::langutil;
|
using namespace solidity::langutil;
|
||||||
using namespace solidity::frontend::experimental;
|
using namespace solidity::frontend::experimental;
|
||||||
|
|
||||||
|
// TODO: creating all of them for all nodes up front may be wasteful, we should improve the mechanism.
|
||||||
|
struct Analysis::AnnotationContainer
|
||||||
|
{
|
||||||
|
TypeRegistration::Annotation typeRegistrationAnnotation;
|
||||||
|
TypeInference::Annotation typeInferenceAnnotation;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
TypeRegistration::Annotation& solidity::frontend::experimental::detail::AnnotationFetcher<TypeRegistration>::get(ASTNode const& _node)
|
||||||
|
{
|
||||||
|
return analysis.annotationContainer(_node).typeRegistrationAnnotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
TypeInference::Annotation& solidity::frontend::experimental::detail::AnnotationFetcher<TypeInference>::get(ASTNode const& _node)
|
||||||
|
{
|
||||||
|
return analysis.annotationContainer(_node).typeInferenceAnnotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
Analysis::AnnotationContainer& Analysis::annotationContainer(ASTNode const& _node)
|
||||||
|
{
|
||||||
|
solAssert(_node.id() > 0);
|
||||||
|
size_t id = static_cast<size_t>(_node.id());
|
||||||
|
solAssert(id < m_maxAstId);
|
||||||
|
return m_annotations[id];
|
||||||
|
}
|
||||||
|
|
||||||
Analysis::Analysis(langutil::ErrorReporter& _errorReporter, uint64_t _maxAstId):
|
Analysis::Analysis(langutil::ErrorReporter& _errorReporter, uint64_t _maxAstId):
|
||||||
m_errorReporter(_errorReporter),
|
m_errorReporter(_errorReporter),
|
||||||
m_maxAstId(_maxAstId)
|
m_maxAstId(_maxAstId),
|
||||||
|
m_annotations(std::make_unique<AnnotationContainer[]>(static_cast<size_t>(_maxAstId)))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Analysis::~Analysis()
|
||||||
|
{}
|
||||||
|
|
||||||
|
template<size_t... Is>
|
||||||
|
std::tuple<std::integral_constant<size_t, Is>...> makeIndexTuple(std::index_sequence<Is...>) {
|
||||||
|
return std::make_tuple( std::integral_constant<size_t, Is>{}...);
|
||||||
|
}
|
||||||
|
|
||||||
bool Analysis::check(vector<shared_ptr<SourceUnit const>> const& _sourceUnits)
|
bool Analysis::check(vector<shared_ptr<SourceUnit const>> const& _sourceUnits)
|
||||||
{
|
{
|
||||||
SyntaxRestrictor syntaxRestrictor{m_errorReporter};
|
using AnalysisSteps = std::tuple<SyntaxRestrictor, TypeRegistration, TypeInference>;
|
||||||
|
|
||||||
|
return std::apply([&](auto... _indexTuple) {
|
||||||
|
return ([&](auto&& _step) {
|
||||||
for (auto source: _sourceUnits)
|
for (auto source: _sourceUnits)
|
||||||
if (!syntaxRestrictor.check(*source))
|
if (!_step.analyze(*source))
|
||||||
return false;
|
return false;
|
||||||
|
return true;
|
||||||
|
}(std::tuple_element_t<decltype(_indexTuple)::value, AnalysisSteps>{*this}) && ...);
|
||||||
|
}, makeIndexTuple(std::make_index_sequence<std::tuple_size_v<AnalysisSteps>>{}));
|
||||||
|
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
SyntaxRestrictor syntaxRestrictor{*this};
|
||||||
|
for (auto source: _sourceUnits)
|
||||||
|
if (!syntaxRestrictor.analyze(*source))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
TypeRegistration typeRegistration{*this};
|
||||||
|
for (auto source: _sourceUnits)
|
||||||
|
if (!typeRegistration.analyze(*source))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
{
|
||||||
TypeInference typeInference{*this};
|
TypeInference typeInference{*this};
|
||||||
for (auto source: _sourceUnits)
|
for (auto source: _sourceUnits)
|
||||||
if (!typeInference.analyze(*source))
|
if (!typeInference.analyze(*source))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
}
|
||||||
|
return true;
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <libsolidity/ast/experimental/TypeSystem.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -24,6 +26,7 @@
|
|||||||
namespace solidity::frontend
|
namespace solidity::frontend
|
||||||
{
|
{
|
||||||
class SourceUnit;
|
class SourceUnit;
|
||||||
|
class ASTNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace solidity::langutil
|
namespace solidity::langutil
|
||||||
@ -33,19 +36,43 @@ class ErrorReporter;
|
|||||||
|
|
||||||
namespace solidity::frontend::experimental
|
namespace solidity::frontend::experimental
|
||||||
{
|
{
|
||||||
|
class TypeSystem;
|
||||||
|
|
||||||
|
class Analysis;
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
template<typename Step>
|
||||||
|
struct AnnotationFetcher
|
||||||
|
{
|
||||||
|
Analysis& analysis;
|
||||||
|
typename Step::Annotation& get(ASTNode const& _node);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
class Analysis
|
class Analysis
|
||||||
{
|
{
|
||||||
|
struct AnnotationContainer;
|
||||||
public:
|
public:
|
||||||
Analysis(langutil::ErrorReporter& _errorReporter, uint64_t _maxAstId);
|
Analysis(langutil::ErrorReporter& _errorReporter, uint64_t _maxAstId);
|
||||||
Analysis(Analysis const&) = delete;
|
Analysis(Analysis const&) = delete;
|
||||||
|
~Analysis();
|
||||||
Analysis const& operator=(Analysis const&) = delete;
|
Analysis const& operator=(Analysis const&) = delete;
|
||||||
bool check(std::vector<std::shared_ptr<SourceUnit const>> const& _sourceUnits);
|
bool check(std::vector<std::shared_ptr<SourceUnit const>> const& _sourceUnits);
|
||||||
langutil::ErrorReporter& errorReporter() { return m_errorReporter; }
|
langutil::ErrorReporter& errorReporter() { return m_errorReporter; }
|
||||||
uint64_t maxAstId() const { return m_maxAstId; }
|
uint64_t maxAstId() const { return m_maxAstId; }
|
||||||
|
TypeSystem& typeSystem() { return m_typeSystem; }
|
||||||
|
template<typename Step>
|
||||||
|
typename Step::Annotation& annotation(ASTNode const& _node)
|
||||||
|
{
|
||||||
|
return detail::AnnotationFetcher<Step>{*this}.get(_node);
|
||||||
|
}
|
||||||
|
AnnotationContainer& annotationContainer(ASTNode const& _node);
|
||||||
private:
|
private:
|
||||||
langutil::ErrorReporter& m_errorReporter;
|
langutil::ErrorReporter& m_errorReporter;
|
||||||
|
TypeSystem m_typeSystem;
|
||||||
uint64_t m_maxAstId = 0;
|
uint64_t m_maxAstId = 0;
|
||||||
|
std::unique_ptr<AnnotationContainer[]> m_annotations;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -18,13 +18,18 @@
|
|||||||
|
|
||||||
#include <libsolidity/analysis/experimental/SyntaxRestrictor.h>
|
#include <libsolidity/analysis/experimental/SyntaxRestrictor.h>
|
||||||
|
|
||||||
|
#include <libsolidity/analysis/experimental/Analysis.h>
|
||||||
|
|
||||||
#include <liblangutil/Exceptions.h>
|
#include <liblangutil/Exceptions.h>
|
||||||
|
|
||||||
using namespace solidity::frontend;
|
using namespace solidity::frontend;
|
||||||
using namespace solidity::frontend::experimental;
|
using namespace solidity::frontend::experimental;
|
||||||
using namespace solidity::langutil;
|
using namespace solidity::langutil;
|
||||||
|
|
||||||
bool SyntaxRestrictor::check(ASTNode const& _astRoot)
|
SyntaxRestrictor::SyntaxRestrictor(Analysis& _analysis): m_errorReporter(_analysis.errorReporter())
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool SyntaxRestrictor::analyze(ASTNode const& _astRoot)
|
||||||
{
|
{
|
||||||
_astRoot.accept(*this);
|
_astRoot.accept(*this);
|
||||||
return !Error::containsErrors(m_errorReporter.errors());
|
return !Error::containsErrors(m_errorReporter.errors());
|
||||||
|
@ -24,14 +24,14 @@
|
|||||||
|
|
||||||
namespace solidity::frontend::experimental
|
namespace solidity::frontend::experimental
|
||||||
{
|
{
|
||||||
|
class Analysis;
|
||||||
|
|
||||||
class SyntaxRestrictor: public ASTConstVisitor
|
class SyntaxRestrictor: public ASTConstVisitor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// @param _errorReporter provides the error logging functionality.
|
SyntaxRestrictor(Analysis& _analysis);
|
||||||
explicit SyntaxRestrictor(langutil::ErrorReporter& _errorReporter): m_errorReporter(_errorReporter) {}
|
|
||||||
|
|
||||||
bool check(ASTNode const& _astRoot);
|
bool analyze(ASTNode const& _astRoot);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Default visit will reject all AST nodes that are not explicitly allowed.
|
/// Default visit will reject all AST nodes that are not explicitly allowed.
|
||||||
|
@ -34,22 +34,12 @@ using namespace solidity::langutil;
|
|||||||
|
|
||||||
TypeInference::TypeInference(Analysis& _analysis):
|
TypeInference::TypeInference(Analysis& _analysis):
|
||||||
m_analysis(_analysis),
|
m_analysis(_analysis),
|
||||||
m_errorReporter(_analysis.errorReporter())
|
m_errorReporter(_analysis.errorReporter()),
|
||||||
|
m_typeSystem(_analysis.typeSystem())
|
||||||
{
|
{
|
||||||
for (auto [type, name, arity]: std::initializer_list<std::tuple<BuiltinType, const char*, uint64_t>> {
|
|
||||||
{BuiltinType::Void, "void", 0},
|
|
||||||
{BuiltinType::Function, "fun", 2},
|
|
||||||
{BuiltinType::Unit, "unit", 0},
|
|
||||||
{BuiltinType::Pair, "pair", 2},
|
|
||||||
{BuiltinType::Word, "word", 0},
|
|
||||||
{BuiltinType::Integer, "integer", 0}
|
|
||||||
})
|
|
||||||
m_typeSystem.declareBuiltinType(type, name, arity);
|
|
||||||
m_voidType = m_typeSystem.builtinType(BuiltinType::Void, {});
|
m_voidType = m_typeSystem.builtinType(BuiltinType::Void, {});
|
||||||
m_wordType = m_typeSystem.builtinType(BuiltinType::Word, {});
|
m_wordType = m_typeSystem.builtinType(BuiltinType::Word, {});
|
||||||
m_integerType = m_typeSystem.builtinType(BuiltinType::Integer, {});
|
m_integerType = m_typeSystem.builtinType(BuiltinType::Integer, {});
|
||||||
|
|
||||||
m_typeAnnotations.resize(_analysis.maxAstId());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TypeInference::analyze(SourceUnit const& _sourceUnit)
|
bool TypeInference::analyze(SourceUnit const& _sourceUnit)
|
||||||
@ -72,7 +62,7 @@ bool TypeInference::visit(FunctionDefinition const& _functionDefinition)
|
|||||||
auto typeFromParameterList = [&](ParameterList const* _list) {
|
auto typeFromParameterList = [&](ParameterList const* _list) {
|
||||||
if (!_list)
|
if (!_list)
|
||||||
return m_typeSystem.builtinType(BuiltinType::Unit, {});
|
return m_typeSystem.builtinType(BuiltinType::Unit, {});
|
||||||
return TypeSystemHelpers{m_typeSystem}.tupleType(_list->parameters() | ranges::view::transform([&](auto _param) {
|
return TypeSystemHelpers{m_typeSystem}.tupleType(_list->parameters() | ranges::views::transform([&](auto _param) {
|
||||||
auto& argAnnotation = annotation(*_param);
|
auto& argAnnotation = annotation(*_param);
|
||||||
solAssert(argAnnotation.type);
|
solAssert(argAnnotation.type);
|
||||||
return *argAnnotation.type;
|
return *argAnnotation.type;
|
||||||
@ -173,7 +163,6 @@ experimental::Type TypeInference::fromTypeName(TypeName const& _typeName)
|
|||||||
else
|
else
|
||||||
m_errorReporter.typeError(0000_error, _typeName.location(), "Unsupported type name.");
|
m_errorReporter.typeError(0000_error, _typeName.location(), "Unsupported type name.");
|
||||||
return m_typeSystem.freshTypeVariable(false);
|
return m_typeSystem.freshTypeVariable(false);
|
||||||
|
|
||||||
}
|
}
|
||||||
void TypeInference::unify(Type _a, Type _b)
|
void TypeInference::unify(Type _a, Type _b)
|
||||||
{
|
{
|
||||||
@ -256,12 +245,9 @@ void TypeInference::endVisit(Assignment const& _assignment)
|
|||||||
assignmentAnnotation.type = m_typeSystem.resolve(*lhsAnnotation.type);
|
assignmentAnnotation.type = m_typeSystem.resolve(*lhsAnnotation.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeInference::TypeAnnotation& TypeInference::annotation(ASTNode const& _node)
|
TypeInference::Annotation& TypeInference::annotation(ASTNode const& _node)
|
||||||
{
|
{
|
||||||
auto& annotation = m_typeAnnotations.at(static_cast<size_t>(_node.id()));
|
return m_analysis.annotation<TypeInference>(_node);
|
||||||
if (!annotation)
|
|
||||||
annotation = make_unique<TypeAnnotation>();
|
|
||||||
return *annotation;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TypeInference::visit(Identifier const& _identifier)
|
bool TypeInference::visit(Identifier const& _identifier)
|
||||||
|
@ -22,8 +22,6 @@
|
|||||||
|
|
||||||
#include <liblangutil/ErrorReporter.h>
|
#include <liblangutil/ErrorReporter.h>
|
||||||
|
|
||||||
#include <range/v3/span.hpp>
|
|
||||||
|
|
||||||
namespace solidity::frontend::experimental
|
namespace solidity::frontend::experimental
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -35,6 +33,12 @@ public:
|
|||||||
TypeInference(Analysis& _analysis);
|
TypeInference(Analysis& _analysis);
|
||||||
|
|
||||||
bool analyze(SourceUnit const& _sourceUnit);
|
bool analyze(SourceUnit const& _sourceUnit);
|
||||||
|
|
||||||
|
|
||||||
|
struct Annotation
|
||||||
|
{
|
||||||
|
std::optional<Type> type;
|
||||||
|
};
|
||||||
private:
|
private:
|
||||||
bool visit(Block const&) override { return true; }
|
bool visit(Block const&) override { return true; }
|
||||||
bool visit(VariableDeclarationStatement const&) override { return true; }
|
bool visit(VariableDeclarationStatement const&) override { return true; }
|
||||||
@ -67,22 +71,15 @@ private:
|
|||||||
Type fromTypeName(TypeName const& _typeName);
|
Type fromTypeName(TypeName const& _typeName);
|
||||||
Analysis& m_analysis;
|
Analysis& m_analysis;
|
||||||
langutil::ErrorReporter& m_errorReporter;
|
langutil::ErrorReporter& m_errorReporter;
|
||||||
TypeSystem m_typeSystem;
|
TypeSystem& m_typeSystem;
|
||||||
Type m_voidType;
|
Type m_voidType;
|
||||||
Type m_wordType;
|
Type m_wordType;
|
||||||
Type m_integerType;
|
Type m_integerType;
|
||||||
std::optional<Type> m_currentFunctionType;
|
std::optional<Type> m_currentFunctionType;
|
||||||
|
|
||||||
struct TypeAnnotation
|
Annotation& annotation(ASTNode const& _node);
|
||||||
{
|
|
||||||
std::optional<Type> type;
|
|
||||||
};
|
|
||||||
|
|
||||||
TypeAnnotation& annotation(ASTNode const& _node);
|
|
||||||
|
|
||||||
void unify(Type _a, Type _b);
|
void unify(Type _a, Type _b);
|
||||||
|
|
||||||
std::vector<std::unique_ptr<TypeAnnotation>> m_typeAnnotations;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
102
libsolidity/analysis/experimental/TypeRegistration.cpp
Normal file
102
libsolidity/analysis/experimental/TypeRegistration.cpp
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
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/TypeRegistration.h>
|
||||||
|
#include <libsolidity/analysis/experimental/Analysis.h>
|
||||||
|
#include <liblangutil/Exceptions.h>
|
||||||
|
|
||||||
|
#include <libyul/AsmAnalysis.h>
|
||||||
|
#include <libyul/AsmAnalysisInfo.h>
|
||||||
|
#include <libyul/AST.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace solidity::frontend;
|
||||||
|
using namespace solidity::frontend::experimental;
|
||||||
|
using namespace solidity::langutil;
|
||||||
|
|
||||||
|
TypeRegistration::TypeRegistration(Analysis& _analysis):
|
||||||
|
m_analysis(_analysis),
|
||||||
|
m_errorReporter(_analysis.errorReporter()),
|
||||||
|
m_typeSystem(_analysis.typeSystem())
|
||||||
|
{
|
||||||
|
for (auto [type, name, arity]: std::initializer_list<std::tuple<BuiltinType, const char*, uint64_t>> {
|
||||||
|
{BuiltinType::Void, "void", 0},
|
||||||
|
{BuiltinType::Function, "fun", 2},
|
||||||
|
{BuiltinType::Unit, "unit", 0},
|
||||||
|
{BuiltinType::Pair, "pair", 2},
|
||||||
|
{BuiltinType::Word, "word", 0},
|
||||||
|
{BuiltinType::Integer, "integer", 0}
|
||||||
|
})
|
||||||
|
m_typeSystem.declareBuiltinType(type, name, arity);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TypeRegistration::analyze(SourceUnit const& _sourceUnit)
|
||||||
|
{
|
||||||
|
_sourceUnit.accept(*this);
|
||||||
|
return !m_errorReporter.hasErrors();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TypeRegistration::visit(TypeClassDefinition const& _typeClassDefinition)
|
||||||
|
{
|
||||||
|
if (!m_visitedClasses.insert(_typeClassDefinition.id()).second)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool TypeRegistration::visit(TypeClassInstantiation const& _typeClassInstantiation)
|
||||||
|
{
|
||||||
|
auto const* classDefintion = dynamic_cast<TypeClassDefinition const*>(_typeClassInstantiation.sort().annotation().referencedDeclaration);
|
||||||
|
if (!classDefintion)
|
||||||
|
m_errorReporter.fatalTypeError(0000_error, _typeClassInstantiation.sort().location(), "Expected a type class.");
|
||||||
|
classDefintion->accept(*this);
|
||||||
|
|
||||||
|
// TypeClass typeClass{classDefintion};
|
||||||
|
|
||||||
|
auto fromTypeName = [&](TypeName const& _typeName) -> Type {
|
||||||
|
if (auto const* elementaryTypeName = dynamic_cast<ElementaryTypeName const*>(&_typeName))
|
||||||
|
{
|
||||||
|
switch(elementaryTypeName->typeName().token())
|
||||||
|
{
|
||||||
|
case Token::Word:
|
||||||
|
return m_typeSystem.builtinType(BuiltinType::Word, {});
|
||||||
|
case Token::Void:
|
||||||
|
return m_typeSystem.builtinType(BuiltinType::Void, {});
|
||||||
|
case Token::Integer:
|
||||||
|
return m_typeSystem.builtinType(BuiltinType::Integer, {});
|
||||||
|
default:
|
||||||
|
m_errorReporter.typeError(0000_error, _typeName.location(), "Only elementary types are supported.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_errorReporter.typeError(0000_error, _typeName.location(), "Unsupported type name.");
|
||||||
|
return m_typeSystem.freshTypeVariable(false);
|
||||||
|
};
|
||||||
|
auto type = fromTypeName(_typeClassInstantiation.typeConstructor());
|
||||||
|
_typeClassInstantiation.argumentSorts();
|
||||||
|
|
||||||
|
// m_typeSystem.instantiateClass();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeRegistration::Annotation& TypeRegistration::annotation(ASTNode const& _node)
|
||||||
|
{
|
||||||
|
return m_analysis.annotation<TypeRegistration>(_node);
|
||||||
|
}
|
51
libsolidity/analysis/experimental/TypeRegistration.h
Normal file
51
libsolidity/analysis/experimental/TypeRegistration.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
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
|
||||||
|
|
||||||
|
#include <libsolidity/ast/ASTVisitor.h>
|
||||||
|
#include <libsolidity/ast/experimental/TypeSystem.h>
|
||||||
|
|
||||||
|
#include <liblangutil/ErrorReporter.h>
|
||||||
|
|
||||||
|
namespace solidity::frontend::experimental
|
||||||
|
{
|
||||||
|
|
||||||
|
class Analysis;
|
||||||
|
|
||||||
|
class TypeRegistration: public ASTConstVisitor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct Annotation
|
||||||
|
{
|
||||||
|
Type type;
|
||||||
|
};
|
||||||
|
TypeRegistration(Analysis& _analysis);
|
||||||
|
|
||||||
|
bool analyze(SourceUnit const& _sourceUnit);
|
||||||
|
private:
|
||||||
|
bool visit(TypeClassDefinition const& _typeClassDefinition) override;
|
||||||
|
bool visit(TypeClassInstantiation const& _typeClassInstantiation) override;
|
||||||
|
Annotation& annotation(ASTNode const& _node);
|
||||||
|
|
||||||
|
Analysis& m_analysis;
|
||||||
|
langutil::ErrorReporter& m_errorReporter;
|
||||||
|
TypeSystem& m_typeSystem;
|
||||||
|
std::set<int64_t> m_visitedClasses;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -70,7 +70,7 @@ std::string TypeSystem::typeToString(Type const& _type) const
|
|||||||
{
|
{
|
||||||
auto tupleTypes = TypeSystemHelpers{*this}.destTupleType(_type);
|
auto tupleTypes = TypeSystemHelpers{*this}.destTupleType(_type);
|
||||||
stream << "(";
|
stream << "(";
|
||||||
for (auto type: tupleTypes | ranges::view::drop_last(1))
|
for (auto type: tupleTypes | ranges::views::drop_last(1))
|
||||||
stream << typeToString(type) << ", ";
|
stream << typeToString(type) << ", ";
|
||||||
stream << typeToString(tupleTypes.back()) << ")";
|
stream << typeToString(tupleTypes.back()) << ")";
|
||||||
break;
|
break;
|
||||||
@ -136,16 +136,16 @@ experimental::Type TypeSystem::freshTypeVariable(bool _generic)
|
|||||||
void TypeSystem::instantiate(TypeVariable _variable, Type _type)
|
void TypeSystem::instantiate(TypeVariable _variable, Type _type)
|
||||||
{
|
{
|
||||||
validate(_variable);
|
validate(_variable);
|
||||||
solAssert(!m_typeVariables.at(_variable.index()).has_value());
|
solAssert(!m_typeVariables.at(static_cast<size_t>(_variable.index())).has_value());
|
||||||
solAssert(_variable.m_parent == this);
|
solAssert(_variable.m_parent == this);
|
||||||
m_typeVariables[_variable.index()] = _type;
|
m_typeVariables[static_cast<size_t>(_variable.index())] = _type;
|
||||||
}
|
}
|
||||||
|
|
||||||
experimental::Type TypeSystem::resolve(Type _type) const
|
experimental::Type TypeSystem::resolve(Type _type) const
|
||||||
{
|
{
|
||||||
Type result = _type;
|
Type result = _type;
|
||||||
while(auto const* var = std::get_if<TypeVariable>(&result))
|
while(auto const* var = std::get_if<TypeVariable>(&result))
|
||||||
if (auto value = m_typeVariables.at(var->index()))
|
if (auto value = m_typeVariables.at(static_cast<size_t>(var->index())))
|
||||||
result = *value;
|
result = *value;
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
@ -182,7 +182,7 @@ experimental::Type TypeSystem::fresh(Type _type, bool _generalize)
|
|||||||
[&](TypeExpression const& _type) -> Type {
|
[&](TypeExpression const& _type) -> Type {
|
||||||
return TypeExpression{
|
return TypeExpression{
|
||||||
_type.constructor,
|
_type.constructor,
|
||||||
_type.arguments | ranges::view::transform([&](Type _argType) {
|
_type.arguments | ranges::views::transform([&](Type _argType) {
|
||||||
return _recurse(_argType, _generalize, _recurse);
|
return _recurse(_argType, _generalize, _recurse);
|
||||||
}) | ranges::to<vector<Type>>
|
}) | ranges::to<vector<Type>>
|
||||||
};
|
};
|
||||||
@ -203,6 +203,13 @@ experimental::Type TypeSystem::fresh(Type _type, bool _generalize)
|
|||||||
return freshImpl(_type, _generalize, freshImpl);
|
return freshImpl(_type, _generalize, freshImpl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TypeSystem::instantiateClass(TypeExpression::Constructor _typeConstructor, vector<TypeClass> _argumentSorts, TypeClass _class)
|
||||||
|
{
|
||||||
|
(void)_typeConstructor;
|
||||||
|
(void)_argumentSorts;
|
||||||
|
(void)_class;
|
||||||
|
}
|
||||||
|
|
||||||
experimental::Type TypeSystemHelpers::tupleType(vector<Type> _elements) const
|
experimental::Type TypeSystemHelpers::tupleType(vector<Type> _elements) const
|
||||||
{
|
{
|
||||||
if (_elements.empty())
|
if (_elements.empty())
|
||||||
@ -210,7 +217,7 @@ experimental::Type TypeSystemHelpers::tupleType(vector<Type> _elements) const
|
|||||||
if (_elements.size() == 1)
|
if (_elements.size() == 1)
|
||||||
return _elements.front();
|
return _elements.front();
|
||||||
Type result = _elements.back();
|
Type result = _elements.back();
|
||||||
for (Type type: _elements | ranges::view::reverse | ranges::view::drop_exactly(1))
|
for (Type type: _elements | ranges::views::reverse | ranges::views::drop_exactly(1))
|
||||||
result = typeSystem.builtinType(BuiltinType::Pair, {type, result});
|
result = typeSystem.builtinType(BuiltinType::Pair, {type, result});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,6 @@ struct TypeExpression
|
|||||||
using Constructor = std::variant<BuiltinType, Declaration const*>;
|
using Constructor = std::variant<BuiltinType, Declaration const*>;
|
||||||
Constructor constructor;
|
Constructor constructor;
|
||||||
std::vector<Type> arguments;
|
std::vector<Type> arguments;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TypeVariable
|
struct TypeVariable
|
||||||
@ -71,6 +70,21 @@ private:
|
|||||||
TypeVariable(TypeSystem const& _parent, uint64_t _index, bool _generic): m_parent(&_parent), m_index(_index), m_generic(_generic) {}
|
TypeVariable(TypeSystem const& _parent, uint64_t _index, bool _generic): m_parent(&_parent), m_index(_index), m_generic(_generic) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TypeClass
|
||||||
|
{
|
||||||
|
Declaration const* declaration = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Sort
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Arity
|
||||||
|
{
|
||||||
|
std::vector<Arity> _argumentSorts;
|
||||||
|
TypeClass _class;
|
||||||
|
};
|
||||||
class TypeSystem
|
class TypeSystem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -90,6 +104,7 @@ public:
|
|||||||
Type fresh(Type _type, bool _generalize);
|
Type fresh(Type _type, bool _generalize);
|
||||||
struct UnificationFailure { Type a; Type b; };
|
struct UnificationFailure { Type a; Type b; };
|
||||||
[[nodiscard]] std::vector<UnificationFailure> unify(Type _a, Type _b);
|
[[nodiscard]] std::vector<UnificationFailure> unify(Type _a, Type _b);
|
||||||
|
void instantiateClass(TypeExpression::Constructor _typeConstructor, std::vector<TypeClass> _argumentSorts, TypeClass _class);
|
||||||
private:
|
private:
|
||||||
void instantiate(TypeVariable _variable, Type _type);
|
void instantiate(TypeVariable _variable, Type _type);
|
||||||
void validate(TypeVariable _variable) const;
|
void validate(TypeVariable _variable) const;
|
||||||
@ -101,6 +116,7 @@ private:
|
|||||||
};
|
};
|
||||||
std::map<BuiltinType, TypeConstructorInfo> m_builtinTypes;
|
std::map<BuiltinType, TypeConstructorInfo> m_builtinTypes;
|
||||||
std::vector<std::optional<Type>> m_typeVariables;
|
std::vector<std::optional<Type>> m_typeVariables;
|
||||||
|
std::map<TypeExpression::Constructor, Sort> m_sorts;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TypeSystemHelpers
|
struct TypeSystemHelpers
|
||||||
|
@ -100,7 +100,7 @@ string IRGenerator::generate(FunctionDefinition const& _function)
|
|||||||
std::stringstream code;
|
std::stringstream code;
|
||||||
code << "function " << IRNames::function(_function) << "(";
|
code << "function " << IRNames::function(_function) << "(";
|
||||||
if (_function.parameters().size() > 1)
|
if (_function.parameters().size() > 1)
|
||||||
for (auto const& arg: _function.parameters() | ranges::view::drop_last(1))
|
for (auto const& arg: _function.parameters() | ranges::views::drop_last(1))
|
||||||
code << IRNames::localVariable(*arg) << ", ";
|
code << IRNames::localVariable(*arg) << ", ";
|
||||||
if (!_function.parameters().empty())
|
if (!_function.parameters().empty())
|
||||||
code << IRNames::localVariable(*_function.parameters().back());
|
code << IRNames::localVariable(*_function.parameters().back());
|
||||||
@ -109,7 +109,7 @@ string IRGenerator::generate(FunctionDefinition const& _function)
|
|||||||
{
|
{
|
||||||
code << " -> ";
|
code << " -> ";
|
||||||
if (_function.returnParameters().size() > 1)
|
if (_function.returnParameters().size() > 1)
|
||||||
for (auto const& arg: _function.returnParameters() | ranges::view::drop_last(1))
|
for (auto const& arg: _function.returnParameters() | ranges::views::drop_last(1))
|
||||||
code << IRNames::localVariable(*arg) << ", ";
|
code << IRNames::localVariable(*arg) << ", ";
|
||||||
if (!_function.returnParameters().empty())
|
if (!_function.returnParameters().empty())
|
||||||
code << IRNames::localVariable(*_function.returnParameters().back());
|
code << IRNames::localVariable(*_function.returnParameters().back());
|
||||||
|
@ -46,14 +46,14 @@ public:
|
|||||||
std::optional<uint8_t> _eofVersion,
|
std::optional<uint8_t> _eofVersion,
|
||||||
RevertStrings /*_revertStrings*/,
|
RevertStrings /*_revertStrings*/,
|
||||||
std::map<std::string, unsigned> /*_sourceIndices*/,
|
std::map<std::string, unsigned> /*_sourceIndices*/,
|
||||||
langutil::DebugInfoSelection const& _debugInfoSelection,
|
langutil::DebugInfoSelection const& /*_debugInfoSelection*/,
|
||||||
langutil::CharStreamProvider const* _soliditySourceProvider,
|
langutil::CharStreamProvider const* /*_soliditySourceProvider*/,
|
||||||
Analysis const& _analysis
|
Analysis const& _analysis
|
||||||
):
|
):
|
||||||
m_evmVersion(_evmVersion),
|
m_evmVersion(_evmVersion),
|
||||||
m_eofVersion(_eofVersion),
|
m_eofVersion(_eofVersion),
|
||||||
m_debugInfoSelection(_debugInfoSelection),
|
// m_debugInfoSelection(_debugInfoSelection),
|
||||||
m_soliditySourceProvider(_soliditySourceProvider),
|
// m_soliditySourceProvider(_soliditySourceProvider),
|
||||||
m_context{_analysis, {}, {}}
|
m_context{_analysis, {}, {}}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
@ -69,8 +69,8 @@ private:
|
|||||||
langutil::EVMVersion const m_evmVersion;
|
langutil::EVMVersion const m_evmVersion;
|
||||||
std::optional<uint8_t> const m_eofVersion;
|
std::optional<uint8_t> const m_eofVersion;
|
||||||
OptimiserSettings const m_optimiserSettings;
|
OptimiserSettings const m_optimiserSettings;
|
||||||
langutil::DebugInfoSelection m_debugInfoSelection = {};
|
// langutil::DebugInfoSelection m_debugInfoSelection = {};
|
||||||
langutil::CharStreamProvider const* m_soliditySourceProvider = nullptr;
|
// langutil::CharStreamProvider const* m_soliditySourceProvider = nullptr;
|
||||||
IRGenerationContext m_context;
|
IRGenerationContext m_context;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -145,7 +145,6 @@ void IRGeneratorForStatements::endVisit(Return const& _return)
|
|||||||
m_code << IRNames::localVariable(*returnParameters.front()) << " := " << IRNames::localVariable(*value) << "\n";
|
m_code << IRNames::localVariable(*returnParameters.front()) << " := " << IRNames::localVariable(*value) << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
_return.annotation().functionReturnParameters;
|
|
||||||
m_code << "leave\n";
|
m_code << "leave\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,7 +162,7 @@ bool IRGeneratorForStatements::visit(FunctionCall const& _functionCall)
|
|||||||
m_code << "let " << IRNames::localVariable(_functionCall) << " := " << IRNames::function(*functionDefinition) << "(";
|
m_code << "let " << IRNames::localVariable(_functionCall) << " := " << IRNames::function(*functionDefinition) << "(";
|
||||||
auto const& arguments = _functionCall.arguments();
|
auto const& arguments = _functionCall.arguments();
|
||||||
if (arguments.size() > 1)
|
if (arguments.size() > 1)
|
||||||
for (auto arg: arguments | ranges::view::drop_last(1))
|
for (auto arg: arguments | ranges::views::drop_last(1))
|
||||||
m_code << IRNames::localVariable(*arg) << ", ";
|
m_code << IRNames::localVariable(*arg) << ", ";
|
||||||
if (!arguments.empty())
|
if (!arguments.empty())
|
||||||
m_code << IRNames::localVariable(*arguments.back());
|
m_code << IRNames::localVariable(*arguments.back());
|
||||||
|
Loading…
Reference in New Issue
Block a user