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/DebugWarner.cpp
|
||||
experimental/analysis/DebugWarner.h
|
||||
experimental/analysis/TypeClassRegistration.cpp
|
||||
experimental/analysis/TypeClassRegistration.h
|
||||
experimental/analysis/TypeInference.cpp
|
||||
experimental/analysis/TypeInference.h
|
||||
experimental/analysis/TypeRegistration.cpp
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <libsolidity/experimental/analysis/Analysis.h>
|
||||
#include <libsolidity/experimental/analysis/DebugWarner.h>
|
||||
#include <libsolidity/experimental/analysis/SyntaxRestrictor.h>
|
||||
#include <libsolidity/experimental/analysis/TypeClassRegistration.h>
|
||||
#include <libsolidity/experimental/analysis/TypeInference.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.
|
||||
struct Analysis::AnnotationContainer
|
||||
{
|
||||
TypeClassRegistration::Annotation typeClassRegistrationAnnotation;
|
||||
TypeRegistration::Annotation typeRegistrationAnnotation;
|
||||
TypeInference::Annotation typeInferenceAnnotation;
|
||||
};
|
||||
|
||||
struct Analysis::GlobalAnnotationContainer
|
||||
{
|
||||
TypeClassRegistration::GlobalAnnotation typeClassRegistrationAnnotation;
|
||||
TypeRegistration::GlobalAnnotation typeRegistrationAnnotation;
|
||||
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<>
|
||||
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)
|
||||
{
|
||||
using AnalysisSteps = std::tuple<SyntaxRestrictor, TypeRegistration, TypeInference, DebugWarner>;
|
||||
using AnalysisSteps = std::tuple<SyntaxRestrictor, TypeClassRegistration, TypeRegistration, TypeInference, DebugWarner>;
|
||||
|
||||
return std::apply([&](auto... _indexTuple) {
|
||||
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/TypeClassRegistration.h>
|
||||
#include <libsolidity/experimental/analysis/TypeRegistration.h>
|
||||
#include <libsolidity/experimental/analysis/Analysis.h>
|
||||
#include <libsolidity/experimental/ast/TypeSystemHelper.h>
|
||||
@ -205,7 +207,9 @@ bool TypeInference::visit(TypeClassDefinition const& _typeClassDefinition)
|
||||
|
||||
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)];
|
||||
|
||||
for (auto subNode: _typeClassDefinition.subNodes())
|
||||
@ -224,14 +228,6 @@ bool TypeInference::visit(TypeClassDefinition const& _typeClassDefinition)
|
||||
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);
|
||||
|
||||
for (auto [functionName, functionType]: functionTypes)
|
||||
@ -574,12 +570,10 @@ experimental::Type TypeInference::handleIdentifierByReferencedDeclaration(langut
|
||||
{
|
||||
ScopedSaveAndRestore expressionContext{m_expressionContext, ExpressionContext::Term};
|
||||
typeClassDefinition->accept(*this);
|
||||
if (!annotation(*typeClassDefinition).typeClass)
|
||||
{
|
||||
m_errorReporter.typeError(2736_error, _location, "Unregistered type class.");
|
||||
return m_typeSystem.freshTypeVariable({});
|
||||
}
|
||||
return m_typeSystem.freshTypeVariable(Sort{{*annotation(*typeClassDefinition).typeClass}});
|
||||
|
||||
solAssert(m_analysis.annotation<TypeClassRegistration>(*typeClassDefinition).typeClass.has_value());
|
||||
TypeClass typeClass = m_analysis.annotation<TypeClassRegistration>(*typeClassDefinition).typeClass.value();
|
||||
return m_typeSystem.freshTypeVariable(Sort{{typeClass}});
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -680,9 +674,8 @@ bool TypeInference::visit(TypeClassInstantiation const& _typeClassInstantiation)
|
||||
// visiting the type class will re-visit this instantiation
|
||||
typeClassDefinition->accept(*this);
|
||||
// TODO: more error handling? Should be covered by the visit above.
|
||||
if (!annotation(*typeClassDefinition).typeClass)
|
||||
m_errorReporter.typeError(8503_error, _typeClassInstantiation.typeClass().location(), "Expected type class.");
|
||||
return annotation(*typeClassDefinition).typeClass;
|
||||
solAssert(m_analysis.annotation<TypeClassRegistration>(*typeClassDefinition).typeClass.has_value());
|
||||
return m_analysis.annotation<TypeClassRegistration>(*typeClassDefinition).typeClass.value();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -38,8 +38,6 @@ public:
|
||||
{
|
||||
/// Expressions, variable declarations, function declarations.
|
||||
std::optional<Type> type;
|
||||
// Type classes.
|
||||
std::optional<TypeClass> typeClass;
|
||||
};
|
||||
struct TypeMember
|
||||
{
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <libsolidity/experimental/codegen/IRGeneratorForStatements.h>
|
||||
|
||||
#include <libsolidity/experimental/analysis/Analysis.h>
|
||||
#include <libsolidity/experimental/analysis/TypeClassRegistration.h>
|
||||
#include <libsolidity/experimental/analysis/TypeInference.h>
|
||||
#include <libsolidity/experimental/analysis/TypeRegistration.h>
|
||||
|
||||
@ -271,11 +272,11 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
||||
solAssert(declaration);
|
||||
if (auto const* typeClassDefinition = dynamic_cast<TypeClassDefinition const*>(declaration))
|
||||
{
|
||||
std::optional<TypeClass> typeClass = m_context.analysis.annotation<TypeInference>(*typeClassDefinition).typeClass;
|
||||
solAssert(typeClass);
|
||||
solAssert(m_context.analysis.annotation<TypeClassRegistration>(*typeClassDefinition).typeClass.has_value());
|
||||
TypeClass typeClass = m_context.analysis.annotation<TypeClassRegistration>(*typeClassDefinition).typeClass.value();
|
||||
solAssert(m_expressionDeclaration.emplace(
|
||||
&_memberAccess,
|
||||
&resolveTypeClassFunction(*typeClass, _memberAccess.memberName(), memberAccessType)
|
||||
&resolveTypeClassFunction(typeClass, _memberAccess.memberName(), memberAccessType)
|
||||
).second);
|
||||
}
|
||||
else if (dynamic_cast<TypeDefinition const*>(declaration))
|
||||
|
@ -3,9 +3,9 @@ pragma experimental solidity;
|
||||
type Cat = word;
|
||||
type Dog = word;
|
||||
|
||||
class A: Animal {
|
||||
function new() -> A;
|
||||
function alive(a: A) -> bool;
|
||||
class Self: Animal {
|
||||
function new() -> Self;
|
||||
function alive(self: Self) -> bool;
|
||||
}
|
||||
|
||||
instantiation Cat: Animal {
|
||||
@ -14,7 +14,7 @@ instantiation Cat: Animal {
|
||||
return c;
|
||||
}
|
||||
|
||||
function alive(c: Cat) -> bool {
|
||||
function alive(self: Cat) -> bool {
|
||||
// TODO: Boolean literals or operators not implemented.
|
||||
let w;
|
||||
assembly {
|
||||
@ -30,7 +30,7 @@ instantiation Dog: Animal {
|
||||
return d;
|
||||
}
|
||||
|
||||
function alive(d: Dog) -> bool {
|
||||
function alive(self: Dog) -> bool {
|
||||
let b: bool;
|
||||
return b;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user