mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
tmp
This commit is contained in:
parent
1bc8caf54a
commit
d882a08582
@ -340,6 +340,11 @@ namespace TokenTraits
|
||||
tok == Token::Default || tok == Token::For || tok == Token::Break || tok == Token::Continue || tok == Token::Leave ||
|
||||
tok == Token::TrueLiteral || tok == Token::FalseLiteral || tok == Token::HexStringLiteral || tok == Token::Hex;
|
||||
}
|
||||
constexpr bool isBuiltinTypeClassName(Token tok)
|
||||
{
|
||||
return tok == Token::Integer || (isBinaryOp(tok) && tok != Token::Comma) ||
|
||||
isCompareOp(tok) || isUnaryOp(tok) || (isAssignmentOp(tok) && tok != Token::Assign);
|
||||
}
|
||||
constexpr bool isExperimentalSolidityKeyword(Token tok)
|
||||
{
|
||||
return tok == Token::Assembly || tok == Token::Contract || tok == Token::External || tok == Token::Fallback ||
|
||||
|
@ -33,12 +33,31 @@ struct Analysis::AnnotationContainer
|
||||
TypeInference::Annotation typeInferenceAnnotation;
|
||||
};
|
||||
|
||||
struct Analysis::GlobalAnnotationContainer
|
||||
{
|
||||
TypeRegistration::GlobalAnnotation typeRegistrationAnnotation;
|
||||
TypeInference::GlobalAnnotation typeInferenceAnnotation;
|
||||
};
|
||||
|
||||
template<>
|
||||
TypeRegistration::Annotation& solidity::frontend::experimental::detail::AnnotationFetcher<TypeRegistration>::get(ASTNode const& _node)
|
||||
{
|
||||
return analysis.annotationContainer(_node).typeRegistrationAnnotation;
|
||||
}
|
||||
|
||||
template<>
|
||||
TypeRegistration::GlobalAnnotation const& solidity::frontend::experimental::detail::ConstAnnotationFetcher<TypeRegistration>::get() const
|
||||
{
|
||||
return analysis.annotationContainer().typeRegistrationAnnotation;
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
TypeRegistration::GlobalAnnotation& solidity::frontend::experimental::detail::AnnotationFetcher<TypeRegistration>::get()
|
||||
{
|
||||
return analysis.annotationContainer().typeRegistrationAnnotation;
|
||||
}
|
||||
|
||||
template<>
|
||||
TypeRegistration::Annotation const& solidity::frontend::experimental::detail::ConstAnnotationFetcher<TypeRegistration>::get(ASTNode const& _node) const
|
||||
{
|
||||
@ -57,6 +76,19 @@ TypeInference::Annotation const& solidity::frontend::experimental::detail::Const
|
||||
return analysis.annotationContainer(_node).typeInferenceAnnotation;
|
||||
}
|
||||
|
||||
template<>
|
||||
TypeInference::GlobalAnnotation const& solidity::frontend::experimental::detail::ConstAnnotationFetcher<TypeInference>::get() const
|
||||
{
|
||||
return analysis.annotationContainer().typeInferenceAnnotation;
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
TypeInference::GlobalAnnotation& solidity::frontend::experimental::detail::AnnotationFetcher<TypeInference>::get()
|
||||
{
|
||||
return analysis.annotationContainer().typeInferenceAnnotation;
|
||||
}
|
||||
|
||||
Analysis::AnnotationContainer& Analysis::annotationContainer(ASTNode const& _node)
|
||||
{
|
||||
solAssert(_node.id() > 0);
|
||||
@ -76,7 +108,8 @@ Analysis::AnnotationContainer const& Analysis::annotationContainer(ASTNode const
|
||||
Analysis::Analysis(langutil::ErrorReporter& _errorReporter, uint64_t _maxAstId):
|
||||
m_errorReporter(_errorReporter),
|
||||
m_maxAstId(_maxAstId),
|
||||
m_annotations(std::make_unique<AnnotationContainer[]>(static_cast<size_t>(_maxAstId + 1)))
|
||||
m_annotations(std::make_unique<AnnotationContainer[]>(static_cast<size_t>(_maxAstId + 1))),
|
||||
m_globalAnnotation(std::make_unique<GlobalAnnotationContainer>())
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -47,18 +47,21 @@ struct AnnotationFetcher
|
||||
{
|
||||
Analysis& analysis;
|
||||
typename Step::Annotation& get(ASTNode const& _node);
|
||||
typename Step::GlobalAnnotation& get();
|
||||
};
|
||||
template<typename Step>
|
||||
struct ConstAnnotationFetcher
|
||||
{
|
||||
Analysis const& analysis;
|
||||
typename Step::Annotation const& get(ASTNode const& _node) const;
|
||||
typename Step::GlobalAnnotation const& get() const;
|
||||
};
|
||||
}
|
||||
|
||||
class Analysis
|
||||
{
|
||||
struct AnnotationContainer;
|
||||
struct GlobalAnnotationContainer;
|
||||
public:
|
||||
Analysis(langutil::ErrorReporter& _errorReporter, uint64_t _maxAstId);
|
||||
Analysis(Analysis const&) = delete;
|
||||
@ -79,13 +82,26 @@ public:
|
||||
{
|
||||
return detail::ConstAnnotationFetcher<Step>{*this}.get(_node);
|
||||
}
|
||||
template<typename Step>
|
||||
typename Step::GlobalAnnotation& annotation()
|
||||
{
|
||||
return detail::AnnotationFetcher<Step>{*this}.get();
|
||||
}
|
||||
template<typename Step>
|
||||
typename Step::GlobalAnnotation const& annotation() const
|
||||
{
|
||||
return detail::ConstAnnotationFetcher<Step>{*this}.get();
|
||||
}
|
||||
AnnotationContainer& annotationContainer(ASTNode const& _node);
|
||||
AnnotationContainer const& annotationContainer(ASTNode const& _node) const;
|
||||
GlobalAnnotationContainer& annotationContainer() { return *m_globalAnnotation; }
|
||||
GlobalAnnotationContainer const& annotationContainer() const { return *m_globalAnnotation; }
|
||||
private:
|
||||
langutil::ErrorReporter& m_errorReporter;
|
||||
TypeSystem m_typeSystem;
|
||||
uint64_t m_maxAstId = 0;
|
||||
std::unique_ptr<AnnotationContainer[]> m_annotations;
|
||||
std::unique_ptr<GlobalAnnotationContainer> m_globalAnnotation;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -80,8 +80,6 @@ bool SyntaxRestrictor::visit(FunctionDefinition const& _functionDefinition)
|
||||
|
||||
bool SyntaxRestrictor::visit(VariableDeclarationStatement const& _variableDeclarationStatement)
|
||||
{
|
||||
if (_variableDeclarationStatement.initialValue())
|
||||
m_errorReporter.syntaxError(0000_error, _variableDeclarationStatement.initialValue()->location(), "Variable declarations with initial value not supported.");
|
||||
if (_variableDeclarationStatement.declarations().size() == 1)
|
||||
{
|
||||
if (!_variableDeclarationStatement.declarations().front())
|
||||
|
@ -58,6 +58,7 @@ private:
|
||||
bool visit(BinaryOperation const&) override { return true; }
|
||||
bool visit(ElementaryTypeNameExpression const&) override { return true; }
|
||||
bool visit(TupleExpression const&) override { return true; }
|
||||
bool visit(Literal const&) override { return true; }
|
||||
|
||||
langutil::ErrorReporter& m_errorReporter;
|
||||
};
|
||||
|
@ -18,17 +18,23 @@
|
||||
|
||||
|
||||
#include <libsolidity/analysis/experimental/TypeInference.h>
|
||||
#include <libsolidity/analysis/experimental/TypeRegistration.h>
|
||||
#include <libsolidity/analysis/experimental/Analysis.h>
|
||||
#include <libsolidity/ast/experimental/TypeSystemHelper.h>
|
||||
|
||||
#include <libsolutil/Numeric.h>
|
||||
#include <libsolutil/StringUtils.h>
|
||||
#include <liblangutil/Exceptions.h>
|
||||
|
||||
#include <libyul/AsmAnalysis.h>
|
||||
#include <libyul/AsmAnalysisInfo.h>
|
||||
#include <libyul/AST.h>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <range/v3/view/transform.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity;
|
||||
using namespace solidity::frontend;
|
||||
using namespace solidity::frontend::experimental;
|
||||
using namespace solidity::langutil;
|
||||
@ -128,36 +134,75 @@ bool TypeInference::visitNode(ASTNode const& _node)
|
||||
bool TypeInference::visit(TypeClassDefinition const& _typeClassDefinition)
|
||||
{
|
||||
solAssert(m_expressionContext == ExpressionContext::Term);
|
||||
auto& typeVariableAnnotation = annotation(_typeClassDefinition.typeVariable());
|
||||
if (typeVariableAnnotation.type)
|
||||
auto& typeClassAnnotation = annotation(_typeClassDefinition);
|
||||
if (typeClassAnnotation.type)
|
||||
return false;
|
||||
m_typeSystem.declareTypeConstructor(&_typeClassDefinition, _typeClassDefinition.name(), 0);
|
||||
typeClassAnnotation.type = TypeConstant{&_typeClassDefinition, {}};
|
||||
auto& typeVariableAnnotation = annotation(_typeClassDefinition.typeVariable());
|
||||
{
|
||||
ScopedSaveAndRestore expressionContext{m_expressionContext, ExpressionContext::Type};
|
||||
_typeClassDefinition.typeVariable().accept(*this);
|
||||
}
|
||||
solAssert(typeVariableAnnotation.type);
|
||||
|
||||
for (auto const& subNode: _typeClassDefinition.subNodes())
|
||||
map<string, Type> functionTypes;
|
||||
|
||||
Type typeVar = m_typeSystem.freshTypeVariable(false, {});
|
||||
|
||||
auto& typeMembers = annotation().members[&_typeClassDefinition];
|
||||
|
||||
for (auto subNode: _typeClassDefinition.subNodes())
|
||||
{
|
||||
subNode->accept(*this);
|
||||
auto const* functionDefinition = dynamic_cast<FunctionDefinition const*>(subNode.get());
|
||||
solAssert(functionDefinition);
|
||||
auto functionDefinitionType = annotation(*functionDefinition).type;
|
||||
solAssert(functionDefinitionType);
|
||||
auto functionType = m_env->fresh(*functionDefinitionType, true);
|
||||
functionTypes[functionDefinition->name()] = functionType;
|
||||
auto typeVars = TypeSystemHelpers{m_typeSystem}.typeVars(functionType);
|
||||
if(typeVars.size() != 1)
|
||||
m_errorReporter.fatalTypeError(0000_error, functionDefinition->location(), "Function in type class may only depend on the type class variable.");
|
||||
unify(typeVars.front(), typeVar);
|
||||
|
||||
if (!typeMembers.emplace(functionDefinition->name(), TypeMember{functionType}).second)
|
||||
m_errorReporter.fatalTypeError(0000_error, functionDefinition->location(), "Function in type class declared multiple times.");
|
||||
}
|
||||
|
||||
if (auto error = m_typeSystem.declareTypeClass(TypeClass{&_typeClassDefinition}, typeVar, std::move(functionTypes)))
|
||||
m_errorReporter.fatalTypeError(0000_error, _typeClassDefinition.location(), *error);
|
||||
|
||||
solAssert(typeVariableAnnotation.type);
|
||||
TypeSystemHelpers helper{m_typeSystem};
|
||||
unify(*typeVariableAnnotation.type, helper.kindType(m_typeSystem.freshTypeVariable(false, Sort{{TypeClass{&_typeClassDefinition}}})), _typeClassDefinition.location());
|
||||
|
||||
for (auto instantiation: m_analysis.annotation<TypeRegistration>(_typeClassDefinition).instantiations | ranges::views::values)
|
||||
// TODO: recursion-safety?
|
||||
instantiation->accept(*this);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
experimental::Type TypeInference::fromTypeName(TypeName const& _typeName)
|
||||
optional<TypeConstructor> TypeInference::fromTypeName(TypeName const& _typeName)
|
||||
{
|
||||
if (auto const* elementaryTypeName = dynamic_cast<ElementaryTypeName const*>(&_typeName))
|
||||
{
|
||||
switch(elementaryTypeName->typeName().token())
|
||||
{
|
||||
case Token::Word:
|
||||
return m_wordType;
|
||||
case Token::Void:
|
||||
return m_voidType;
|
||||
return BuiltinType::Void;
|
||||
case Token::Fun:
|
||||
return BuiltinType::Function;
|
||||
case Token::Unit:
|
||||
return BuiltinType::Unit;
|
||||
case Token::Pair:
|
||||
return BuiltinType::Pair;
|
||||
case Token::Word:
|
||||
return BuiltinType::Word;
|
||||
case Token::Integer:
|
||||
return m_integerType;
|
||||
return BuiltinType::Integer;
|
||||
default:
|
||||
m_errorReporter.typeError(0000_error, _typeName.location(), "Only elementary types are supported.");
|
||||
break;
|
||||
@ -188,17 +233,19 @@ experimental::Type TypeInference::fromTypeName(TypeName const& _typeName)
|
||||
}
|
||||
*/
|
||||
|
||||
void TypeInference::unify(Type _a, Type _b, langutil::SourceLocation _location)
|
||||
void TypeInference::unify(Type _a, Type _b, langutil::SourceLocation _location, TypeEnvironment* _env)
|
||||
{
|
||||
for (auto failure: m_env->unify(_a, _b))
|
||||
if (!_env)
|
||||
_env = m_env;
|
||||
for (auto failure: _env->unify(_a, _b))
|
||||
std::visit(util::GenericVisitor{
|
||||
[&](TypeEnvironment::TypeMismatch _typeMismatch) {
|
||||
m_errorReporter.typeError(0000_error, _location, fmt::format("Cannot unify {} and {}.", m_env->typeToString(_typeMismatch.a), m_env->typeToString(_typeMismatch.b)));
|
||||
m_errorReporter.typeError(0000_error, _location, fmt::format("Cannot unify {} and {}.", _env->typeToString(_typeMismatch.a), _env->typeToString(_typeMismatch.b)));
|
||||
},
|
||||
[&](TypeEnvironment::SortMismatch _sortMismatch) {
|
||||
m_errorReporter.typeError(0000_error, _location, fmt::format(
|
||||
"{} does not have sort {}",
|
||||
m_env->typeToString(_sortMismatch.type),
|
||||
_env->typeToString(_sortMismatch.type),
|
||||
TypeSystemHelpers{m_typeSystem}.sortToString(_sortMismatch.sort)
|
||||
));
|
||||
}
|
||||
@ -276,8 +323,8 @@ bool TypeInference::visit(ElementaryTypeNameExpression const& _expression)
|
||||
break;
|
||||
case Token::Pair:
|
||||
{
|
||||
auto leftType = m_typeSystem.freshTypeVariable(true, {});
|
||||
auto rightType = m_typeSystem.freshTypeVariable(true, {});
|
||||
auto leftType = m_typeSystem.freshTypeVariable(false, {});
|
||||
auto rightType = m_typeSystem.freshTypeVariable(false, {});
|
||||
expressionAnnotation.type =
|
||||
helper.functionType(
|
||||
helper.kindType(helper.tupleType({leftType, rightType})),
|
||||
@ -287,8 +334,8 @@ bool TypeInference::visit(ElementaryTypeNameExpression const& _expression)
|
||||
}
|
||||
case Token::Fun:
|
||||
{
|
||||
auto argType = m_typeSystem.freshTypeVariable(true, {});
|
||||
auto resultType = m_typeSystem.freshTypeVariable(true, {});
|
||||
auto argType = m_typeSystem.freshTypeVariable(false, {});
|
||||
auto resultType = m_typeSystem.freshTypeVariable(false, {});
|
||||
expressionAnnotation.type =
|
||||
helper.functionType(
|
||||
helper.kindType(helper.tupleType({argType, resultType})),
|
||||
@ -313,9 +360,30 @@ bool TypeInference::visit(BinaryOperation const& _binaryOperation)
|
||||
switch (m_expressionContext)
|
||||
{
|
||||
case ExpressionContext::Term:
|
||||
m_errorReporter.typeError(0000_error, _binaryOperation.location(), "Binary operations in term context not yet supported.");
|
||||
operationAnnotation.type = m_typeSystem.freshTypeVariable(false, {});
|
||||
return false;
|
||||
if (auto* operatorInfo = util::valueOrNullptr(m_analysis.annotation<TypeRegistration>().operators, _binaryOperation.getOperator()))
|
||||
{
|
||||
auto [typeClass, functionName] = *operatorInfo;
|
||||
Type functionType = m_env->fresh(m_typeSystem.typeClassInfo(typeClass)->functions.at(functionName), true);
|
||||
|
||||
_binaryOperation.leftExpression().accept(*this);
|
||||
solAssert(leftAnnotation.type);
|
||||
_binaryOperation.rightExpression().accept(*this);
|
||||
solAssert(rightAnnotation.type);
|
||||
|
||||
Type argTuple = helper.tupleType({*leftAnnotation.type, *rightAnnotation.type});
|
||||
Type genericFunctionType = helper.functionType(argTuple, m_typeSystem.freshTypeVariable(false, {}));
|
||||
unify(functionType, genericFunctionType, _binaryOperation.location());
|
||||
|
||||
operationAnnotation.type = m_env->resolve(std::get<1>(helper.destFunctionType(m_env->resolve(genericFunctionType))));
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_errorReporter.typeError(0000_error, _binaryOperation.location(), "Binary operations in term context not yet supported.");
|
||||
operationAnnotation.type = m_typeSystem.freshTypeVariable(false, {});
|
||||
return false;
|
||||
}
|
||||
case ExpressionContext::Type:
|
||||
if (_binaryOperation.getOperator() == Token::Colon)
|
||||
{
|
||||
@ -361,6 +429,24 @@ bool TypeInference::visit(BinaryOperation const& _binaryOperation)
|
||||
return false;
|
||||
}
|
||||
|
||||
void TypeInference::endVisit(VariableDeclarationStatement const& _variableDeclarationStatement)
|
||||
{
|
||||
solAssert(m_expressionContext == ExpressionContext::Term);
|
||||
if (_variableDeclarationStatement.declarations().size () != 1)
|
||||
{
|
||||
m_errorReporter.typeError(0000_error, _variableDeclarationStatement.location(), "Multi variable declaration not supported.");
|
||||
return;
|
||||
}
|
||||
auto& variableAnnotation = annotation(*_variableDeclarationStatement.declarations().front());
|
||||
solAssert(variableAnnotation.type);
|
||||
if (_variableDeclarationStatement.initialValue())
|
||||
{
|
||||
auto& expressionAnnotation = annotation(*_variableDeclarationStatement.initialValue());
|
||||
solAssert(expressionAnnotation.type);
|
||||
unify(*variableAnnotation.type, *expressionAnnotation.type, _variableDeclarationStatement.location());
|
||||
}
|
||||
}
|
||||
|
||||
bool TypeInference::visit(VariableDeclaration const& _variableDeclaration)
|
||||
{
|
||||
solAssert(!_variableDeclaration.value());
|
||||
@ -390,9 +476,16 @@ bool TypeInference::visit(VariableDeclaration const& _variableDeclaration)
|
||||
variableAnnotation.type = m_typeSystem.freshTypeVariable(false, {});
|
||||
return false;
|
||||
case ExpressionContext::Type:
|
||||
if (_variableDeclaration.typeExpression())
|
||||
m_errorReporter.typeError(0000_error, _variableDeclaration.location(), "Variable declaration in type context with type expression.");
|
||||
variableAnnotation.type = helper.kindType(m_typeSystem.freshTypeVariable(false, {}));
|
||||
if (_variableDeclaration.typeExpression())
|
||||
{
|
||||
ScopedSaveAndRestore expressionContext{m_expressionContext, ExpressionContext::Sort};
|
||||
_variableDeclaration.typeExpression()->accept(*this);
|
||||
auto& typeExpressionAnnotation = annotation(*_variableDeclaration.typeExpression());
|
||||
solAssert(typeExpressionAnnotation.type);
|
||||
|
||||
unify(*variableAnnotation.type, *typeExpressionAnnotation.type, _variableDeclaration.typeExpression()->location());
|
||||
}
|
||||
return false;
|
||||
case ExpressionContext::Sort:
|
||||
m_errorReporter.typeError(0000_error, _variableDeclaration.location(), "Variable declaration in sort context.");
|
||||
@ -432,102 +525,131 @@ TypeInference::Annotation& TypeInference::annotation(ASTNode const& _node)
|
||||
return m_analysis.annotation<TypeInference>(_node);
|
||||
}
|
||||
|
||||
bool TypeInference::visit(Identifier const& _identifier)
|
||||
TypeInference::GlobalAnnotation& TypeInference::annotation()
|
||||
{
|
||||
auto& identifierAnnotation = annotation(_identifier);
|
||||
solAssert(!identifierAnnotation.type);
|
||||
|
||||
auto const* referencedDeclaration = _identifier.annotation().referencedDeclaration;
|
||||
return m_analysis.annotation<TypeInference>();
|
||||
}
|
||||
|
||||
experimental::Type TypeInference::handleIdentifierByReferencedDeclaration(langutil::SourceLocation _location, Declaration const& _declaration)
|
||||
{
|
||||
TypeSystemHelpers helper{m_typeSystem};
|
||||
switch(m_expressionContext)
|
||||
{
|
||||
case ExpressionContext::Term:
|
||||
{
|
||||
solAssert(referencedDeclaration);
|
||||
|
||||
if (
|
||||
!dynamic_cast<FunctionDefinition const*>(referencedDeclaration) &&
|
||||
!dynamic_cast<VariableDeclaration const*>(referencedDeclaration)
|
||||
!dynamic_cast<FunctionDefinition const*>(&_declaration) &&
|
||||
!dynamic_cast<VariableDeclaration const*>(&_declaration) &&
|
||||
!dynamic_cast<TypeClassDefinition const*>(&_declaration) &&
|
||||
!dynamic_cast<TypeDefinition const*>(&_declaration)
|
||||
)
|
||||
{
|
||||
SecondarySourceLocation ssl;
|
||||
ssl.append("Referenced node.", referencedDeclaration->location());
|
||||
m_errorReporter.fatalTypeError(0000_error, _identifier.location(), ssl, "Attempt to type identifier referring to unexpected node.");
|
||||
ssl.append("Referenced node.", _declaration.location());
|
||||
m_errorReporter.fatalTypeError(0000_error, _location, ssl, "Attempt to type identifier referring to unexpected node.");
|
||||
}
|
||||
|
||||
auto& declarationAnnotation = annotation(*referencedDeclaration);
|
||||
auto& declarationAnnotation = annotation(_declaration);
|
||||
if (!declarationAnnotation.type)
|
||||
referencedDeclaration->accept(*this);
|
||||
_declaration.accept(*this);
|
||||
|
||||
solAssert(declarationAnnotation.type);
|
||||
|
||||
if (dynamic_cast<FunctionDefinition const*>(referencedDeclaration))
|
||||
identifierAnnotation.type = m_env->fresh(*declarationAnnotation.type, true);
|
||||
else if (dynamic_cast<VariableDeclaration const*>(referencedDeclaration))
|
||||
identifierAnnotation.type = declarationAnnotation.type;
|
||||
if (dynamic_cast<FunctionDefinition const*>(&_declaration))
|
||||
return m_env->fresh(*declarationAnnotation.type, true);
|
||||
else if (dynamic_cast<VariableDeclaration const*>(&_declaration))
|
||||
return *declarationAnnotation.type;
|
||||
else if (dynamic_cast<TypeClassDefinition const*>(&_declaration))
|
||||
return *declarationAnnotation.type;
|
||||
else if (dynamic_cast<TypeDefinition const*>(&_declaration))
|
||||
return *declarationAnnotation.type;
|
||||
else
|
||||
solAssert(false);
|
||||
break;
|
||||
}
|
||||
case ExpressionContext::Type:
|
||||
{
|
||||
if (referencedDeclaration)
|
||||
if (
|
||||
!dynamic_cast<VariableDeclaration const*>(&_declaration) &&
|
||||
!dynamic_cast<TypeDefinition const*>(&_declaration)
|
||||
)
|
||||
{
|
||||
if (
|
||||
!dynamic_cast<VariableDeclaration const*>(referencedDeclaration) &&
|
||||
!dynamic_cast<TypeDefinition const*>(referencedDeclaration)
|
||||
)
|
||||
{
|
||||
SecondarySourceLocation ssl;
|
||||
ssl.append("Referenced node.", referencedDeclaration->location());
|
||||
m_errorReporter.fatalTypeError(0000_error, _identifier.location(), ssl, "Attempt to type identifier referring to unexpected node.");
|
||||
}
|
||||
SecondarySourceLocation ssl;
|
||||
ssl.append("Referenced node.", _declaration.location());
|
||||
m_errorReporter.fatalTypeError(0000_error, _location, ssl, "Attempt to type identifier referring to unexpected node.");
|
||||
}
|
||||
|
||||
// TODO: Assert that this is a type class variable declaration.
|
||||
auto& declarationAnnotation = annotation(*referencedDeclaration);
|
||||
if (!declarationAnnotation.type)
|
||||
referencedDeclaration->accept(*this);
|
||||
// TODO: Assert that this is a type class variable declaration.
|
||||
auto& declarationAnnotation = annotation(_declaration);
|
||||
if (!declarationAnnotation.type)
|
||||
_declaration.accept(*this);
|
||||
|
||||
solAssert(declarationAnnotation.type);
|
||||
solAssert(declarationAnnotation.type);
|
||||
|
||||
if (dynamic_cast<VariableDeclaration const*>(referencedDeclaration))
|
||||
{
|
||||
// TODO: helper.destKindType(*declarationAnnotation.type);
|
||||
identifierAnnotation.type = declarationAnnotation.type;
|
||||
}
|
||||
else if (dynamic_cast<TypeDefinition const*>(referencedDeclaration))
|
||||
{
|
||||
// TODO: helper.destKindType(*declarationAnnotation.type);
|
||||
identifierAnnotation.type = m_env->fresh(*declarationAnnotation.type, true);
|
||||
}
|
||||
else
|
||||
solAssert(false);
|
||||
if (dynamic_cast<VariableDeclaration const*>(&_declaration))
|
||||
{
|
||||
// TODO: helper.destKindType(*declarationAnnotation.type);
|
||||
return *declarationAnnotation.type;
|
||||
}
|
||||
else if (dynamic_cast<TypeDefinition const*>(&_declaration))
|
||||
{
|
||||
// TODO: helper.destKindType(*declarationAnnotation.type);
|
||||
return m_env->fresh(*declarationAnnotation.type, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: register free type variable name!
|
||||
identifierAnnotation.type = helper.kindType(m_typeSystem.freshTypeVariable(false, {}));
|
||||
return false;
|
||||
}
|
||||
solAssert(false);
|
||||
break;
|
||||
}
|
||||
case ExpressionContext::Sort:
|
||||
{
|
||||
solAssert(referencedDeclaration);
|
||||
|
||||
auto const* typeClass = dynamic_cast<TypeClassDefinition const*>(referencedDeclaration);
|
||||
if (
|
||||
!dynamic_cast<TypeClassDefinition const*>(referencedDeclaration)
|
||||
)
|
||||
m_errorReporter.fatalTypeError(0000_error, _identifier.location(), "Expected type class.");
|
||||
|
||||
identifierAnnotation.type = helper.kindType(m_typeSystem.freshTypeVariable(false, Sort{{TypeClass{typeClass}}}));
|
||||
if (auto const* typeClass = dynamic_cast<TypeClassDefinition const*>(&_declaration))
|
||||
{
|
||||
ScopedSaveAndRestore expressionContext{m_expressionContext, ExpressionContext::Term};
|
||||
typeClass->accept(*this);
|
||||
return helper.kindType(m_typeSystem.freshTypeVariable(false, Sort{{TypeClass{typeClass}}}));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_errorReporter.typeError(0000_error, _location, "Expected type class.");
|
||||
return helper.kindType(m_typeSystem.freshTypeVariable(false, {}));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
util::unreachable();
|
||||
}
|
||||
|
||||
return true;
|
||||
bool TypeInference::visit(Identifier const& _identifier)
|
||||
{
|
||||
auto& identifierAnnotation = annotation(_identifier);
|
||||
solAssert(!identifierAnnotation.type);
|
||||
|
||||
if (auto const* referencedDeclaration = _identifier.annotation().referencedDeclaration)
|
||||
{
|
||||
identifierAnnotation.type = handleIdentifierByReferencedDeclaration(_identifier.location(), *referencedDeclaration);
|
||||
return false;
|
||||
}
|
||||
|
||||
TypeSystemHelpers helper{m_typeSystem};
|
||||
switch(m_expressionContext)
|
||||
{
|
||||
case ExpressionContext::Term:
|
||||
// TODO: error handling
|
||||
solAssert(false);
|
||||
break;
|
||||
case ExpressionContext::Type:
|
||||
{
|
||||
// TODO: register free type variable name!
|
||||
identifierAnnotation.type = helper.kindType(m_typeSystem.freshTypeVariable(false, {}));
|
||||
return false;
|
||||
}
|
||||
case ExpressionContext::Sort:
|
||||
// TODO: error handling
|
||||
solAssert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void TypeInference::endVisit(TupleExpression const& _tupleExpression)
|
||||
@ -575,45 +697,107 @@ void TypeInference::endVisit(TupleExpression const& _tupleExpression)
|
||||
}
|
||||
}
|
||||
|
||||
bool TypeInference::visit(IdentifierPath const&)
|
||||
bool TypeInference::visit(IdentifierPath const& _identifierPath)
|
||||
{
|
||||
auto& identifierAnnotation = annotation(_identifierPath);
|
||||
solAssert(!identifierAnnotation.type);
|
||||
|
||||
if (auto const* referencedDeclaration = _identifierPath.annotation().referencedDeclaration)
|
||||
{
|
||||
identifierAnnotation.type = handleIdentifierByReferencedDeclaration(_identifierPath.location(), *referencedDeclaration);
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: error handling
|
||||
solAssert(false);
|
||||
}
|
||||
|
||||
bool TypeInference::visit(TypeClassInstantiation const& _typeClassInstantiation)
|
||||
{
|
||||
auto const* typeClass = dynamic_cast<TypeClassDefinition const*>(_typeClassInstantiation.typeClass().annotation().referencedDeclaration);
|
||||
auto& instantiationAnnotation = annotation(_typeClassInstantiation);
|
||||
if (instantiationAnnotation.type)
|
||||
return false;
|
||||
instantiationAnnotation.type = m_voidType;
|
||||
std::optional<TypeClass> typeClass = std::visit(util::GenericVisitor{
|
||||
[&](ASTPointer<IdentifierPath> _typeClassName) -> std::optional<TypeClass> {
|
||||
if (auto const* typeClass = dynamic_cast<TypeClassDefinition const*>(_typeClassName->annotation().referencedDeclaration))
|
||||
{
|
||||
auto const* typeClassInfo = m_typeSystem.typeClassInfo(TypeClass{typeClass});
|
||||
if (!typeClassInfo)
|
||||
{
|
||||
// visiting the type class will re-visit this instantiation
|
||||
typeClass->accept(*this);
|
||||
}
|
||||
return TypeClass{typeClass};
|
||||
}
|
||||
else
|
||||
{
|
||||
m_errorReporter.typeError(0000_error, _typeClassInstantiation.typeClass().location(), "Expected type class.");
|
||||
return nullopt;
|
||||
}
|
||||
},
|
||||
[&](Token _token) -> std::optional<TypeClass> {
|
||||
if (auto typeClass = typeClassFromToken(_token))
|
||||
return typeClass;
|
||||
else
|
||||
{
|
||||
m_errorReporter.typeError(0000_error, _typeClassInstantiation.location(), "Invalid type class name.");
|
||||
return nullopt;
|
||||
}
|
||||
}
|
||||
}, _typeClassInstantiation.typeClass().name());
|
||||
if (!typeClass)
|
||||
m_errorReporter.fatalTypeError(0000_error, _typeClassInstantiation.typeClass().location(), "Expected type class.");
|
||||
typeClass->accept(*this);
|
||||
return false;
|
||||
|
||||
auto typeConstructor = typeConstructorFromTypeName(_typeClassInstantiation.typeConstructor());
|
||||
if (!typeConstructor)
|
||||
{
|
||||
m_errorReporter.typeError(0000_error, _typeClassInstantiation.typeConstructor().location(), "Invalid type constructor.");
|
||||
return false;
|
||||
}
|
||||
|
||||
vector<Type> arguments;
|
||||
Arity arity{
|
||||
{},
|
||||
*typeClass
|
||||
};
|
||||
|
||||
{
|
||||
ScopedSaveAndRestore expressionContext{m_expressionContext, ExpressionContext::Type};
|
||||
if (_typeClassInstantiation.argumentSorts())
|
||||
{
|
||||
_typeClassInstantiation.argumentSorts()->accept(*this);
|
||||
auto& argumentSortAnnotation = annotation(*_typeClassInstantiation.argumentSorts());
|
||||
solAssert(argumentSortAnnotation.type);
|
||||
arguments = TypeSystemHelpers{m_typeSystem}.destTupleType(*argumentSortAnnotation.type);
|
||||
for (auto& argument: arguments)
|
||||
argument = TypeSystemHelpers{m_typeSystem}.destKindType(argument);
|
||||
arity.argumentSorts = arguments | ranges::views::transform([&](Type _type) {
|
||||
return m_env->sort(_type);
|
||||
}) | ranges::to<vector<Sort>>;
|
||||
}
|
||||
}
|
||||
|
||||
Type type{TypeConstant{*typeConstructor, arguments}};
|
||||
|
||||
map<string, Type> functionTypes;
|
||||
|
||||
Type typeVar = m_typeSystem.freshTypeVariable(false, {});
|
||||
|
||||
for (auto subNode: typeClass->subNodes())
|
||||
{
|
||||
auto const* functionDefinition = dynamic_cast<FunctionDefinition const*>(subNode.get());
|
||||
solAssert(functionDefinition);
|
||||
auto functionType = annotation(*functionDefinition).type;
|
||||
solAssert(functionType);
|
||||
functionTypes[functionDefinition->name()] = m_env->fresh(*functionType, true);
|
||||
auto typeVars = TypeSystemHelpers{m_typeSystem}.typeVars(functionTypes[functionDefinition->name()]);
|
||||
solAssert(typeVars.size() == 1);
|
||||
unify(typeVars.front(), typeVar);
|
||||
}
|
||||
for (auto subNode: _typeClassInstantiation.subNodes())
|
||||
{
|
||||
auto const* functionDefinition = dynamic_cast<FunctionDefinition const*>(subNode.get());
|
||||
solAssert(functionDefinition);
|
||||
Type* expectedFunctionType = util::valueOrNullptr(functionTypes, functionDefinition->name());
|
||||
if (!expectedFunctionType)
|
||||
{
|
||||
m_errorReporter.typeError(0000_error, functionDefinition->location(), "Function definition during instantiation that does not belong to the class.");
|
||||
continue;
|
||||
}
|
||||
subNode->accept(*this);
|
||||
solAssert(annotation(*functionDefinition).type);
|
||||
functionTypes[functionDefinition->name()] = *annotation(*functionDefinition).type;
|
||||
}
|
||||
|
||||
|
||||
if (auto error = m_typeSystem.instantiateClass(type, arity, std::move(functionTypes)))
|
||||
m_errorReporter.typeError(0000_error, _typeClassInstantiation.location(), *error);
|
||||
/*
|
||||
TypeEnvironment newEnv = m_env->clone();
|
||||
|
||||
|
||||
for (auto subNode: _typeClassInstantiation.subNodes())
|
||||
{
|
||||
auto const* functionDefinition = dynamic_cast<FunctionDefinition const*>(subNode.get());
|
||||
@ -628,10 +812,41 @@ bool TypeInference::visit(TypeClassInstantiation const& _typeClassInstantiation)
|
||||
}
|
||||
if (!functionTypes.empty())
|
||||
m_errorReporter.typeError(0000_error, _typeClassInstantiation.location(), "Type class instantiation does not implement all required functions.");
|
||||
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
void TypeInference::endVisit(MemberAccess const& _memberAccess)
|
||||
{
|
||||
auto &memberAccessAnnotation = annotation(_memberAccess);
|
||||
solAssert(!memberAccessAnnotation.type);
|
||||
auto& expressionAnnotation = annotation(_memberAccess.expression());
|
||||
solAssert(expressionAnnotation.type);
|
||||
TypeSystemHelpers helper{m_typeSystem};
|
||||
if (helper.isTypeConstant(*expressionAnnotation.type))
|
||||
{
|
||||
Type expressionType = *expressionAnnotation.type;
|
||||
// TODO: unify this, s.t. this is always or never a kind type.
|
||||
if (helper.isKindType(expressionType))
|
||||
expressionType = helper.destKindType(expressionType);
|
||||
auto constructor = std::get<0>(helper.destTypeConstant(expressionType));
|
||||
if (auto* typeMember = util::valueOrNullptr(annotation().members.at(constructor), _memberAccess.memberName()))
|
||||
{
|
||||
Type type = m_env->fresh(typeMember->type, true);
|
||||
annotation(_memberAccess).type = type;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_errorReporter.typeError(0000_error, _memberAccess.memberLocation(), "Member not found.");
|
||||
annotation(_memberAccess).type = m_typeSystem.freshTypeVariable(false, {});
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_errorReporter.typeError(0000_error, _memberAccess.expression().location(), "Unsupported member access expression.");
|
||||
annotation(_memberAccess).type = m_typeSystem.freshTypeVariable(false, {});
|
||||
}
|
||||
|
||||
bool TypeInference::visit(MemberAccess const& _memberAccess)
|
||||
{
|
||||
if (m_expressionContext != ExpressionContext::Term)
|
||||
@ -639,8 +854,10 @@ bool TypeInference::visit(MemberAccess const& _memberAccess)
|
||||
m_errorReporter.typeError(0000_error, _memberAccess.location(), "Member access outside term context.");
|
||||
annotation(_memberAccess).type = m_typeSystem.freshTypeVariable(false, {});
|
||||
return false;
|
||||
|
||||
}
|
||||
return true;
|
||||
/*
|
||||
_memberAccess.expression().accept(*this);
|
||||
if (auto const* identifier = dynamic_cast<Identifier const*>(&_memberAccess.expression()))
|
||||
{
|
||||
auto const* declaration = identifier->annotation().referencedDeclaration;
|
||||
@ -675,19 +892,25 @@ bool TypeInference::visit(MemberAccess const& _memberAccess)
|
||||
else
|
||||
m_errorReporter.fatalTypeError(0000_error, _memberAccess.location(), "Member access to non-identifier.");
|
||||
|
||||
return false;
|
||||
return false;*/
|
||||
}
|
||||
|
||||
bool TypeInference::visit(TypeDefinition const& _typeDefinition)
|
||||
{
|
||||
TypeSystemHelpers helper{m_typeSystem};
|
||||
auto& typeDefinitionAnnotation = annotation(_typeDefinition);
|
||||
if (typeDefinitionAnnotation.type)
|
||||
return false;
|
||||
|
||||
std::optional<Type> underlyingType;
|
||||
if (_typeDefinition.typeExpression())
|
||||
{
|
||||
ScopedSaveAndRestore expressionContext{m_expressionContext, ExpressionContext::Type};
|
||||
_typeDefinition.typeExpression()->accept(*this);
|
||||
underlyingType = annotation(*_typeDefinition.typeExpression()).type;
|
||||
// TODO: settle the kind type mess.
|
||||
if (underlyingType && helper.isKindType(*underlyingType))
|
||||
underlyingType = helper.destKindType(*underlyingType);
|
||||
}
|
||||
|
||||
vector<Type> arguments;
|
||||
@ -695,15 +918,24 @@ bool TypeInference::visit(TypeDefinition const& _typeDefinition)
|
||||
for (size_t i = 0; i < _typeDefinition.arguments()->parameters().size(); ++i)
|
||||
arguments.emplace_back(m_typeSystem.freshTypeVariable(true, {}));
|
||||
|
||||
TypeSystemHelpers helper{m_typeSystem};
|
||||
Type type = m_typeSystem.type(TypeConstructor{&_typeDefinition}, arguments);
|
||||
if (arguments.empty())
|
||||
typeDefinitionAnnotation.type = helper.kindType(m_typeSystem.type(TypeConstructor{&_typeDefinition}, arguments));
|
||||
else
|
||||
typeDefinitionAnnotation.type =
|
||||
helper.functionType(
|
||||
helper.kindType(helper.tupleType(arguments)),
|
||||
helper.kindType(m_typeSystem.type(TypeConstructor{&_typeDefinition}, arguments))
|
||||
helper.kindType(type)
|
||||
);
|
||||
|
||||
auto& typeMembers = annotation().members[&_typeDefinition];
|
||||
|
||||
if (underlyingType)
|
||||
{
|
||||
typeMembers.emplace("abs", TypeMember{helper.functionType(*underlyingType, type)});
|
||||
typeMembers.emplace("rep", TypeMember{helper.functionType(type, *underlyingType)});
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -751,7 +983,7 @@ void TypeInference::endVisit(FunctionCall const& _functionCall)
|
||||
{
|
||||
Type argTuple = helper.tupleType(argTypes);
|
||||
Type genericFunctionType = helper.functionType(argTuple, m_typeSystem.freshTypeVariable(false, {}));
|
||||
unify(genericFunctionType, functionType, _functionCall.location());
|
||||
unify(functionType, genericFunctionType, _functionCall.location());
|
||||
|
||||
functionCallAnnotation.type = m_env->resolve(std::get<1>(helper.destFunctionType(m_env->resolve(genericFunctionType))));
|
||||
break;
|
||||
@ -760,7 +992,7 @@ void TypeInference::endVisit(FunctionCall const& _functionCall)
|
||||
{
|
||||
Type argTuple = helper.kindType(helper.tupleType(argTypes));
|
||||
Type genericFunctionType = helper.functionType(argTuple, m_typeSystem.freshKindVariable(false, {}));
|
||||
unify(genericFunctionType, functionType, _functionCall.location());
|
||||
unify(functionType, genericFunctionType, _functionCall.location());
|
||||
|
||||
functionCallAnnotation.type = m_env->resolve(std::get<1>(helper.destFunctionType(m_env->resolve(genericFunctionType))));
|
||||
break;
|
||||
@ -768,6 +1000,182 @@ void TypeInference::endVisit(FunctionCall const& _functionCall)
|
||||
case ExpressionContext::Sort:
|
||||
solAssert(false);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// TODO: clean up rational parsing
|
||||
namespace
|
||||
{
|
||||
|
||||
optional<rational> parseRational(string const& _value)
|
||||
{
|
||||
rational value;
|
||||
try
|
||||
{
|
||||
auto radixPoint = find(_value.begin(), _value.end(), '.');
|
||||
|
||||
if (radixPoint != _value.end())
|
||||
{
|
||||
if (
|
||||
!all_of(radixPoint + 1, _value.end(), util::isDigit) ||
|
||||
!all_of(_value.begin(), radixPoint, util::isDigit)
|
||||
)
|
||||
return nullopt;
|
||||
|
||||
// Only decimal notation allowed here, leading zeros would switch to octal.
|
||||
auto fractionalBegin = find_if_not(
|
||||
radixPoint + 1,
|
||||
_value.end(),
|
||||
[](char const& a) { return a == '0'; }
|
||||
);
|
||||
|
||||
rational numerator;
|
||||
rational denominator(1);
|
||||
|
||||
denominator = bigint(string(fractionalBegin, _value.end()));
|
||||
denominator /= boost::multiprecision::pow(
|
||||
bigint(10),
|
||||
static_cast<unsigned>(distance(radixPoint + 1, _value.end()))
|
||||
);
|
||||
numerator = bigint(string(_value.begin(), radixPoint));
|
||||
value = numerator + denominator;
|
||||
}
|
||||
else
|
||||
value = bigint(_value);
|
||||
return value;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether _mantissa * (10 ** _expBase10) fits into 4096 bits.
|
||||
bool fitsPrecisionBase10(bigint const& _mantissa, uint32_t _expBase10)
|
||||
{
|
||||
double const log2Of10AwayFromZero = 3.3219280948873624;
|
||||
return fitsPrecisionBaseX(_mantissa, log2Of10AwayFromZero, _expBase10);
|
||||
}
|
||||
|
||||
optional<rational> rationalValue(Literal const& _literal)
|
||||
{
|
||||
rational value;
|
||||
try
|
||||
{
|
||||
ASTString valueString = _literal.valueWithoutUnderscores();
|
||||
|
||||
auto expPoint = find(valueString.begin(), valueString.end(), 'e');
|
||||
if (expPoint == valueString.end())
|
||||
expPoint = find(valueString.begin(), valueString.end(), 'E');
|
||||
|
||||
if (boost::starts_with(valueString, "0x"))
|
||||
{
|
||||
// process as hex
|
||||
value = bigint(valueString);
|
||||
}
|
||||
else if (expPoint != valueString.end())
|
||||
{
|
||||
// Parse mantissa and exponent. Checks numeric limit.
|
||||
optional<rational> mantissa = parseRational(string(valueString.begin(), expPoint));
|
||||
|
||||
if (!mantissa)
|
||||
return nullopt;
|
||||
value = *mantissa;
|
||||
|
||||
// 0E... is always zero.
|
||||
if (value == 0)
|
||||
return nullopt;
|
||||
|
||||
bigint exp = bigint(string(expPoint + 1, valueString.end()));
|
||||
|
||||
if (exp > numeric_limits<int32_t>::max() || exp < numeric_limits<int32_t>::min())
|
||||
return nullopt;
|
||||
|
||||
uint32_t expAbs = bigint(abs(exp)).convert_to<uint32_t>();
|
||||
|
||||
if (exp < 0)
|
||||
{
|
||||
if (!fitsPrecisionBase10(abs(value.denominator()), expAbs))
|
||||
return nullopt;
|
||||
value /= boost::multiprecision::pow(
|
||||
bigint(10),
|
||||
expAbs
|
||||
);
|
||||
}
|
||||
else if (exp > 0)
|
||||
{
|
||||
if (!fitsPrecisionBase10(abs(value.numerator()), expAbs))
|
||||
return nullopt;
|
||||
value *= boost::multiprecision::pow(
|
||||
bigint(10),
|
||||
expAbs
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// parse as rational number
|
||||
optional<rational> tmp = parseRational(valueString);
|
||||
if (!tmp)
|
||||
return nullopt;
|
||||
value = *tmp;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return nullopt;
|
||||
}
|
||||
switch (_literal.subDenomination())
|
||||
{
|
||||
case Literal::SubDenomination::None:
|
||||
case Literal::SubDenomination::Wei:
|
||||
case Literal::SubDenomination::Second:
|
||||
break;
|
||||
case Literal::SubDenomination::Gwei:
|
||||
value *= bigint("1000000000");
|
||||
break;
|
||||
case Literal::SubDenomination::Ether:
|
||||
value *= bigint("1000000000000000000");
|
||||
break;
|
||||
case Literal::SubDenomination::Minute:
|
||||
value *= bigint("60");
|
||||
break;
|
||||
case Literal::SubDenomination::Hour:
|
||||
value *= bigint("3600");
|
||||
break;
|
||||
case Literal::SubDenomination::Day:
|
||||
value *= bigint("86400");
|
||||
break;
|
||||
case Literal::SubDenomination::Week:
|
||||
value *= bigint("604800");
|
||||
break;
|
||||
case Literal::SubDenomination::Year:
|
||||
value *= bigint("31536000");
|
||||
break;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
bool TypeInference::visit(Literal const& _literal)
|
||||
{
|
||||
auto& literalAnnotation = annotation(_literal);
|
||||
literalAnnotation.type = m_typeSystem.freshTypeVariable(false, {});
|
||||
if (_literal.token() != Token::Number)
|
||||
{
|
||||
m_errorReporter.typeError(0000_error, _literal.location(), "Only number literals are supported.");
|
||||
return false;
|
||||
}
|
||||
optional<rational> value = rationalValue(_literal);
|
||||
if (!value)
|
||||
{
|
||||
m_errorReporter.typeError(0000_error, _literal.location(), "Invalid number literals.");
|
||||
return false;
|
||||
}
|
||||
if (value->denominator() != 1)
|
||||
{
|
||||
m_errorReporter.typeError(0000_error, _literal.location(), "Only integers are supported.");
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -39,8 +39,17 @@ public:
|
||||
/// Expressions, variable declarations, function declarations.
|
||||
std::optional<Type> type;
|
||||
};
|
||||
struct TypeMember
|
||||
{
|
||||
Type type;
|
||||
};
|
||||
struct GlobalAnnotation
|
||||
{
|
||||
std::map<TypeConstructor, std::map<std::string, TypeMember>> members;
|
||||
};
|
||||
bool visit(Block const&) override { return true; }
|
||||
bool visit(VariableDeclarationStatement const&) override { return true; }
|
||||
void endVisit(VariableDeclarationStatement const& _variableDeclarationStatement) override;
|
||||
bool visit(VariableDeclaration const& _variableDeclaration) override;
|
||||
|
||||
bool visit(FunctionDefinition const& _functionDefinition) override;
|
||||
@ -62,6 +71,7 @@ public:
|
||||
void endVisit(Return const& _return) override;
|
||||
|
||||
bool visit(MemberAccess const& _memberAccess) override;
|
||||
void endVisit(MemberAccess const& _memberAccess) override;
|
||||
bool visit(ElementaryTypeNameExpression const& _expression) override;
|
||||
|
||||
bool visit(TypeClassDefinition const& _typeClassDefinition) override;
|
||||
@ -73,6 +83,8 @@ public:
|
||||
bool visitNode(ASTNode const& _node) override;
|
||||
|
||||
bool visit(BinaryOperation const& _operation) override;
|
||||
|
||||
bool visit(Literal const& _literal) override;
|
||||
private:
|
||||
Analysis& m_analysis;
|
||||
langutil::ErrorReporter& m_errorReporter;
|
||||
@ -85,14 +97,16 @@ private:
|
||||
std::optional<Type> m_currentFunctionType;
|
||||
|
||||
Annotation& annotation(ASTNode const& _node);
|
||||
GlobalAnnotation& annotation();
|
||||
|
||||
void unify(Type _a, Type _b, langutil::SourceLocation _location = {});
|
||||
void unify(Type _a, Type _b, langutil::SourceLocation _location = {}, TypeEnvironment* _env = nullptr);
|
||||
enum class ExpressionContext
|
||||
{
|
||||
Term,
|
||||
Type,
|
||||
Sort
|
||||
};
|
||||
Type handleIdentifierByReferencedDeclaration(langutil::SourceLocation _location, Declaration const& _declaration);
|
||||
ExpressionContext m_expressionContext = ExpressionContext::Term;
|
||||
};
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include <libsolidity/analysis/experimental/TypeRegistration.h>
|
||||
#include <libsolidity/analysis/experimental/Analysis.h>
|
||||
#include <libsolidity/ast/experimental/TypeSystemHelper.h>
|
||||
#include <liblangutil/Exceptions.h>
|
||||
|
||||
#include <libyul/AsmAnalysis.h>
|
||||
@ -43,6 +44,36 @@ m_typeSystem(_analysis.typeSystem())
|
||||
{BuiltinType::Integer, "integer", 0}
|
||||
})
|
||||
m_typeSystem.declareTypeConstructor(type, name, arity);
|
||||
|
||||
auto declareBuiltinClass = [&](BuiltinClass _class, auto _memberCreator, Sort _sort = {}) {
|
||||
Type type = m_typeSystem.freshTypeVariable(false, std::move(_sort));
|
||||
auto error = m_typeSystem.declareTypeClass(
|
||||
TypeClass{_class},
|
||||
type,
|
||||
_memberCreator(type)
|
||||
);
|
||||
solAssert(!error, *error);
|
||||
};
|
||||
TypeSystemHelpers helper{m_typeSystem};
|
||||
using MemberList = std::map<std::string, Type>;
|
||||
|
||||
declareBuiltinClass(BuiltinClass::Integer, [&](Type _typeVar) -> MemberList {
|
||||
return {
|
||||
{
|
||||
"fromInteger",
|
||||
helper.functionType(TypeConstant{{BuiltinType::Integer}, {}}, _typeVar)
|
||||
}
|
||||
};
|
||||
});
|
||||
declareBuiltinClass(BuiltinClass::Mul, [&](Type _typeVar) -> MemberList {
|
||||
return {
|
||||
{
|
||||
"mul",
|
||||
helper.functionType(helper.tupleType({_typeVar, _typeVar}), _typeVar)
|
||||
}
|
||||
};
|
||||
});
|
||||
annotation().operators[Token::Mul] = std::make_tuple(TypeClass{BuiltinClass::Mul}, "mul");
|
||||
}
|
||||
|
||||
bool TypeRegistration::analyze(SourceUnit const& _sourceUnit)
|
||||
@ -51,90 +82,36 @@ bool TypeRegistration::analyze(SourceUnit const& _sourceUnit)
|
||||
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.typeClass().annotation().referencedDeclaration);
|
||||
if (!classDefintion)
|
||||
m_errorReporter.fatalTypeError(0000_error, _typeClassInstantiation.typeClass().location(), "Expected a type class.");
|
||||
classDefintion->accept(*this);
|
||||
|
||||
TypeClass typeClass{classDefintion};
|
||||
|
||||
TypeName const& typeName = _typeClassInstantiation.typeConstructor();
|
||||
|
||||
TypeConstructor typeConstructor = [&]() -> TypeConstructor {
|
||||
if (auto const* elementaryTypeName = dynamic_cast<ElementaryTypeName const*>(&typeName))
|
||||
{
|
||||
switch(elementaryTypeName->typeName().token())
|
||||
{
|
||||
case Token::Word:
|
||||
return BuiltinType::Word;
|
||||
case Token::Void:
|
||||
return BuiltinType::Void;
|
||||
case Token::Integer:
|
||||
return BuiltinType::Integer;
|
||||
case Token::Pair:
|
||||
return BuiltinType::Pair;
|
||||
case Token::Function:
|
||||
return BuiltinType::Function;
|
||||
case Token::Unit:
|
||||
return BuiltinType::Function;
|
||||
default:
|
||||
m_errorReporter.typeError(0000_error, typeName.location(), "Only elementary types are supported.");
|
||||
return BuiltinType::Void;
|
||||
}
|
||||
}
|
||||
else if (auto const* userDefinedType = dynamic_cast<UserDefinedTypeName const*>(&typeName))
|
||||
{
|
||||
if (auto const* referencedDeclaration = userDefinedType->pathNode().annotation().referencedDeclaration)
|
||||
return referencedDeclaration;
|
||||
else
|
||||
{
|
||||
m_errorReporter.typeError(0000_error, userDefinedType->pathNode().location(), "No declaration found for user-defined type name.");
|
||||
return BuiltinType::Void;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_errorReporter.typeError(0000_error, typeName.location(), "Only elementary types are supported.");
|
||||
return BuiltinType::Void;
|
||||
}
|
||||
}();
|
||||
|
||||
Arity arity{
|
||||
{},
|
||||
typeClass
|
||||
};
|
||||
if (_typeClassInstantiation.argumentSorts().size() != m_typeSystem.constructorArguments(typeConstructor))
|
||||
m_errorReporter.fatalTypeError(0000_error, _typeClassInstantiation.location(), "Invalid number of arguments.");
|
||||
|
||||
for (auto argumentSort : _typeClassInstantiation.argumentSorts())
|
||||
optional<TypeClass> typeClass = typeClassFromTypeClassName(_typeClassInstantiation.typeClass());
|
||||
if (!typeClass)
|
||||
{
|
||||
if (auto const* referencedDeclaration = argumentSort->annotation().referencedDeclaration)
|
||||
{
|
||||
if (auto const* typeClassDefinition = dynamic_cast<TypeClassDefinition const*>(referencedDeclaration))
|
||||
// TODO: multi arities
|
||||
arity.argumentSorts.emplace_back(Sort{{TypeClass{typeClassDefinition}}});
|
||||
else
|
||||
m_errorReporter.fatalTypeError(0000_error, argumentSort->location(), "Argument sort has to be a type class.");
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: error Handling
|
||||
m_errorReporter.fatalTypeError(0000_error, argumentSort->location(), "Invalid sort.");
|
||||
}
|
||||
m_errorReporter.typeError(0000_error, _typeClassInstantiation.typeClass().location(), "Expected a type class.");
|
||||
return false;
|
||||
}
|
||||
m_typeSystem.instantiateClass(typeConstructor, arity);
|
||||
|
||||
optional<TypeConstructor> typeConstructor = typeConstructorFromTypeName(_typeClassInstantiation.typeConstructor());
|
||||
if (!typeConstructor)
|
||||
{
|
||||
m_errorReporter.typeError(0000_error, _typeClassInstantiation.typeConstructor().location(), "Invalid type name.");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& instantiations = std::visit(util::GenericVisitor{
|
||||
[&](TypeClassDefinition const* classDefinition) -> auto&
|
||||
{
|
||||
return annotation(*classDefinition).instantiations;
|
||||
},
|
||||
[&](BuiltinClass _builtinClass) -> auto&
|
||||
{
|
||||
return annotation().builtinClassInstantiations[_builtinClass];
|
||||
}
|
||||
}, typeClass->declaration);
|
||||
|
||||
|
||||
if (
|
||||
auto [instantiation, newlyInserted] = annotation(*classDefintion).instantiations.emplace(typeConstructor, &_typeClassInstantiation);
|
||||
auto [instantiation, newlyInserted] = instantiations.emplace(*typeConstructor, &_typeClassInstantiation);
|
||||
!newlyInserted
|
||||
)
|
||||
{
|
||||
@ -160,3 +137,9 @@ TypeRegistration::Annotation& TypeRegistration::annotation(ASTNode const& _node)
|
||||
{
|
||||
return m_analysis.annotation<TypeRegistration>(_node);
|
||||
}
|
||||
|
||||
|
||||
TypeRegistration::GlobalAnnotation& TypeRegistration::annotation()
|
||||
{
|
||||
return m_analysis.annotation<TypeRegistration>();
|
||||
}
|
||||
|
@ -30,19 +30,25 @@ class Analysis;
|
||||
class TypeRegistration: public ASTConstVisitor
|
||||
{
|
||||
public:
|
||||
using TypeClassInstantiations = std::map<TypeConstructor, TypeClassInstantiation const*>;
|
||||
struct Annotation
|
||||
{
|
||||
Type type;
|
||||
std::map<TypeConstructor, TypeClassInstantiation const*> instantiations;
|
||||
TypeClassInstantiations instantiations;
|
||||
};
|
||||
struct GlobalAnnotation
|
||||
{
|
||||
std::map<BuiltinClass, TypeClassInstantiations> builtinClassInstantiations;
|
||||
std::map<Token, std::tuple<TypeClass, std::string>> operators;
|
||||
};
|
||||
TypeRegistration(Analysis& _analysis);
|
||||
|
||||
bool analyze(SourceUnit const& _sourceUnit);
|
||||
private:
|
||||
bool visit(TypeClassDefinition const& _typeClassDefinition) override;
|
||||
bool visit(TypeClassInstantiation const& _typeClassInstantiation) override;
|
||||
bool visit(TypeDefinition const& _typeDefinition) override;
|
||||
Annotation& annotation(ASTNode const& _node);
|
||||
GlobalAnnotation& annotation();
|
||||
|
||||
Analysis& m_analysis;
|
||||
langutil::ErrorReporter& m_errorReporter;
|
||||
|
@ -2497,8 +2497,8 @@ public:
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<TypeName> _typeConstructor,
|
||||
std::vector<ASTPointer<IdentifierPath>> const& _argumentSorts,
|
||||
ASTPointer<IdentifierPath> _class,
|
||||
ASTPointer<ParameterList> _argumentSorts,
|
||||
ASTPointer<TypeClassName> _class,
|
||||
std::vector<ASTPointer<ASTNode>> _subNodes
|
||||
):
|
||||
ASTNode(_id, _location),
|
||||
@ -2512,16 +2512,16 @@ public:
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
|
||||
TypeName const& typeConstructor() const { return *m_typeConstructor; }
|
||||
std::vector<ASTPointer<IdentifierPath>> const& argumentSorts() const { return m_argumentSorts; }
|
||||
IdentifierPath const& typeClass() const { return *m_class; }
|
||||
ParameterList const* argumentSorts() const { return m_argumentSorts.get(); }
|
||||
TypeClassName const& typeClass() const { return *m_class; }
|
||||
std::vector<ASTPointer<ASTNode>> const& subNodes() const { return m_subNodes; }
|
||||
|
||||
bool experimentalSolidityOnly() const override { return true; }
|
||||
|
||||
private:
|
||||
ASTPointer<TypeName> m_typeConstructor;
|
||||
std::vector<ASTPointer<IdentifierPath>> m_argumentSorts;
|
||||
ASTPointer<IdentifierPath> m_class;
|
||||
ASTPointer<ParameterList> m_argumentSorts;
|
||||
ASTPointer<TypeClassName> m_class;
|
||||
std::vector<ASTPointer<ASTNode>> m_subNodes;
|
||||
};
|
||||
|
||||
@ -2559,6 +2559,31 @@ private:
|
||||
ASTPointer<Expression> m_typeExpression;
|
||||
};
|
||||
|
||||
class TypeClassName: public ASTNode
|
||||
{
|
||||
public:
|
||||
TypeClassName(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
std::variant<Token, ASTPointer<IdentifierPath>> _name
|
||||
):
|
||||
ASTNode(_id, _location),
|
||||
m_name(std::move(_name))
|
||||
{
|
||||
if (Token const* token = std::get_if<Token>(&_name))
|
||||
solAssert(TokenTraits::isBuiltinTypeClassName(*token));
|
||||
}
|
||||
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
|
||||
bool experimentalSolidityOnly() const override { return true; }
|
||||
|
||||
std::variant<Token, ASTPointer<IdentifierPath>> name() const { return m_name; }
|
||||
private:
|
||||
std::variant<Token, ASTPointer<IdentifierPath>> m_name;
|
||||
};
|
||||
|
||||
/// @}
|
||||
|
||||
}
|
||||
|
@ -103,6 +103,8 @@ class StructuredDocumentation;
|
||||
/// @{
|
||||
class TypeClassDefinition;
|
||||
class TypeClassInstantiation;
|
||||
class TypeClassName;
|
||||
class TypeDefinition;
|
||||
/// @}
|
||||
|
||||
class VariableScope;
|
||||
|
@ -114,6 +114,7 @@ public:
|
||||
virtual bool visit(TypeClassDefinition& _node) { return visitNode(_node); }
|
||||
virtual bool visit(TypeClassInstantiation& _node) { return visitNode(_node); }
|
||||
virtual bool visit(TypeDefinition& _node) { return visitNode(_node); }
|
||||
virtual bool visit(TypeClassName& _node) { return visitNode(_node); }
|
||||
/// @}
|
||||
|
||||
virtual void endVisit(SourceUnit& _node) { endVisitNode(_node); }
|
||||
@ -176,6 +177,7 @@ public:
|
||||
virtual void endVisit(TypeClassDefinition& _node) { endVisitNode(_node); }
|
||||
virtual void endVisit(TypeClassInstantiation& _node) { endVisitNode(_node); }
|
||||
virtual void endVisit(TypeDefinition& _node) { endVisitNode(_node); }
|
||||
virtual void endVisit(TypeClassName& _node) { endVisitNode(_node); }
|
||||
/// @}
|
||||
|
||||
protected:
|
||||
@ -260,6 +262,7 @@ public:
|
||||
virtual bool visit(TypeClassDefinition const& _node) { return visitNode(_node); }
|
||||
virtual bool visit(TypeClassInstantiation const& _node) { return visitNode(_node); }
|
||||
virtual bool visit(TypeDefinition const& _node) { return visitNode(_node); }
|
||||
virtual bool visit(TypeClassName const& _node) { return visitNode(_node); }
|
||||
/// @}
|
||||
|
||||
virtual void endVisit(SourceUnit const& _node) { endVisitNode(_node); }
|
||||
@ -322,6 +325,7 @@ public:
|
||||
virtual void endVisit(TypeClassDefinition const& _node) { endVisitNode(_node); }
|
||||
virtual void endVisit(TypeClassInstantiation const& _node) { endVisitNode(_node); }
|
||||
virtual void endVisit(TypeDefinition const& _node) { endVisitNode(_node); }
|
||||
virtual void endVisit(TypeClassName const& _node) { endVisitNode(_node); }
|
||||
/// @}
|
||||
|
||||
protected:
|
||||
|
@ -1059,7 +1059,8 @@ void TypeClassInstantiation::accept(ASTVisitor& _visitor)
|
||||
if (_visitor.visit(*this))
|
||||
{
|
||||
m_typeConstructor->accept(_visitor);
|
||||
listAccept(m_argumentSorts, _visitor);
|
||||
if(m_argumentSorts)
|
||||
m_argumentSorts->accept(_visitor);
|
||||
m_class->accept(_visitor);
|
||||
listAccept(m_subNodes, _visitor);
|
||||
}
|
||||
@ -1071,7 +1072,8 @@ void TypeClassInstantiation::accept(ASTConstVisitor& _visitor) const
|
||||
if (_visitor.visit(*this))
|
||||
{
|
||||
m_typeConstructor->accept(_visitor);
|
||||
listAccept(m_argumentSorts, _visitor);
|
||||
if(m_argumentSorts)
|
||||
m_argumentSorts->accept(_visitor);
|
||||
m_class->accept(_visitor);
|
||||
listAccept(m_subNodes, _visitor);
|
||||
}
|
||||
@ -1101,6 +1103,27 @@ void TypeDefinition::accept(ASTConstVisitor& _visitor) const
|
||||
}
|
||||
_visitor.endVisit(*this);
|
||||
}
|
||||
|
||||
|
||||
void TypeClassName::accept(ASTVisitor& _visitor)
|
||||
{
|
||||
if (_visitor.visit(*this))
|
||||
{
|
||||
if (auto* path = std::get_if<ASTPointer<IdentifierPath>>(&m_name))
|
||||
(*path)->accept(_visitor);
|
||||
}
|
||||
_visitor.endVisit(*this);
|
||||
}
|
||||
|
||||
void TypeClassName::accept(ASTConstVisitor& _visitor) const
|
||||
{
|
||||
if (_visitor.visit(*this))
|
||||
{
|
||||
if (auto* path = std::get_if<ASTPointer<IdentifierPath>>(&m_name))
|
||||
(*path)->accept(_visitor);
|
||||
}
|
||||
_visitor.endVisit(*this);
|
||||
}
|
||||
/// @}
|
||||
|
||||
}
|
||||
|
@ -29,6 +29,16 @@ using namespace std;
|
||||
using namespace solidity;
|
||||
using namespace solidity::frontend::experimental;
|
||||
|
||||
bool less<TypeConstructor>::operator()(TypeConstructor const& _lhs, TypeConstructor const& _rhs) const
|
||||
{
|
||||
return std::visit(util::GenericVisitor{
|
||||
[](BuiltinType _left, BuiltinType _right) { return _left < _right; },
|
||||
[](frontend::Declaration const* _left, frontend::Declaration const* _right) { return _left->id() < _right->id(); },
|
||||
[](BuiltinType, frontend::Declaration const*) { return true; },
|
||||
[](frontend::Declaration const*, BuiltinType) { return false; },
|
||||
}, _lhs, _rhs);
|
||||
}
|
||||
|
||||
bool TypeClass::operator<(TypeClass const& _rhs) const
|
||||
{
|
||||
return std::visit(util::GenericVisitor{
|
||||
@ -61,6 +71,10 @@ string TypeClass::toString() const
|
||||
return "kind";
|
||||
case BuiltinClass::Constraint:
|
||||
return "contraint";
|
||||
case BuiltinClass::Integer:
|
||||
return "integer";
|
||||
case BuiltinClass::Mul:
|
||||
return "*";
|
||||
}
|
||||
solAssert(false);
|
||||
},
|
||||
|
@ -51,7 +51,17 @@ enum class BuiltinType
|
||||
};
|
||||
|
||||
using TypeConstructor = std::variant<BuiltinType, Declaration const*>;
|
||||
|
||||
}
|
||||
namespace std
|
||||
{
|
||||
template<>
|
||||
struct less<solidity::frontend::experimental::TypeConstructor>
|
||||
{
|
||||
bool operator()(solidity::frontend::experimental::TypeConstructor const& _lhs, solidity::frontend::experimental::TypeConstructor const& _rhs) const;
|
||||
};
|
||||
}
|
||||
namespace solidity::frontend::experimental
|
||||
{
|
||||
struct TypeConstant
|
||||
{
|
||||
TypeConstructor constructor;
|
||||
@ -62,7 +72,9 @@ enum class BuiltinClass
|
||||
{
|
||||
Type,
|
||||
Kind,
|
||||
Constraint
|
||||
Constraint,
|
||||
Integer,
|
||||
Mul
|
||||
};
|
||||
|
||||
struct TypeClass
|
||||
|
@ -382,14 +382,28 @@ void TypeSystem::declareTypeConstructor(TypeConstructor _typeConstructor, std::s
|
||||
solAssert(newlyInserted, "Type constructor already declared.");
|
||||
}
|
||||
|
||||
void TypeSystem::declareTypeClass(TypeConstructor _classDeclaration, std::string _name)
|
||||
std::optional<std::string> TypeSystem::declareTypeClass(TypeClass _class, Type _typeVariable, std::map<std::string, Type> _functions)
|
||||
{
|
||||
bool newlyInserted = m_typeConstructors.emplace(std::make_pair(_classDeclaration, TypeConstructorInfo{
|
||||
_name,
|
||||
{Arity{vector<Sort>{}, TypeClass{BuiltinClass::Kind}}}
|
||||
})).second;
|
||||
// TODO: proper error handling.
|
||||
solAssert(newlyInserted, "Type class already declared.");
|
||||
TypeVariable const* typeVariable = get_if<TypeVariable>(&_typeVariable);
|
||||
if (!typeVariable)
|
||||
return "Invalid type variable.";
|
||||
for (auto [functionName, functionType]: _functions)
|
||||
{
|
||||
auto typeVars = TypeSystemHelpers{*this}.typeVars(functionType);
|
||||
if (typeVars.empty())
|
||||
return "Function " + functionName + " does not depend on class variable.";
|
||||
if (typeVars.size() > 2)
|
||||
return "Function " + functionName + " depends on multiple type variables.";
|
||||
if (get<TypeVariable>(typeVars.front()).index() != typeVariable->index())
|
||||
return "Function " + functionName + " depends on invalid type variable.";
|
||||
}
|
||||
|
||||
if (!m_typeClasses.emplace(std::make_pair(_class, TypeClassInfo{
|
||||
_typeVariable,
|
||||
std::move(_functions)
|
||||
})).second)
|
||||
return "Type class already declared";
|
||||
return nullopt;
|
||||
|
||||
}
|
||||
|
||||
@ -435,10 +449,48 @@ experimental::Type TypeEnvironment::fresh(Type _type, bool _generalize)
|
||||
return freshImpl(_type, _generalize, freshImpl);
|
||||
}
|
||||
|
||||
void TypeSystem::instantiateClass(TypeConstructor _typeConstructor, Arity _arity)
|
||||
std::optional<std::string> TypeSystem::instantiateClass(Type _instanceVariable, Arity _arity, map<string, Type> _functionTypes)
|
||||
{
|
||||
// TODO: proper error handling
|
||||
auto& typeConstructorInfo = m_typeConstructors.at(_typeConstructor);
|
||||
solAssert(_arity.argumentSorts.size() == typeConstructorInfo.arguments(), "Invalid arity.");
|
||||
if (!TypeSystemHelpers{*this}.isTypeConstant(_instanceVariable))
|
||||
return "Invalid instance variable.";
|
||||
auto [typeConstructor, typeArguments] = TypeSystemHelpers{*this}.destTypeConstant(_instanceVariable);
|
||||
auto& typeConstructorInfo = m_typeConstructors.at(typeConstructor);
|
||||
if (_arity.argumentSorts.size() != typeConstructorInfo.arguments())
|
||||
return "Invalid arity.";
|
||||
if (typeArguments.size() != typeConstructorInfo.arguments())
|
||||
return "Invalid arity.";
|
||||
|
||||
auto const* classInfo = typeClassInfo(_arity.typeClass);
|
||||
if (!classInfo)
|
||||
return "Unknown class.";
|
||||
|
||||
TypeEnvironment newEnv = m_globalTypeEnvironment.clone();
|
||||
|
||||
std::set<size_t> typeVariables;
|
||||
|
||||
Type classVariable = classInfo->typeVariable;
|
||||
if (!newEnv.unify(classVariable, _instanceVariable).empty())
|
||||
// TODO: error reporting
|
||||
return "Unification of class and instance variable failed.";
|
||||
|
||||
for (auto [name, classFunctionType]: classInfo->functions)
|
||||
{
|
||||
if (!_functionTypes.count(name))
|
||||
return "Missing function: " + name;
|
||||
Type instanceFunctionType = _functionTypes.at(name);
|
||||
_functionTypes.erase(name);
|
||||
|
||||
if (!newEnv.typeEquals(instanceFunctionType, classFunctionType))
|
||||
return "Type mismatch for function " + name + " " + newEnv.typeToString(instanceFunctionType) + " != " + newEnv.typeToString(classFunctionType);
|
||||
}
|
||||
|
||||
typeConstructorInfo.arities.emplace_back(_arity);
|
||||
|
||||
if (!_functionTypes.empty())
|
||||
{
|
||||
// TODO: list function names.
|
||||
return "Additional functions in class instantiation.";
|
||||
}
|
||||
|
||||
return nullopt;
|
||||
}
|
||||
|
@ -66,6 +66,11 @@ public:
|
||||
return arities.front().argumentSorts.size();
|
||||
}
|
||||
};
|
||||
struct TypeClassInfo
|
||||
{
|
||||
Type typeVariable;
|
||||
std::map<std::string, Type> functions;
|
||||
};
|
||||
TypeSystem();
|
||||
TypeSystem(TypeSystem const&) = delete;
|
||||
TypeSystem const& operator=(TypeSystem const&) = delete;
|
||||
@ -86,9 +91,13 @@ public:
|
||||
// TODO: error handling
|
||||
return m_typeConstructors.at(_typeConstructor);
|
||||
}
|
||||
TypeClassInfo const* typeClassInfo(TypeClass _class) const
|
||||
{
|
||||
return util::valueOrNullptr(m_typeClasses, _class);
|
||||
}
|
||||
|
||||
void declareTypeClass(TypeConstructor _classDeclaration, std::string _name);
|
||||
void instantiateClass(TypeConstructor _typeConstructor, Arity _arity);
|
||||
[[nodiscard]] std::optional<std::string> declareTypeClass(TypeClass _class, Type _typeVariable, std::map<std::string, Type> _functions);
|
||||
[[nodiscard]] std::optional<std::string> instantiateClass(Type _instanceVariable, Arity _arity, std::map<std::string, Type> _functions);
|
||||
|
||||
Type freshTypeVariable(bool _generic, Sort _sort);
|
||||
Type freshKindVariable(bool _generic, Sort _sort);
|
||||
@ -100,6 +109,7 @@ public:
|
||||
private:
|
||||
size_t m_numTypeVariables = 0;
|
||||
std::map<TypeConstructor, TypeConstructorInfo> m_typeConstructors;
|
||||
std::map<TypeClass, TypeClassInfo> m_typeClasses;
|
||||
TypeEnvironment m_globalTypeEnvironment{*this};
|
||||
};
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
|
||||
#include <libsolidity/ast/experimental/TypeSystemHelper.h>
|
||||
|
||||
#include <libsolidity/ast/AST.h>
|
||||
#include <libsolutil/Visitor.h>
|
||||
|
||||
#include <range/v3/to_container.hpp>
|
||||
@ -27,9 +27,74 @@
|
||||
#include <range/v3/view/reverse.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity::langutil;
|
||||
using namespace solidity::frontend;
|
||||
using namespace solidity::frontend::experimental;
|
||||
|
||||
std::optional<TypeConstructor> experimental::typeConstructorFromTypeName(TypeName const& _typeName)
|
||||
{
|
||||
if (auto const* elementaryTypeName = dynamic_cast<ElementaryTypeName const*>(&_typeName))
|
||||
{
|
||||
if (auto constructor = typeConstructorFromToken(elementaryTypeName->typeName().token()))
|
||||
return *constructor;
|
||||
}
|
||||
else if (auto const* userDefinedType = dynamic_cast<UserDefinedTypeName const*>(&_typeName))
|
||||
{
|
||||
if (auto const* referencedDeclaration = userDefinedType->pathNode().annotation().referencedDeclaration)
|
||||
return referencedDeclaration;
|
||||
}
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
std::optional<TypeConstructor> experimental::typeConstructorFromToken(langutil::Token _token)
|
||||
{
|
||||
switch(_token)
|
||||
{
|
||||
case Token::Void:
|
||||
return BuiltinType::Void;
|
||||
case Token::Fun:
|
||||
return BuiltinType::Function;
|
||||
case Token::Unit:
|
||||
return BuiltinType::Unit;
|
||||
case Token::Pair:
|
||||
return BuiltinType::Pair;
|
||||
case Token::Word:
|
||||
return BuiltinType::Word;
|
||||
case Token::Integer:
|
||||
return BuiltinType::Integer;
|
||||
default:
|
||||
return nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<TypeClass> experimental::typeClassFromToken(langutil::Token _token)
|
||||
{
|
||||
switch (_token)
|
||||
{
|
||||
case Token::Integer:
|
||||
return TypeClass{BuiltinClass::Integer};
|
||||
case Token::Mul:
|
||||
return TypeClass{BuiltinClass::Mul};
|
||||
default:
|
||||
return nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<TypeClass> experimental::typeClassFromTypeClassName(TypeClassName const& _typeClass)
|
||||
{
|
||||
return std::visit(util::GenericVisitor{
|
||||
[&](ASTPointer<IdentifierPath> _path) -> optional<TypeClass> {
|
||||
auto classDefinition = dynamic_cast<TypeClassDefinition const*>(_path->annotation().referencedDeclaration);
|
||||
if (!classDefinition)
|
||||
return nullopt;
|
||||
return TypeClass{classDefinition};
|
||||
},
|
||||
[&](Token _token) -> optional<TypeClass> {
|
||||
return typeClassFromToken(_token);
|
||||
}
|
||||
}, _typeClass.name());
|
||||
}
|
||||
|
||||
experimental::Type TypeSystemHelpers::tupleType(vector<Type> _elements) const
|
||||
{
|
||||
if (_elements.empty())
|
||||
@ -127,6 +192,7 @@ bool TypeSystemHelpers::isFunctionType(Type _type) const
|
||||
|
||||
vector<experimental::Type> TypeSystemHelpers::typeVars(Type _type) const
|
||||
{
|
||||
set<size_t> indices;
|
||||
vector<Type> typeVars;
|
||||
auto typeVarsImpl = [&](Type _type, auto _recurse) -> void {
|
||||
std::visit(util::GenericVisitor{
|
||||
@ -135,7 +201,8 @@ vector<experimental::Type> TypeSystemHelpers::typeVars(Type _type) const
|
||||
_recurse(arg, _recurse);
|
||||
},
|
||||
[&](TypeVariable const& _var) {
|
||||
typeVars.emplace_back(_var);
|
||||
if (indices.emplace(_var.index()).second)
|
||||
typeVars.emplace_back(_var);
|
||||
},
|
||||
// TODO: move to env helpers?
|
||||
}, typeSystem.env().resolve(_type));
|
||||
|
@ -18,10 +18,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <libsolidity/ast/experimental/TypeSystem.h>
|
||||
#include <libsolidity/ast/ASTForward.h>
|
||||
#include <liblangutil/Token.h>
|
||||
|
||||
namespace solidity::frontend::experimental
|
||||
{
|
||||
|
||||
std::optional<TypeConstructor> typeConstructorFromTypeName(TypeName const& _typeName);
|
||||
std::optional<TypeConstructor> typeConstructorFromToken(langutil::Token _token);
|
||||
std::optional<TypeClass> typeClassFromTypeClassName(TypeClassName const& _typeClass);
|
||||
std::optional<TypeClass> typeClassFromToken(langutil::Token _token);
|
||||
|
||||
struct TypeSystemHelpers
|
||||
{
|
||||
TypeSystem const& typeSystem;
|
||||
|
@ -122,12 +122,16 @@ bool IRGeneratorForStatements::visit(InlineAssembly const& _assembly)
|
||||
|
||||
bool IRGeneratorForStatements::visit(VariableDeclarationStatement const& _variableDeclarationStatement)
|
||||
{
|
||||
if (_variableDeclarationStatement.initialValue())
|
||||
_variableDeclarationStatement.initialValue()->accept(*this);
|
||||
solAssert(_variableDeclarationStatement.declarations().size() == 1, "multi variable declarations not supported");
|
||||
solAssert(!_variableDeclarationStatement.initialValue(), "initial values not yet supported");
|
||||
VariableDeclaration const* variableDeclaration = _variableDeclarationStatement.declarations().front().get();
|
||||
solAssert(variableDeclaration);
|
||||
// TODO: check the type of the variable; register local variable; initialize
|
||||
m_code << "let " << IRNames::localVariable(*variableDeclaration) << "\n";
|
||||
m_code << "let " << IRNames::localVariable(*variableDeclaration);
|
||||
if (_variableDeclarationStatement.initialValue())
|
||||
m_code << " := " << IRNames::localVariable(*_variableDeclarationStatement.initialValue());
|
||||
m_code << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -138,9 +142,18 @@ bool IRGeneratorForStatements::visit(ExpressionStatement const&)
|
||||
|
||||
bool IRGeneratorForStatements::visit(Identifier const& _identifier)
|
||||
{
|
||||
auto const* rhsVar = dynamic_cast<VariableDeclaration const*>(_identifier.annotation().referencedDeclaration);
|
||||
solAssert(rhsVar, "Can only reference identifiers referring to variables.");
|
||||
m_code << "let " << IRNames::localVariable(_identifier) << " := " << IRNames::localVariable(*rhsVar) << "\n";
|
||||
if (auto const* var = dynamic_cast<VariableDeclaration const*>(_identifier.annotation().referencedDeclaration))
|
||||
{
|
||||
m_code << "let " << IRNames::localVariable(_identifier) << " := " << IRNames::localVariable(*var) << "\n";
|
||||
}
|
||||
else if (auto const* function = dynamic_cast<FunctionDefinition const*>(_identifier.annotation().referencedDeclaration))
|
||||
solAssert(m_expressionDeclaration.emplace(&_identifier, function).second);
|
||||
else if (auto const* typeClass = dynamic_cast<TypeClassDefinition const*>(_identifier.annotation().referencedDeclaration))
|
||||
solAssert(m_expressionDeclaration.emplace(&_identifier, typeClass).second);
|
||||
else if (auto const* typeDefinition = dynamic_cast<TypeDefinition const*>(_identifier.annotation().referencedDeclaration))
|
||||
solAssert(m_expressionDeclaration.emplace(&_identifier, typeDefinition).second);
|
||||
else
|
||||
solAssert(false, "Unsupported Identifier");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -158,51 +171,129 @@ void IRGeneratorForStatements::endVisit(Return const& _return)
|
||||
m_code << "leave\n";
|
||||
}
|
||||
|
||||
bool IRGeneratorForStatements::visit(FunctionCall const& _functionCall)
|
||||
experimental::Type IRGeneratorForStatements::type(ASTNode const& _node) const
|
||||
{
|
||||
for(auto arg: _functionCall.arguments())
|
||||
arg->accept(*this);
|
||||
auto type = m_context.analysis.annotation<TypeInference>(_node).type;
|
||||
solAssert(type);
|
||||
return *type;
|
||||
}
|
||||
|
||||
void IRGeneratorForStatements::endVisit(BinaryOperation const& _binaryOperation)
|
||||
{
|
||||
TypeSystemHelpers helper{m_context.analysis.typeSystem()};
|
||||
Type leftType = type(_binaryOperation.leftExpression());
|
||||
Type rightType = type(_binaryOperation.rightExpression());
|
||||
Type resultType = type(_binaryOperation);
|
||||
Type functionType = helper.functionType(helper.tupleType({leftType, rightType}), resultType);
|
||||
auto [typeClass, memberName] = m_context.analysis.annotation<TypeRegistration>().operators.at(_binaryOperation.getOperator());
|
||||
auto const& functionDefinition = resolveTypeClassFunction(typeClass, memberName, functionType);
|
||||
// TODO: deduplicate with FunctionCall
|
||||
// TODO: get around resolveRecursive by passing the environment further down?
|
||||
functionType = m_context.env->resolveRecursive(functionType);
|
||||
m_context.enqueueFunctionDefinition(&functionDefinition, functionType);
|
||||
// TODO: account for return stack size
|
||||
m_code << "let " << IRNames::localVariable(_binaryOperation) << " := " << IRNames::function(*m_context.env, functionDefinition, functionType) << "("
|
||||
<< IRNames::localVariable(_binaryOperation.leftExpression()) << ", " << IRNames::localVariable(_binaryOperation.rightExpression()) << ")\n";
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
TypeRegistration::TypeClassInstantiations const& typeClassInstantiations(IRGenerationContext const& _context, TypeClass _class)
|
||||
{
|
||||
return std::visit(util::GenericVisitor{
|
||||
[&](BuiltinClass _builtinClass) -> auto const& {
|
||||
return _context.analysis.annotation<TypeRegistration>().builtinClassInstantiations.at(_builtinClass);
|
||||
},
|
||||
[&](TypeClassDefinition const* _classDefinition) -> auto const& {
|
||||
return _context.analysis.annotation<TypeRegistration>(*_classDefinition).instantiations;
|
||||
}
|
||||
}, _class.declaration);
|
||||
}
|
||||
}
|
||||
|
||||
FunctionDefinition const& IRGeneratorForStatements::resolveTypeClassFunction(TypeClass _class, string _name, Type _type)
|
||||
{
|
||||
TypeSystemHelpers helper{m_context.analysis.typeSystem()};
|
||||
auto const* typeClassInfo = m_context.analysis.typeSystem().typeClassInfo(_class);
|
||||
solAssert(typeClassInfo);
|
||||
Type genericFunctionType = typeClassInfo->functions.at(_name);
|
||||
|
||||
TypeEnvironment env = m_context.env->clone();
|
||||
auto typeVars = helper.typeVars(genericFunctionType);
|
||||
solAssert(typeVars.size() == 1);
|
||||
solAssert(env.unify(genericFunctionType, _type).empty());
|
||||
auto typeClassInstantiation = get<0>(helper.destTypeConstant(env.resolve(typeVars.front())));
|
||||
|
||||
auto const& instantiations = typeClassInstantiations(m_context, _class);
|
||||
TypeClassInstantiation const* instantiation = instantiations.at(typeClassInstantiation);
|
||||
FunctionDefinition const* functionDefinition = nullptr;
|
||||
if (auto const* identifier = dynamic_cast<Identifier const*>(&_functionCall.expression()))
|
||||
for (auto const& node: instantiation->subNodes())
|
||||
{
|
||||
functionDefinition = dynamic_cast<FunctionDefinition const*>(identifier->annotation().referencedDeclaration);
|
||||
}
|
||||
else if (auto const* memberAccess = dynamic_cast<MemberAccess const*>(&_functionCall.expression()))
|
||||
{
|
||||
auto const& expressionAnnotation = m_context.analysis.annotation<TypeInference>(memberAccess->expression());
|
||||
solAssert(expressionAnnotation.type);
|
||||
|
||||
auto typeConstructor = std::get<0>(TypeSystemHelpers{m_context.analysis.typeSystem()}.destTypeConstant(
|
||||
m_context.env->resolve(*expressionAnnotation.type)
|
||||
));
|
||||
auto const* typeClass = dynamic_cast<Identifier const*>(&memberAccess->expression());
|
||||
solAssert(typeClass, "Function call to member access only supported for type classes.");
|
||||
auto const* typeClassDefinition = dynamic_cast<TypeClassDefinition const*>(typeClass->annotation().referencedDeclaration);
|
||||
solAssert(typeClassDefinition, "Function call to member access only supported for type classes.");
|
||||
auto const& classAnnotation = m_context.analysis.annotation<TypeRegistration>(*typeClassDefinition);
|
||||
TypeClassInstantiation const* instantiation = classAnnotation.instantiations.at(typeConstructor);
|
||||
for (auto const& node: instantiation->subNodes())
|
||||
auto const* def = dynamic_cast<FunctionDefinition const*>(node.get());
|
||||
solAssert(def);
|
||||
if (def->name() == _name)
|
||||
{
|
||||
auto const* def = dynamic_cast<FunctionDefinition const*>(node.get());
|
||||
solAssert(def);
|
||||
if (def->name() == memberAccess->memberName())
|
||||
{
|
||||
functionDefinition = def;
|
||||
break;
|
||||
}
|
||||
functionDefinition = def;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
solAssert(false, "Complex function call expressions not supported.");
|
||||
|
||||
solAssert(functionDefinition);
|
||||
auto functionType = m_context.analysis.annotation<TypeInference>(_functionCall.expression()).type;
|
||||
solAssert(functionType);
|
||||
return *functionDefinition;
|
||||
}
|
||||
|
||||
void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
||||
{
|
||||
TypeSystemHelpers helper{m_context.analysis.typeSystem()};
|
||||
auto expressionType = type(_memberAccess.expression());
|
||||
// TODO: avoid kind destruction
|
||||
if (helper.isKindType(expressionType))
|
||||
expressionType = helper.destKindType(expressionType);
|
||||
auto constructor = std::get<0>(helper.destTypeConstant(expressionType));
|
||||
auto memberAccessType = type(_memberAccess);
|
||||
std::visit(util::GenericVisitor{
|
||||
[](BuiltinType) { solAssert(false); },
|
||||
[&](Declaration const *_declaration)
|
||||
{
|
||||
if (auto const* typeClass = dynamic_cast<TypeClassDefinition const*>(_declaration))
|
||||
solAssert(m_expressionDeclaration.emplace(
|
||||
&_memberAccess,
|
||||
&resolveTypeClassFunction(TypeClass{typeClass}, _memberAccess.memberName(), memberAccessType)
|
||||
).second);
|
||||
else if (dynamic_cast<TypeDefinition const*>(_declaration))
|
||||
{
|
||||
if (_memberAccess.memberName() == "abs" || _memberAccess.memberName() == "rep")
|
||||
solAssert(m_expressionDeclaration.emplace(&_memberAccess, Builtins::Identity).second);
|
||||
else
|
||||
solAssert(false);
|
||||
}
|
||||
else
|
||||
solAssert(false);
|
||||
}
|
||||
}, constructor);
|
||||
}
|
||||
|
||||
void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
{
|
||||
Type functionType = type(_functionCall.expression());
|
||||
auto declaration = m_expressionDeclaration.at(&_functionCall.expression());
|
||||
if (auto builtin = get_if<Builtins>(&declaration))
|
||||
{
|
||||
switch(*builtin)
|
||||
{
|
||||
case Builtins::Identity:
|
||||
solAssert(_functionCall.arguments().size() == 1);
|
||||
m_code << "let " << IRNames::localVariable(_functionCall) << " := " << IRNames::localVariable(*_functionCall.arguments().front()) << "\n";
|
||||
return;
|
||||
}
|
||||
solAssert(false);
|
||||
}
|
||||
FunctionDefinition const* functionDefinition = dynamic_cast<FunctionDefinition const*>(get<Declaration const*>(declaration));
|
||||
solAssert(functionDefinition);
|
||||
// TODO: get around resolveRecursive by passing the environment further down?
|
||||
functionType = m_context.env->resolveRecursive(*functionType);
|
||||
m_context.enqueueFunctionDefinition(functionDefinition, *functionType);
|
||||
m_code << "let " << IRNames::localVariable(_functionCall) << " := " << IRNames::function(*m_context.env, *functionDefinition, *functionType) << "(";
|
||||
functionType = m_context.env->resolveRecursive(functionType);
|
||||
m_context.enqueueFunctionDefinition(functionDefinition, functionType);
|
||||
// TODO: account for return stack size
|
||||
m_code << "let " << IRNames::localVariable(_functionCall) << " := " << IRNames::function(*m_context.env, *functionDefinition, functionType) << "(";
|
||||
auto const& arguments = _functionCall.arguments();
|
||||
if (arguments.size() > 1)
|
||||
for (auto arg: arguments | ranges::views::drop_last(1))
|
||||
@ -210,7 +301,11 @@ bool IRGeneratorForStatements::visit(FunctionCall const& _functionCall)
|
||||
if (!arguments.empty())
|
||||
m_code << IRNames::localVariable(*arguments.back());
|
||||
m_code << ")\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IRGeneratorForStatements::visit(FunctionCall const&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IRGeneratorForStatements::visit(Assignment const& _assignment)
|
||||
|
@ -38,8 +38,13 @@ private:
|
||||
bool visit(ExpressionStatement const& _expressionStatement) override;
|
||||
bool visit(Assignment const& _assignment) override;
|
||||
bool visit(Identifier const& _identifier) override;
|
||||
bool visit(FunctionCall const&) override;
|
||||
bool visit(FunctionCall const& _functionCall) override;
|
||||
void endVisit(FunctionCall const& _functionCall) override;
|
||||
bool visit(MemberAccess const&) override { return true; }
|
||||
void endVisit(MemberAccess const& _memberAccess) override;
|
||||
bool visit(InlineAssembly const& _inlineAssembly) override;
|
||||
bool visit(BinaryOperation const&) override { return true; }
|
||||
void endVisit(BinaryOperation const& _binaryOperation) override;
|
||||
bool visit(VariableDeclarationStatement const& _variableDeclarationStatement) override;
|
||||
bool visit(Return const&) override { return true; }
|
||||
void endVisit(Return const& _return) override;
|
||||
@ -47,6 +52,14 @@ private:
|
||||
bool visitNode(ASTNode const& _node) override;
|
||||
IRGenerationContext& m_context;
|
||||
std::stringstream m_code;
|
||||
enum class Builtins
|
||||
{
|
||||
Identity
|
||||
};
|
||||
std::map<Expression const*, std::variant<Declaration const*, Builtins>> m_expressionDeclaration;
|
||||
Type type(ASTNode const& _node) const;
|
||||
|
||||
FunctionDefinition const& resolveTypeClassFunction(TypeClass _class, std::string _name, Type _type);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -1723,7 +1723,7 @@ ASTPointer<VariableDeclaration> Parser::parsePostfixVariableDeclaration()
|
||||
if (m_scanner->currentToken() == Token::Colon)
|
||||
{
|
||||
advance();
|
||||
type = parseExpression();
|
||||
type = parseBinaryExpression();
|
||||
nodeFactory.setEndPositionFromNode(type);
|
||||
}
|
||||
|
||||
@ -1791,6 +1791,26 @@ ASTPointer<TypeClassDefinition> Parser::parseTypeClassDefinition()
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<TypeClassName> Parser::parseTypeClassName()
|
||||
{
|
||||
RecursionGuard recursionGuard(*this);
|
||||
ASTNodeFactory nodeFactory(*this);
|
||||
std::variant<Token, ASTPointer<IdentifierPath>> name;
|
||||
if (TokenTraits::isBuiltinTypeClassName(m_scanner->currentToken()))
|
||||
{
|
||||
nodeFactory.markEndPosition();
|
||||
name = m_scanner->currentToken();
|
||||
advance();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto identifierPath = parseIdentifierPath();
|
||||
name = identifierPath;
|
||||
nodeFactory.setEndPositionFromNode(identifierPath);
|
||||
}
|
||||
return nodeFactory.createNode<TypeClassName>(name);
|
||||
}
|
||||
|
||||
ASTPointer<TypeClassInstantiation> Parser::parseTypeClassInstantiation()
|
||||
{
|
||||
solAssert(m_experimentalSolidityEnabledInCurrentSourceUnit);
|
||||
@ -1803,22 +1823,12 @@ ASTPointer<TypeClassInstantiation> Parser::parseTypeClassInstantiation()
|
||||
// TODO: parseTypeConstructor()
|
||||
ASTPointer<TypeName> typeConstructor = parseTypeName();
|
||||
expectToken(Token::Colon);
|
||||
vector<ASTPointer<IdentifierPath>> argumentSorts;
|
||||
ASTPointer<ParameterList> argumentSorts;
|
||||
if (m_scanner->currentToken() == Token::LParen)
|
||||
{
|
||||
expectToken(Token::LParen);
|
||||
if (m_scanner->currentToken() != Token::RParen)
|
||||
{
|
||||
argumentSorts.emplace_back(parseIdentifierPath());
|
||||
while (m_scanner->currentToken() == Token::Comma)
|
||||
{
|
||||
expectToken(Token::Comma);
|
||||
argumentSorts.emplace_back(parseIdentifierPath());
|
||||
}
|
||||
}
|
||||
expectToken(Token::RParen);
|
||||
argumentSorts = parseParameterList();
|
||||
}
|
||||
ASTPointer<IdentifierPath> sort = parseIdentifierPath();
|
||||
ASTPointer<TypeClassName> typeClassName = parseTypeClassName();
|
||||
expectToken(Token::LBrace);
|
||||
while (true)
|
||||
{
|
||||
@ -1835,7 +1845,7 @@ ASTPointer<TypeClassInstantiation> Parser::parseTypeClassInstantiation()
|
||||
return nodeFactory.createNode<TypeClassInstantiation>(
|
||||
typeConstructor,
|
||||
argumentSorts,
|
||||
sort,
|
||||
typeClassName,
|
||||
subNodes
|
||||
);
|
||||
}
|
||||
|
@ -179,6 +179,7 @@ private:
|
||||
ASTPointer<TypeClassDefinition> parseTypeClassDefinition();
|
||||
ASTPointer<TypeClassInstantiation> parseTypeClassInstantiation();
|
||||
ASTPointer<TypeDefinition> parseTypeDefinition();
|
||||
ASTPointer<TypeClassName> parseTypeClassName();
|
||||
///@}
|
||||
|
||||
///@{
|
||||
|
@ -1,58 +1,37 @@
|
||||
pragma experimental solidity;
|
||||
|
||||
|
||||
class a:A {
|
||||
function testValue(x:a) -> y:word;
|
||||
}
|
||||
|
||||
|
||||
class a:B {
|
||||
function testValue(x:a) -> y:word;
|
||||
}
|
||||
|
||||
instantiation word : A {
|
||||
function testValue(x:word) -> y:word {
|
||||
assembly {
|
||||
y := 7
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
instantiation word : B {
|
||||
function testValue(x:word) -> y:word {
|
||||
assembly {
|
||||
y := 14
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function f(a:_:A) -> b:_:B {
|
||||
return a;
|
||||
}
|
||||
|
||||
type uint256 = word;
|
||||
|
||||
instantiation uint256 : A {
|
||||
function testValue(x:uint256) -> y:word {
|
||||
instantiation uint256: * {
|
||||
function mul(x, y) -> z {
|
||||
let a = uint256.rep(x);
|
||||
let b = uint256.rep(y);
|
||||
assembly {
|
||||
y := 21
|
||||
a := mul(a,b)
|
||||
}
|
||||
z = uint256.abs(a);
|
||||
}
|
||||
}
|
||||
|
||||
instantiation word: * {
|
||||
function mul(x, y) -> z {
|
||||
assembly {
|
||||
z := mul(x,y)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
contract C {
|
||||
fallback() external {
|
||||
let x : word : A;
|
||||
let y;
|
||||
let z: (word, word);
|
||||
let w: uint256;
|
||||
let x : word;
|
||||
assembly {
|
||||
x := 0x42
|
||||
x := 0x10
|
||||
}
|
||||
z = f(z);
|
||||
y = f(x);
|
||||
y = B.testValue(x);
|
||||
y = A.testValue(w);
|
||||
let w: uint256 = uint256.abs(x);
|
||||
w = w * w;
|
||||
let y : word;
|
||||
assembly { y := 2 }
|
||||
y = uint256.rep(w) * y;
|
||||
assembly {
|
||||
mstore(0, y)
|
||||
return(0, 32)
|
||||
|
Loading…
Reference in New Issue
Block a user