mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Separate experimental analysis pass for type class registration
This commit is contained in:
parent
086c912c65
commit
da83b35a71
@ -188,6 +188,8 @@ set(sources
|
|||||||
experimental/analysis/Analysis.h
|
experimental/analysis/Analysis.h
|
||||||
experimental/analysis/DebugWarner.cpp
|
experimental/analysis/DebugWarner.cpp
|
||||||
experimental/analysis/DebugWarner.h
|
experimental/analysis/DebugWarner.h
|
||||||
|
experimental/analysis/TypeClassRegistration.cpp
|
||||||
|
experimental/analysis/TypeClassRegistration.h
|
||||||
experimental/analysis/TypeInference.cpp
|
experimental/analysis/TypeInference.cpp
|
||||||
experimental/analysis/TypeInference.h
|
experimental/analysis/TypeInference.h
|
||||||
experimental/analysis/TypeRegistration.cpp
|
experimental/analysis/TypeRegistration.cpp
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include <libsolidity/experimental/analysis/Analysis.h>
|
#include <libsolidity/experimental/analysis/Analysis.h>
|
||||||
#include <libsolidity/experimental/analysis/DebugWarner.h>
|
#include <libsolidity/experimental/analysis/DebugWarner.h>
|
||||||
#include <libsolidity/experimental/analysis/SyntaxRestrictor.h>
|
#include <libsolidity/experimental/analysis/SyntaxRestrictor.h>
|
||||||
|
#include <libsolidity/experimental/analysis/TypeClassRegistration.h>
|
||||||
#include <libsolidity/experimental/analysis/TypeInference.h>
|
#include <libsolidity/experimental/analysis/TypeInference.h>
|
||||||
#include <libsolidity/experimental/analysis/TypeRegistration.h>
|
#include <libsolidity/experimental/analysis/TypeRegistration.h>
|
||||||
|
|
||||||
@ -27,16 +28,43 @@ using namespace solidity::frontend::experimental;
|
|||||||
// TODO: creating all of them for all nodes up front may be wasteful, we should improve the mechanism.
|
// TODO: creating all of them for all nodes up front may be wasteful, we should improve the mechanism.
|
||||||
struct Analysis::AnnotationContainer
|
struct Analysis::AnnotationContainer
|
||||||
{
|
{
|
||||||
|
TypeClassRegistration::Annotation typeClassRegistrationAnnotation;
|
||||||
TypeRegistration::Annotation typeRegistrationAnnotation;
|
TypeRegistration::Annotation typeRegistrationAnnotation;
|
||||||
TypeInference::Annotation typeInferenceAnnotation;
|
TypeInference::Annotation typeInferenceAnnotation;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Analysis::GlobalAnnotationContainer
|
struct Analysis::GlobalAnnotationContainer
|
||||||
{
|
{
|
||||||
|
TypeClassRegistration::GlobalAnnotation typeClassRegistrationAnnotation;
|
||||||
TypeRegistration::GlobalAnnotation typeRegistrationAnnotation;
|
TypeRegistration::GlobalAnnotation typeRegistrationAnnotation;
|
||||||
TypeInference::GlobalAnnotation typeInferenceAnnotation;
|
TypeInference::GlobalAnnotation typeInferenceAnnotation;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
TypeClassRegistration::Annotation& solidity::frontend::experimental::detail::AnnotationFetcher<TypeClassRegistration>::get(ASTNode const& _node)
|
||||||
|
{
|
||||||
|
return analysis.annotationContainer(_node).typeClassRegistrationAnnotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
TypeClassRegistration::GlobalAnnotation const& solidity::frontend::experimental::detail::ConstAnnotationFetcher<TypeClassRegistration>::get() const
|
||||||
|
{
|
||||||
|
return analysis.annotationContainer().typeClassRegistrationAnnotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<>
|
||||||
|
TypeClassRegistration::GlobalAnnotation& solidity::frontend::experimental::detail::AnnotationFetcher<TypeClassRegistration>::get()
|
||||||
|
{
|
||||||
|
return analysis.annotationContainer().typeClassRegistrationAnnotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
TypeClassRegistration::Annotation const& solidity::frontend::experimental::detail::ConstAnnotationFetcher<TypeClassRegistration>::get(ASTNode const& _node) const
|
||||||
|
{
|
||||||
|
return analysis.annotationContainer(_node).typeClassRegistrationAnnotation;
|
||||||
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
TypeRegistration::Annotation& solidity::frontend::experimental::detail::AnnotationFetcher<TypeRegistration>::get(ASTNode const& _node)
|
TypeRegistration::Annotation& solidity::frontend::experimental::detail::AnnotationFetcher<TypeRegistration>::get(ASTNode const& _node)
|
||||||
{
|
{
|
||||||
@ -121,7 +149,7 @@ std::tuple<std::integral_constant<size_t, Is>...> makeIndexTuple(std::index_sequ
|
|||||||
|
|
||||||
bool Analysis::check(std::vector<std::shared_ptr<SourceUnit const>> const& _sourceUnits)
|
bool Analysis::check(std::vector<std::shared_ptr<SourceUnit const>> const& _sourceUnits)
|
||||||
{
|
{
|
||||||
using AnalysisSteps = std::tuple<SyntaxRestrictor, TypeRegistration, TypeInference, DebugWarner>;
|
using AnalysisSteps = std::tuple<SyntaxRestrictor, TypeClassRegistration, TypeRegistration, TypeInference, DebugWarner>;
|
||||||
|
|
||||||
return std::apply([&](auto... _indexTuple) {
|
return std::apply([&](auto... _indexTuple) {
|
||||||
return ([&](auto&& _step) {
|
return ([&](auto&& _step) {
|
||||||
|
65
libsolidity/experimental/analysis/TypeClassRegistration.cpp
Normal file
65
libsolidity/experimental/analysis/TypeClassRegistration.cpp
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
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/experimental/analysis/TypeClassRegistration.h>
|
||||||
|
|
||||||
|
#include <libsolidity/experimental/analysis/Analysis.h>
|
||||||
|
|
||||||
|
#include <liblangutil/ErrorReporter.h>
|
||||||
|
#include <liblangutil/Exceptions.h>
|
||||||
|
|
||||||
|
using namespace solidity::frontend::experimental;
|
||||||
|
using namespace solidity::langutil;
|
||||||
|
|
||||||
|
TypeClassRegistration::TypeClassRegistration(Analysis& _analysis):
|
||||||
|
m_analysis(_analysis),
|
||||||
|
m_errorReporter(_analysis.errorReporter()),
|
||||||
|
m_typeSystem(_analysis.typeSystem())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TypeClassRegistration::analyze(SourceUnit const& _sourceUnit)
|
||||||
|
{
|
||||||
|
_sourceUnit.accept(*this);
|
||||||
|
return !m_errorReporter.hasErrors();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TypeClassRegistration::visit(TypeClassDefinition const& _typeClassDefinition)
|
||||||
|
{
|
||||||
|
Type typeVar = m_typeSystem.freshTypeVariable({});
|
||||||
|
|
||||||
|
std::variant<TypeClass, std::string> typeClassOrError = m_typeSystem.declareTypeClass(
|
||||||
|
typeVar,
|
||||||
|
_typeClassDefinition.name(),
|
||||||
|
&_typeClassDefinition
|
||||||
|
);
|
||||||
|
|
||||||
|
m_analysis.annotation<TypeClassRegistration>(_typeClassDefinition).typeClass = std::visit(
|
||||||
|
util::GenericVisitor{
|
||||||
|
[](TypeClass _class) -> TypeClass { return _class; },
|
||||||
|
[&](std::string _error) -> TypeClass {
|
||||||
|
m_errorReporter.fatalTypeError(4767_error, _typeClassDefinition.location(), _error);
|
||||||
|
util::unreachable();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
typeClassOrError
|
||||||
|
);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
58
libsolidity/experimental/analysis/TypeClassRegistration.h
Normal file
58
libsolidity/experimental/analysis/TypeClassRegistration.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
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/experimental/ast/TypeSystem.h>
|
||||||
|
|
||||||
|
namespace solidity::langutil
|
||||||
|
{
|
||||||
|
class ErrorReporter;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace solidity::frontend::experimental
|
||||||
|
{
|
||||||
|
|
||||||
|
class Analysis;
|
||||||
|
class TypeSystem;
|
||||||
|
|
||||||
|
class TypeClassRegistration: public ASTConstVisitor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct Annotation
|
||||||
|
{
|
||||||
|
// Type classes.
|
||||||
|
std::optional<TypeClass> typeClass;
|
||||||
|
};
|
||||||
|
struct GlobalAnnotation
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
TypeClassRegistration(Analysis& _analysis);
|
||||||
|
|
||||||
|
bool analyze(SourceUnit const& _sourceUnit);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool visit(TypeClassDefinition const& _typeClassDefinition) override;
|
||||||
|
|
||||||
|
Analysis& m_analysis;
|
||||||
|
langutil::ErrorReporter& m_errorReporter;
|
||||||
|
TypeSystem& m_typeSystem;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -18,6 +18,8 @@
|
|||||||
|
|
||||||
|
|
||||||
#include <libsolidity/experimental/analysis/TypeInference.h>
|
#include <libsolidity/experimental/analysis/TypeInference.h>
|
||||||
|
|
||||||
|
#include <libsolidity/experimental/analysis/TypeClassRegistration.h>
|
||||||
#include <libsolidity/experimental/analysis/TypeRegistration.h>
|
#include <libsolidity/experimental/analysis/TypeRegistration.h>
|
||||||
#include <libsolidity/experimental/analysis/Analysis.h>
|
#include <libsolidity/experimental/analysis/Analysis.h>
|
||||||
#include <libsolidity/experimental/ast/TypeSystemHelper.h>
|
#include <libsolidity/experimental/ast/TypeSystemHelper.h>
|
||||||
@ -205,7 +207,9 @@ bool TypeInference::visit(TypeClassDefinition const& _typeClassDefinition)
|
|||||||
|
|
||||||
std::map<std::string, Type> functionTypes;
|
std::map<std::string, Type> functionTypes;
|
||||||
|
|
||||||
Type typeVar = m_typeSystem.freshTypeVariable({});
|
solAssert(m_analysis.annotation<TypeClassRegistration>(_typeClassDefinition).typeClass.has_value());
|
||||||
|
TypeClass typeClass = m_analysis.annotation<TypeClassRegistration>(_typeClassDefinition).typeClass.value();
|
||||||
|
Type typeVar = m_typeSystem.typeClassInfo(typeClass).typeVariable;
|
||||||
auto& typeMembersAnnotation = annotation().members[typeConstructor(&_typeClassDefinition)];
|
auto& typeMembersAnnotation = annotation().members[typeConstructor(&_typeClassDefinition)];
|
||||||
|
|
||||||
for (auto subNode: _typeClassDefinition.subNodes())
|
for (auto subNode: _typeClassDefinition.subNodes())
|
||||||
@ -224,14 +228,6 @@ bool TypeInference::visit(TypeClassDefinition const& _typeClassDefinition)
|
|||||||
typeMembersAnnotation[functionDefinition->name()] = TypeMember{functionType};
|
typeMembersAnnotation[functionDefinition->name()] = TypeMember{functionType};
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeClass typeClass = std::visit(util::GenericVisitor{
|
|
||||||
[](TypeClass _class) -> TypeClass { return _class; },
|
|
||||||
[&](std::string _error) -> TypeClass {
|
|
||||||
m_errorReporter.fatalTypeError(4767_error, _typeClassDefinition.location(), _error);
|
|
||||||
util::unreachable();
|
|
||||||
}
|
|
||||||
}, m_typeSystem.declareTypeClass(typeVar, _typeClassDefinition.name(), &_typeClassDefinition));
|
|
||||||
typeClassDefinitionAnnotation.typeClass = typeClass;
|
|
||||||
annotation().typeClassFunctions[typeClass] = std::move(functionTypes);
|
annotation().typeClassFunctions[typeClass] = std::move(functionTypes);
|
||||||
|
|
||||||
for (auto [functionName, functionType]: functionTypes)
|
for (auto [functionName, functionType]: functionTypes)
|
||||||
@ -574,12 +570,10 @@ experimental::Type TypeInference::handleIdentifierByReferencedDeclaration(langut
|
|||||||
{
|
{
|
||||||
ScopedSaveAndRestore expressionContext{m_expressionContext, ExpressionContext::Term};
|
ScopedSaveAndRestore expressionContext{m_expressionContext, ExpressionContext::Term};
|
||||||
typeClassDefinition->accept(*this);
|
typeClassDefinition->accept(*this);
|
||||||
if (!annotation(*typeClassDefinition).typeClass)
|
|
||||||
{
|
solAssert(m_analysis.annotation<TypeClassRegistration>(*typeClassDefinition).typeClass.has_value());
|
||||||
m_errorReporter.typeError(2736_error, _location, "Unregistered type class.");
|
TypeClass typeClass = m_analysis.annotation<TypeClassRegistration>(*typeClassDefinition).typeClass.value();
|
||||||
return m_typeSystem.freshTypeVariable({});
|
return m_typeSystem.freshTypeVariable(Sort{{typeClass}});
|
||||||
}
|
|
||||||
return m_typeSystem.freshTypeVariable(Sort{{*annotation(*typeClassDefinition).typeClass}});
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -680,9 +674,8 @@ bool TypeInference::visit(TypeClassInstantiation const& _typeClassInstantiation)
|
|||||||
// visiting the type class will re-visit this instantiation
|
// visiting the type class will re-visit this instantiation
|
||||||
typeClassDefinition->accept(*this);
|
typeClassDefinition->accept(*this);
|
||||||
// TODO: more error handling? Should be covered by the visit above.
|
// TODO: more error handling? Should be covered by the visit above.
|
||||||
if (!annotation(*typeClassDefinition).typeClass)
|
solAssert(m_analysis.annotation<TypeClassRegistration>(*typeClassDefinition).typeClass.has_value());
|
||||||
m_errorReporter.typeError(8503_error, _typeClassInstantiation.typeClass().location(), "Expected type class.");
|
return m_analysis.annotation<TypeClassRegistration>(*typeClassDefinition).typeClass.value();
|
||||||
return annotation(*typeClassDefinition).typeClass;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -38,8 +38,6 @@ public:
|
|||||||
{
|
{
|
||||||
/// Expressions, variable declarations, function declarations.
|
/// Expressions, variable declarations, function declarations.
|
||||||
std::optional<Type> type;
|
std::optional<Type> type;
|
||||||
// Type classes.
|
|
||||||
std::optional<TypeClass> typeClass;
|
|
||||||
};
|
};
|
||||||
struct TypeMember
|
struct TypeMember
|
||||||
{
|
{
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include <libsolidity/experimental/codegen/IRGeneratorForStatements.h>
|
#include <libsolidity/experimental/codegen/IRGeneratorForStatements.h>
|
||||||
|
|
||||||
#include <libsolidity/experimental/analysis/Analysis.h>
|
#include <libsolidity/experimental/analysis/Analysis.h>
|
||||||
|
#include <libsolidity/experimental/analysis/TypeClassRegistration.h>
|
||||||
#include <libsolidity/experimental/analysis/TypeInference.h>
|
#include <libsolidity/experimental/analysis/TypeInference.h>
|
||||||
#include <libsolidity/experimental/analysis/TypeRegistration.h>
|
#include <libsolidity/experimental/analysis/TypeRegistration.h>
|
||||||
|
|
||||||
@ -271,11 +272,11 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
|||||||
solAssert(declaration);
|
solAssert(declaration);
|
||||||
if (auto const* typeClassDefinition = dynamic_cast<TypeClassDefinition const*>(declaration))
|
if (auto const* typeClassDefinition = dynamic_cast<TypeClassDefinition const*>(declaration))
|
||||||
{
|
{
|
||||||
std::optional<TypeClass> typeClass = m_context.analysis.annotation<TypeInference>(*typeClassDefinition).typeClass;
|
solAssert(m_context.analysis.annotation<TypeClassRegistration>(*typeClassDefinition).typeClass.has_value());
|
||||||
solAssert(typeClass);
|
TypeClass typeClass = m_context.analysis.annotation<TypeClassRegistration>(*typeClassDefinition).typeClass.value();
|
||||||
solAssert(m_expressionDeclaration.emplace(
|
solAssert(m_expressionDeclaration.emplace(
|
||||||
&_memberAccess,
|
&_memberAccess,
|
||||||
&resolveTypeClassFunction(*typeClass, _memberAccess.memberName(), memberAccessType)
|
&resolveTypeClassFunction(typeClass, _memberAccess.memberName(), memberAccessType)
|
||||||
).second);
|
).second);
|
||||||
}
|
}
|
||||||
else if (dynamic_cast<TypeDefinition const*>(declaration))
|
else if (dynamic_cast<TypeDefinition const*>(declaration))
|
||||||
|
@ -3,9 +3,9 @@ pragma experimental solidity;
|
|||||||
type Cat = word;
|
type Cat = word;
|
||||||
type Dog = word;
|
type Dog = word;
|
||||||
|
|
||||||
class A: Animal {
|
class Self: Animal {
|
||||||
function new() -> A;
|
function new() -> Self;
|
||||||
function alive(a: A) -> bool;
|
function alive(self: Self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
instantiation Cat: Animal {
|
instantiation Cat: Animal {
|
||||||
@ -14,7 +14,7 @@ instantiation Cat: Animal {
|
|||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
function alive(c: Cat) -> bool {
|
function alive(self: Cat) -> bool {
|
||||||
// TODO: Boolean literals or operators not implemented.
|
// TODO: Boolean literals or operators not implemented.
|
||||||
let w;
|
let w;
|
||||||
assembly {
|
assembly {
|
||||||
@ -30,7 +30,7 @@ instantiation Dog: Animal {
|
|||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
function alive(d: Dog) -> bool {
|
function alive(self: Dog) -> bool {
|
||||||
let b: bool;
|
let b: bool;
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user