mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
tmp
This commit is contained in:
parent
48b35bd921
commit
8135e28821
@ -45,7 +45,7 @@ bool DebugWarner::visitNode(ASTNode const& _node)
|
||||
Type type = *typeInferenceAnnotation.type;
|
||||
Sort sort = m_analysis.typeSystem().env().sort(type);
|
||||
std::string sortString;
|
||||
if (sort.classes.size() != 1 || *sort.classes.begin() != TypeClass{{BuiltinClass::Type}})
|
||||
if (sort.classes.size() != 1 || *sort.classes.begin() != m_analysis.typeSystem().primitiveClass(PrimitiveClass::Type))
|
||||
sortString = ":" + TypeSystemHelpers{m_analysis.typeSystem()}.sortToString(m_analysis.typeSystem().env().sort(type));
|
||||
m_errorReporter.info(
|
||||
0000_error,
|
||||
|
@ -44,11 +44,11 @@ m_analysis(_analysis),
|
||||
m_errorReporter(_analysis.errorReporter()),
|
||||
m_typeSystem(_analysis.typeSystem())
|
||||
{
|
||||
m_voidType = m_typeSystem.type(BuiltinType::Void, {});
|
||||
m_wordType = m_typeSystem.type(BuiltinType::Word, {});
|
||||
m_integerType = m_typeSystem.type(BuiltinType::Integer, {});
|
||||
m_unitType = m_typeSystem.type(BuiltinType::Unit, {});
|
||||
m_boolType = m_typeSystem.type(BuiltinType::Bool, {});
|
||||
m_voidType = m_typeSystem.type(PrimitiveType::Void, {});
|
||||
m_wordType = m_typeSystem.type(PrimitiveType::Word, {});
|
||||
m_integerType = m_typeSystem.type(PrimitiveType::Integer, {});
|
||||
m_unitType = m_typeSystem.type(PrimitiveType::Unit, {});
|
||||
m_boolType = m_typeSystem.type(PrimitiveType::Bool, {});
|
||||
m_env = &m_typeSystem.env();
|
||||
}
|
||||
|
||||
@ -61,17 +61,17 @@ bool TypeInference::analyze(SourceUnit const& _sourceUnit)
|
||||
bool TypeInference::visit(FunctionDefinition const& _functionDefinition)
|
||||
{
|
||||
solAssert(m_expressionContext == ExpressionContext::Term);
|
||||
ScopedSaveAndRestore signatureRestore(m_currentFunctionType, nullopt);
|
||||
auto& functionAnnotation = annotation(_functionDefinition);
|
||||
if (functionAnnotation.type)
|
||||
return false;
|
||||
|
||||
ScopedSaveAndRestore signatureRestore(m_currentFunctionType, nullopt);
|
||||
|
||||
_functionDefinition.parameterList().accept(*this);
|
||||
if (_functionDefinition.returnParameterList())
|
||||
_functionDefinition.returnParameterList()->accept(*this);
|
||||
|
||||
auto getListType = [&](ParameterList const* _list) { return _list ? getType(*_list) : m_unitType; };
|
||||
|
||||
Type functionType = TypeSystemHelpers{m_typeSystem}.functionType(
|
||||
getListType(&_functionDefinition.parameterList()),
|
||||
getListType(_functionDefinition.returnParameterList().get())
|
||||
@ -83,21 +83,17 @@ bool TypeInference::visit(FunctionDefinition const& _functionDefinition)
|
||||
_functionDefinition.body().accept(*this);
|
||||
|
||||
functionAnnotation.type = functionType;
|
||||
|
||||
m_errorReporter.info(0000_error, _functionDefinition.location(), TypeEnvironmentHelpers{*m_env}.typeToString(*functionAnnotation.type));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void TypeInference::endVisit(Return const& _return)
|
||||
{
|
||||
solAssert(m_currentFunctionType);
|
||||
Type functionReturnType = get<1>(TypeSystemHelpers{m_typeSystem}.destFunctionType(*m_currentFunctionType));
|
||||
if (_return.expression())
|
||||
{
|
||||
Type returnExpressionType = getType(*_return.expression());
|
||||
Type functionReturnType = get<1>(TypeSystemHelpers{m_typeSystem}.destFunctionType(*m_currentFunctionType));
|
||||
unify(functionReturnType, returnExpressionType, _return.location());
|
||||
}
|
||||
unify(functionReturnType, getType(*_return.expression()), _return.location());
|
||||
else
|
||||
unify(functionReturnType, m_unitType, _return.location());
|
||||
}
|
||||
|
||||
void TypeInference::endVisit(ParameterList const& _parameterList)
|
||||
@ -115,8 +111,7 @@ bool TypeInference::visit(TypeClassDefinition const& _typeClassDefinition)
|
||||
auto& typeClassAnnotation = annotation(_typeClassDefinition);
|
||||
if (typeClassAnnotation.type)
|
||||
return false;
|
||||
m_typeSystem.declareTypeConstructor(&_typeClassDefinition, _typeClassDefinition.name(), 0);
|
||||
typeClassAnnotation.type = TypeConstant{&_typeClassDefinition, {}};
|
||||
typeClassAnnotation.type = type(&_typeClassDefinition, {});
|
||||
{
|
||||
ScopedSaveAndRestore expressionContext{m_expressionContext, ExpressionContext::Type};
|
||||
_typeClassDefinition.typeVariable().accept(*this);
|
||||
@ -126,32 +121,36 @@ bool TypeInference::visit(TypeClassDefinition const& _typeClassDefinition)
|
||||
|
||||
Type typeVar = m_typeSystem.freshTypeVariable({});
|
||||
|
||||
auto& typeMembers = annotation().members[&_typeClassDefinition];
|
||||
auto& typeMembers = annotation().members[typeConstructor(&_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);
|
||||
auto functionType = m_env->fresh(getType(*functionDefinition));
|
||||
functionTypes[functionDefinition->name()] = functionType;
|
||||
auto typeVars = TypeEnvironmentHelpers{*m_env}.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);
|
||||
unify(typeVars.front(), typeVar, functionDefinition->location());
|
||||
|
||||
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);
|
||||
TypeClass typeClass = std::visit(util::GenericVisitor{
|
||||
[](TypeClass _class) -> TypeClass { return _class; },
|
||||
[&](std::string _error) -> TypeClass {
|
||||
m_errorReporter.fatalTypeError(0000_error, _typeClassDefinition.location(), _error);
|
||||
util::unreachable();
|
||||
}
|
||||
}, m_typeSystem.declareTypeClass(typeVar, std::move(functionTypes), _typeClassDefinition.name(), &_typeClassDefinition));
|
||||
|
||||
unify(getType(_typeClassDefinition.typeVariable()), m_typeSystem.freshTypeVariable({{{&_typeClassDefinition}}}), _typeClassDefinition.location());
|
||||
|
||||
unify(getType(_typeClassDefinition.typeVariable()), m_typeSystem.freshTypeVariable({{typeClass}}), _typeClassDefinition.location());
|
||||
for (auto instantiation: m_analysis.annotation<TypeRegistration>(_typeClassDefinition).instantiations | ranges::views::values)
|
||||
// TODO: recursion-safety?
|
||||
// TODO: recursion-safety? Order of instantiation?
|
||||
instantiation->accept(*this);
|
||||
|
||||
return false;
|
||||
@ -169,22 +168,21 @@ bool TypeInference::visit(InlineAssembly const& _inlineAssembly)
|
||||
{
|
||||
if (_context == yul::IdentifierContext::NonExternal)
|
||||
{
|
||||
// TODO: do we need this?
|
||||
// Hack until we can disallow any shadowing: If we found an internal reference,
|
||||
// clear the external references, so that codegen does not use it.
|
||||
_inlineAssembly.annotation().externalReferences.erase(& _identifier);
|
||||
return false;
|
||||
}
|
||||
auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier);
|
||||
if (ref == _inlineAssembly.annotation().externalReferences.end())
|
||||
InlineAssemblyAnnotation::ExternalIdentifierInfo* identifierInfo = util::valueOrNullptr(_inlineAssembly.annotation().externalReferences, &_identifier);
|
||||
if (!identifierInfo)
|
||||
return false;
|
||||
InlineAssemblyAnnotation::ExternalIdentifierInfo& identifierInfo = ref->second;
|
||||
Declaration const* declaration = identifierInfo.declaration;
|
||||
Declaration const* declaration = identifierInfo->declaration;
|
||||
solAssert(!!declaration, "");
|
||||
|
||||
solAssert(identifierInfo.suffix == "", "");
|
||||
solAssert(identifierInfo->suffix == "", "");
|
||||
|
||||
unify(getType(*declaration), m_wordType, originLocationOf(_identifier));
|
||||
identifierInfo.valueSize = 1;
|
||||
identifierInfo->valueSize = 1;
|
||||
return true;
|
||||
};
|
||||
solAssert(!_inlineAssembly.annotation().analysisInfo, "");
|
||||
@ -203,55 +201,37 @@ bool TypeInference::visit(InlineAssembly const& _inlineAssembly)
|
||||
bool TypeInference::visit(ElementaryTypeNameExpression const& _expression)
|
||||
{
|
||||
auto& expressionAnnotation = annotation(_expression);
|
||||
solAssert(!expressionAnnotation.type);
|
||||
|
||||
if (m_expressionContext != ExpressionContext::Type)
|
||||
{
|
||||
m_errorReporter.typeError(0000_error, _expression.location(), "Elementary type name expression only supported in type context.");
|
||||
expressionAnnotation.type = m_typeSystem.freshTypeVariable({});
|
||||
return false;
|
||||
}
|
||||
TypeSystemHelpers helper{m_typeSystem};
|
||||
switch(_expression.type().typeName().token())
|
||||
|
||||
if (auto constructor = m_analysis.annotation<TypeRegistration>(_expression).typeConstructor)
|
||||
{
|
||||
case Token::Word:
|
||||
expressionAnnotation.type = m_wordType;
|
||||
break;
|
||||
case Token::Void:
|
||||
expressionAnnotation.type = m_voidType;
|
||||
break;
|
||||
case Token::Integer:
|
||||
expressionAnnotation.type = m_integerType;
|
||||
break;
|
||||
case Token::Unit:
|
||||
expressionAnnotation.type = m_unitType;
|
||||
break;
|
||||
case Token::Bool:
|
||||
expressionAnnotation.type = m_boolType;
|
||||
break;
|
||||
case Token::Pair:
|
||||
{
|
||||
auto leftType = m_typeSystem.freshTypeVariable({});
|
||||
auto rightType = m_typeSystem.freshTypeVariable({});
|
||||
expressionAnnotation.type =
|
||||
helper.typeFunctionType(
|
||||
helper.tupleType({leftType, rightType}),
|
||||
m_typeSystem.type(BuiltinType::Pair, {leftType, rightType})
|
||||
);
|
||||
break;
|
||||
vector<Type> arguments;
|
||||
std::generate_n(std::back_inserter(arguments), m_typeSystem.constructorInfo(*constructor).arguments(), [&]() {
|
||||
return m_typeSystem.freshTypeVariable({});
|
||||
});
|
||||
if (arguments.empty())
|
||||
expressionAnnotation.type = m_typeSystem.type(*constructor, arguments);
|
||||
else
|
||||
{
|
||||
TypeSystemHelpers helper{m_typeSystem};
|
||||
expressionAnnotation.type =
|
||||
helper.typeFunctionType(
|
||||
helper.tupleType(arguments),
|
||||
m_typeSystem.type(*constructor, arguments)
|
||||
);
|
||||
}
|
||||
}
|
||||
case Token::Fun:
|
||||
else
|
||||
{
|
||||
auto argType = m_typeSystem.freshTypeVariable({});
|
||||
auto resultType = m_typeSystem.freshTypeVariable({});
|
||||
expressionAnnotation.type = helper.typeFunctionType(
|
||||
helper.tupleType({argType, resultType}),
|
||||
m_typeSystem.type(BuiltinType::Function, {argType, resultType})
|
||||
);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
m_errorReporter.typeError(0000_error, _expression.location(), "Only elementary types are supported.");
|
||||
m_errorReporter.typeError(0000_error, _expression.location(), "No type constructor registered for elementary type name.");
|
||||
expressionAnnotation.type = m_typeSystem.freshTypeVariable({});
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -259,6 +239,7 @@ bool TypeInference::visit(ElementaryTypeNameExpression const& _expression)
|
||||
bool TypeInference::visit(BinaryOperation const& _binaryOperation)
|
||||
{
|
||||
auto& operationAnnotation = annotation(_binaryOperation);
|
||||
solAssert(!operationAnnotation.type);
|
||||
TypeSystemHelpers helper{m_typeSystem};
|
||||
switch (m_expressionContext)
|
||||
{
|
||||
@ -266,14 +247,15 @@ bool TypeInference::visit(BinaryOperation const& _binaryOperation)
|
||||
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));
|
||||
optional<Type> functionType = m_env->typeClassFunction(typeClass, functionName);
|
||||
solAssert(functionType);
|
||||
|
||||
_binaryOperation.leftExpression().accept(*this);
|
||||
_binaryOperation.rightExpression().accept(*this);
|
||||
|
||||
Type argTuple = helper.tupleType({getType(_binaryOperation.leftExpression()), getType(_binaryOperation.rightExpression())});
|
||||
Type genericFunctionType = helper.functionType(argTuple, m_typeSystem.freshTypeVariable({}));
|
||||
unify(functionType, genericFunctionType, _binaryOperation.location());
|
||||
unify(*functionType, genericFunctionType, _binaryOperation.location());
|
||||
|
||||
operationAnnotation.type = m_env->resolve(std::get<1>(helper.destFunctionType(m_env->resolve(genericFunctionType))));
|
||||
|
||||
@ -281,7 +263,7 @@ bool TypeInference::visit(BinaryOperation const& _binaryOperation)
|
||||
}
|
||||
else
|
||||
{
|
||||
m_errorReporter.typeError(0000_error, _binaryOperation.location(), "Binary operations in term context not yet supported.");
|
||||
m_errorReporter.typeError(0000_error, _binaryOperation.location(), "Binary operation in term context not yet supported.");
|
||||
operationAnnotation.type = m_typeSystem.freshTypeVariable({});
|
||||
return false;
|
||||
}
|
||||
@ -430,7 +412,7 @@ experimental::Type TypeInference::handleIdentifierByReferencedDeclaration(langut
|
||||
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.
|
||||
// TODO: Assert that this is a type class variable declaration?
|
||||
auto& declarationAnnotation = annotation(_declaration);
|
||||
if (!declarationAnnotation.type)
|
||||
_declaration.accept(*this);
|
||||
@ -451,7 +433,12 @@ experimental::Type TypeInference::handleIdentifierByReferencedDeclaration(langut
|
||||
{
|
||||
ScopedSaveAndRestore expressionContext{m_expressionContext, ExpressionContext::Term};
|
||||
typeClass->accept(*this);
|
||||
return m_typeSystem.freshTypeVariable(Sort{{TypeClass{typeClass}}});
|
||||
if (!annotation(*typeClass).typeClass)
|
||||
{
|
||||
m_errorReporter.typeError(0000_error, _location, "Unregistered type class.");
|
||||
return m_typeSystem.freshTypeVariable({});
|
||||
}
|
||||
return m_typeSystem.freshTypeVariable(Sort{{*annotation(*typeClass).typeClass}});
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -539,7 +526,8 @@ bool TypeInference::visit(IdentifierPath const& _identifierPath)
|
||||
|
||||
bool TypeInference::visit(TypeClassInstantiation const& _typeClassInstantiation)
|
||||
{
|
||||
// TODO: Deal with dependencies between type class instantiations.
|
||||
ScopedSaveAndRestore activeInstantiations{m_activeInstantiations, m_activeInstantiations + set<TypeClassInstantiation const*>{&_typeClassInstantiation}};
|
||||
// Note: recursion is resolved due to special handling during unification.
|
||||
auto& instantiationAnnotation = annotation(_typeClassInstantiation);
|
||||
if (instantiationAnnotation.type)
|
||||
return false;
|
||||
@ -548,13 +536,10 @@ bool TypeInference::visit(TypeClassInstantiation const& _typeClassInstantiation)
|
||||
[&](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};
|
||||
// visiting the type class will re-visit this instantiation
|
||||
typeClass->accept(*this);
|
||||
// TODO: more error handling? Should be covered by the visit above.
|
||||
return annotation(*typeClass).typeClass;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -563,19 +548,18 @@ bool TypeInference::visit(TypeClassInstantiation const& _typeClassInstantiation)
|
||||
}
|
||||
},
|
||||
[&](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;
|
||||
}
|
||||
if (auto builtinClass = builtinClassFromToken(_token))
|
||||
if (auto typeClass = util::valueOrNullptr(m_analysis.annotation<TypeRegistration>().builtinClasses, *builtinClass))
|
||||
return *typeClass;
|
||||
m_errorReporter.typeError(0000_error, _typeClassInstantiation.location(), "Invalid type class name.");
|
||||
return nullopt;
|
||||
}
|
||||
}, _typeClassInstantiation.typeClass().name());
|
||||
if (!typeClass)
|
||||
return false;
|
||||
|
||||
auto typeConstructor = typeConstructorFromTypeName(_typeClassInstantiation.typeConstructor());
|
||||
// TODO: _typeClassInstantiation.typeConstructor().accept(*this); ?
|
||||
auto typeConstructor = m_analysis.annotation<TypeRegistration>(_typeClassInstantiation.typeConstructor()).typeConstructor;
|
||||
if (!typeConstructor)
|
||||
{
|
||||
m_errorReporter.typeError(0000_error, _typeClassInstantiation.typeConstructor().location(), "Invalid type constructor.");
|
||||
@ -680,21 +664,20 @@ bool TypeInference::visit(TypeDefinition const& _typeDefinition)
|
||||
vector<Type> arguments;
|
||||
if (_typeDefinition.arguments())
|
||||
for (size_t i = 0; i < _typeDefinition.arguments()->parameters().size(); ++i)
|
||||
// TODO: GENERALIZE?
|
||||
arguments.emplace_back(m_typeSystem.freshTypeVariable({}));
|
||||
|
||||
Type type = m_typeSystem.type(TypeConstructor{&_typeDefinition}, arguments);
|
||||
Type definedType = type(&_typeDefinition, arguments);
|
||||
if (arguments.empty())
|
||||
typeDefinitionAnnotation.type = m_typeSystem.type(TypeConstructor{&_typeDefinition}, arguments);
|
||||
typeDefinitionAnnotation.type = definedType;
|
||||
else
|
||||
typeDefinitionAnnotation.type = helper.typeFunctionType(helper.tupleType(arguments), type);
|
||||
typeDefinitionAnnotation.type = helper.typeFunctionType(helper.tupleType(arguments), definedType);
|
||||
|
||||
auto [members, newlyInserted] = annotation().members.emplace(&_typeDefinition, map<string, TypeMember>{});
|
||||
auto [members, newlyInserted] = annotation().members.emplace(typeConstructor(&_typeDefinition), map<string, TypeMember>{});
|
||||
solAssert(newlyInserted);
|
||||
if (underlyingType)
|
||||
{
|
||||
members->second.emplace("abs", TypeMember{helper.functionType(*underlyingType, type)});
|
||||
members->second.emplace("rep", TypeMember{helper.functionType(type, *underlyingType)});
|
||||
members->second.emplace("abs", TypeMember{helper.functionType(*underlyingType, definedType)});
|
||||
members->second.emplace("rep", TypeMember{helper.functionType(definedType, *underlyingType)});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -920,17 +903,89 @@ bool TypeInference::visit(Literal const& _literal)
|
||||
m_errorReporter.typeError(0000_error, _literal.location(), "Only integers are supported.");
|
||||
return false;
|
||||
}
|
||||
literalAnnotation.type = m_typeSystem.freshTypeVariable(Sort{{TypeClass{BuiltinClass::Integer}}});
|
||||
literalAnnotation.type = m_typeSystem.freshTypeVariable(Sort{{m_analysis.annotation<TypeRegistration>().builtinClasses.at(BuiltinClass::Integer)}});
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
// TODO: put at a nice place to deduplicate.
|
||||
TypeRegistration::TypeClassInstantiations const& typeClassInstantiations(Analysis const& _analysis, TypeClass _class)
|
||||
{
|
||||
auto const* typeClassDeclaration = _analysis.typeSystem().typeClassDeclaration(_class);
|
||||
if (typeClassDeclaration)
|
||||
return _analysis.annotation<TypeRegistration>(*typeClassDeclaration).instantiations;
|
||||
// TODO: better mechanism than fetching by name.
|
||||
auto& annotation = _analysis.annotation<TypeRegistration>();
|
||||
return annotation.builtinClassInstantiations.at(annotation.builtinClassesByName.at(_analysis.typeSystem().typeClassName(_class)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TypeInference::unify(Type _a, Type _b, langutil::SourceLocation _location, TypeEnvironment* _env)
|
||||
{
|
||||
TypeSystemHelpers helper{m_typeSystem};
|
||||
if (!_env)
|
||||
_env = m_env;
|
||||
for (auto failure: _env->unify(_a, _b))
|
||||
auto unificationFailures = _env->unify(_a, _b);
|
||||
|
||||
if (!m_activeInstantiations.empty())
|
||||
{
|
||||
TypeEnvironmentHelpers helper{*_env};
|
||||
// Attempt to resolve interdependencies between type class instantiations.
|
||||
std::vector<TypeClassInstantiation const*> missingInstantiations;
|
||||
bool recursion = false;
|
||||
bool onlyMissingInstantiations = [&]() {
|
||||
for (auto failure: unificationFailures)
|
||||
{
|
||||
if (auto* sortMismatch = get_if<TypeEnvironment::SortMismatch>(&failure))
|
||||
if (helper.isTypeConstant(sortMismatch->type))
|
||||
{
|
||||
TypeConstructor constructor = std::get<0>(helper.destTypeConstant(sortMismatch->type));
|
||||
for (auto typeClass: sortMismatch->sort.classes)
|
||||
{
|
||||
if (auto const* instantiation = util::valueOrDefault(typeClassInstantiations(m_analysis, typeClass), constructor, nullptr))
|
||||
{
|
||||
if (m_activeInstantiations.count(instantiation))
|
||||
{
|
||||
langutil::SecondarySourceLocation ssl;
|
||||
for (auto activeInstantiation: m_activeInstantiations)
|
||||
ssl.append("Involved instantiation", activeInstantiation->location());
|
||||
m_errorReporter.typeError(
|
||||
0000_error,
|
||||
_location,
|
||||
ssl,
|
||||
"Recursion during type class instantiation."
|
||||
);
|
||||
recursion = true;
|
||||
return false;
|
||||
}
|
||||
missingInstantiations.emplace_back(instantiation);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}();
|
||||
|
||||
if (recursion)
|
||||
return;
|
||||
|
||||
if (onlyMissingInstantiations)
|
||||
{
|
||||
for (auto instantiation: missingInstantiations)
|
||||
instantiation->accept(*this);
|
||||
unificationFailures = _env->unify(_a, _b);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto failure: unificationFailures)
|
||||
{
|
||||
TypeEnvironmentHelpers envHelper{*_env};
|
||||
std::visit(util::GenericVisitor{
|
||||
[&](TypeEnvironment::TypeMismatch _typeMismatch) {
|
||||
m_errorReporter.typeError(
|
||||
@ -938,16 +993,26 @@ void TypeInference::unify(Type _a, Type _b, langutil::SourceLocation _location,
|
||||
_location,
|
||||
fmt::format(
|
||||
"Cannot unify {} and {}.",
|
||||
helper.typeToString(_typeMismatch.a),
|
||||
helper.typeToString(_typeMismatch.b))
|
||||
envHelper.typeToString(_typeMismatch.a),
|
||||
envHelper.typeToString(_typeMismatch.b))
|
||||
);
|
||||
},
|
||||
[&](TypeEnvironment::SortMismatch _sortMismatch) {
|
||||
m_errorReporter.typeError(0000_error, _location, fmt::format(
|
||||
"{} does not have sort {}",
|
||||
helper.typeToString(_sortMismatch.type),
|
||||
envHelper.typeToString(_sortMismatch.type),
|
||||
TypeSystemHelpers{m_typeSystem}.sortToString(_sortMismatch.sort)
|
||||
));
|
||||
},
|
||||
[&](TypeEnvironment::RecursiveUnification _recursiveUnification) {
|
||||
m_errorReporter.typeError(
|
||||
0000_error,
|
||||
_location,
|
||||
fmt::format(
|
||||
"Recursive unification: {} occurs in {}.",
|
||||
envHelper.typeToString(_recursiveUnification.var),
|
||||
envHelper.typeToString(_recursiveUnification.type))
|
||||
);
|
||||
}
|
||||
}, failure);
|
||||
}
|
||||
@ -959,6 +1024,17 @@ experimental::Type TypeInference::getType(ASTNode const& _node) const
|
||||
solAssert(result);
|
||||
return *result;
|
||||
}
|
||||
TypeConstructor TypeInference::typeConstructor(Declaration const* _type) const
|
||||
{
|
||||
if (auto const& constructor = m_analysis.annotation<TypeRegistration>(*_type).typeConstructor)
|
||||
return *constructor;
|
||||
m_errorReporter.fatalTypeError(0000_error, _type->location(), "Unregistered type.");
|
||||
util::unreachable();
|
||||
}
|
||||
experimental::Type TypeInference::type(Declaration const* _type, vector<Type> _arguments) const
|
||||
{
|
||||
return m_typeSystem.type(typeConstructor(_type), std::move(_arguments));
|
||||
}
|
||||
|
||||
bool TypeInference::visitNode(ASTNode const& _node)
|
||||
{
|
||||
|
@ -38,6 +38,8 @@ public:
|
||||
{
|
||||
/// Expressions, variable declarations, function declarations.
|
||||
std::optional<Type> type;
|
||||
// Type classes.
|
||||
std::optional<TypeClass> typeClass;
|
||||
};
|
||||
struct TypeMember
|
||||
{
|
||||
@ -106,7 +108,10 @@ private:
|
||||
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);
|
||||
TypeConstructor typeConstructor(Declaration const* _type) const;
|
||||
Type type(Declaration const* _type, std::vector<Type> _arguments) const;
|
||||
ExpressionContext m_expressionContext = ExpressionContext::Term;
|
||||
std::set<TypeClassInstantiation const*, ASTCompareByID<TypeClassInstantiation>> m_activeInstantiations;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -36,68 +36,63 @@ m_analysis(_analysis),
|
||||
m_errorReporter(_analysis.errorReporter()),
|
||||
m_typeSystem(_analysis.typeSystem())
|
||||
{
|
||||
for (auto [type, name, arity]: std::initializer_list<std::tuple<BuiltinType, const char*, uint64_t>> {
|
||||
{BuiltinType::Void, "void", 0},
|
||||
{BuiltinType::Unit, "unit", 0},
|
||||
{BuiltinType::Pair, "pair", 2},
|
||||
{BuiltinType::Word, "word", 0},
|
||||
{BuiltinType::Integer, "integer", 0},
|
||||
{BuiltinType::Bool, "bool", 0}
|
||||
})
|
||||
m_typeSystem.declareTypeConstructor(type, name, arity);
|
||||
|
||||
auto declareBuiltinClass = [&](BuiltinClass _class, auto _memberCreator, Sort _sort = {}) {
|
||||
// TODO: move builtin class declarations to TypeInference
|
||||
auto declareBuiltinClass = [&](std::string _name, BuiltinClass _class, auto _memberCreator, Sort _sort = {}) -> TypeClass {
|
||||
Type type = m_typeSystem.freshTypeVariable(std::move(_sort));
|
||||
auto error = m_typeSystem.declareTypeClass(
|
||||
TypeClass{_class},
|
||||
auto result = m_typeSystem.declareTypeClass(
|
||||
type,
|
||||
_memberCreator(type)
|
||||
_memberCreator(type),
|
||||
_name,
|
||||
nullptr
|
||||
);
|
||||
solAssert(!error, *error);
|
||||
if (auto error = get_if<string>(&result))
|
||||
solAssert(!error, *error);
|
||||
solAssert(annotation().builtinClassesByName.emplace(_name, _class).second);
|
||||
return annotation().builtinClasses.emplace(_class, get<TypeClass>(result)).first->second;
|
||||
};
|
||||
TypeSystemHelpers helper{m_typeSystem};
|
||||
using MemberList = std::map<std::string, Type>;
|
||||
|
||||
declareBuiltinClass(BuiltinClass::Integer, [&](Type _typeVar) -> MemberList {
|
||||
declareBuiltinClass("integer", BuiltinClass::Integer, [&](Type _typeVar) -> MemberList {
|
||||
return {
|
||||
{
|
||||
"fromInteger",
|
||||
helper.functionType(TypeConstant{{BuiltinType::Integer}, {}}, _typeVar)
|
||||
helper.functionType(m_typeSystem.type(PrimitiveType::Integer, {}), _typeVar)
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
auto defineBinaryMonoidalOperator = [&](BuiltinClass _class, Token _token, std::string _name) {
|
||||
declareBuiltinClass(_class, [&](Type _typeVar) -> MemberList {
|
||||
auto defineBinaryMonoidalOperator = [&](std::string _className, BuiltinClass _class, Token _token, std::string _functionName) {
|
||||
TypeClass typeClass = declareBuiltinClass(_className, _class, [&](Type _typeVar) -> MemberList {
|
||||
return {
|
||||
{
|
||||
_name,
|
||||
_functionName,
|
||||
helper.functionType(helper.tupleType({_typeVar, _typeVar}), _typeVar)
|
||||
}
|
||||
};
|
||||
});
|
||||
annotation().operators[_token] = std::make_tuple(TypeClass{_class}, _name);
|
||||
annotation().operators.emplace(_token, std::make_tuple(typeClass, _functionName));
|
||||
};
|
||||
|
||||
defineBinaryMonoidalOperator(BuiltinClass::Mul, Token::Mul, "mul");
|
||||
defineBinaryMonoidalOperator(BuiltinClass::Add, Token::Add, "add");
|
||||
defineBinaryMonoidalOperator("*", BuiltinClass::Mul, Token::Mul, "mul");
|
||||
defineBinaryMonoidalOperator("+", BuiltinClass::Add, Token::Add, "add");
|
||||
|
||||
auto defineBinaryCompareOperator = [&](BuiltinClass _class, Token _token, std::string _name) {
|
||||
declareBuiltinClass(_class, [&](Type _typeVar) -> MemberList {
|
||||
auto defineBinaryCompareOperator = [&](std::string _className, BuiltinClass _class, Token _token, std::string _functionName) {
|
||||
TypeClass typeClass = declareBuiltinClass(_className, _class, [&](Type _typeVar) -> MemberList {
|
||||
return {
|
||||
{
|
||||
_name,
|
||||
helper.functionType(helper.tupleType({_typeVar, _typeVar}), TypeConstant{BuiltinType::Bool, {}})
|
||||
_functionName,
|
||||
helper.functionType(helper.tupleType({_typeVar, _typeVar}), m_typeSystem.type(PrimitiveType::Bool, {}))
|
||||
}
|
||||
};
|
||||
});
|
||||
annotation().operators[_token] = std::make_tuple(TypeClass{_class}, _name);
|
||||
annotation().operators.emplace(_token, std::make_tuple(typeClass, _functionName));
|
||||
};
|
||||
defineBinaryCompareOperator(BuiltinClass::Equal, Token::Equal, "eq");
|
||||
defineBinaryCompareOperator(BuiltinClass::Less, Token::LessThan, "lt");
|
||||
defineBinaryCompareOperator(BuiltinClass::LessOrEqual, Token::LessThanOrEqual, "leq");
|
||||
defineBinaryCompareOperator(BuiltinClass::Greater, Token::GreaterThan, "gt");
|
||||
defineBinaryCompareOperator(BuiltinClass::GreaterOrEqual, Token::GreaterThanOrEqual, "geq");
|
||||
defineBinaryCompareOperator("==", BuiltinClass::Equal, Token::Equal, "eq");
|
||||
defineBinaryCompareOperator("<", BuiltinClass::Less, Token::LessThan, "lt");
|
||||
defineBinaryCompareOperator("<=", BuiltinClass::LessOrEqual, Token::LessThanOrEqual, "leq");
|
||||
defineBinaryCompareOperator(">", BuiltinClass::Greater, Token::GreaterThan, "gt");
|
||||
defineBinaryCompareOperator(">=", BuiltinClass::GreaterOrEqual, Token::GreaterThanOrEqual, "geq");
|
||||
}
|
||||
|
||||
bool TypeRegistration::analyze(SourceUnit const& _sourceUnit)
|
||||
@ -106,36 +101,115 @@ bool TypeRegistration::analyze(SourceUnit const& _sourceUnit)
|
||||
return !m_errorReporter.hasErrors();
|
||||
}
|
||||
|
||||
bool TypeRegistration::visit(TypeClassInstantiation const& _typeClassInstantiation)
|
||||
bool TypeRegistration::visit(TypeClassDefinition const& _typeClassDefinition)
|
||||
{
|
||||
optional<TypeClass> typeClass = typeClassFromTypeClassName(_typeClassInstantiation.typeClass());
|
||||
if (!typeClass)
|
||||
if (annotation(_typeClassDefinition).typeConstructor)
|
||||
return false;
|
||||
annotation(_typeClassDefinition).typeConstructor = m_typeSystem.declareTypeConstructor(
|
||||
_typeClassDefinition.name(),
|
||||
"t_" + *_typeClassDefinition.annotation().canonicalName + "_" + util::toString(_typeClassDefinition.id()),
|
||||
0,
|
||||
&_typeClassDefinition
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TypeRegistration::visit(ElementaryTypeName const& _typeName)
|
||||
{
|
||||
if (annotation(_typeName).typeConstructor)
|
||||
return false;
|
||||
annotation(_typeName).typeConstructor = [&]() -> optional<TypeConstructor> {
|
||||
switch(_typeName.typeName().token())
|
||||
{
|
||||
case Token::Void:
|
||||
return m_typeSystem.constructor(PrimitiveType::Void);
|
||||
case Token::Fun:
|
||||
return m_typeSystem.constructor(PrimitiveType::Function);
|
||||
case Token::Unit:
|
||||
return m_typeSystem.constructor(PrimitiveType::Unit);
|
||||
case Token::Pair:
|
||||
return m_typeSystem.constructor(PrimitiveType::Pair);
|
||||
case Token::Word:
|
||||
return m_typeSystem.constructor(PrimitiveType::Word);
|
||||
case Token::Integer:
|
||||
return m_typeSystem.constructor(PrimitiveType::Integer);
|
||||
case Token::Bool:
|
||||
return m_typeSystem.constructor(PrimitiveType::Bool);
|
||||
default:
|
||||
m_errorReporter.fatalTypeError(0000_error, _typeName.location(), "Expected primitive type.");
|
||||
return nullopt;
|
||||
}
|
||||
}();
|
||||
return true;
|
||||
}
|
||||
|
||||
void TypeRegistration::endVisit(ElementaryTypeNameExpression const & _typeNameExpression)
|
||||
{
|
||||
if (annotation(_typeNameExpression).typeConstructor)
|
||||
return;
|
||||
|
||||
// TODO: this is not visited in the ElementaryTypeNameExpression visit - is that intentional?
|
||||
_typeNameExpression.type().accept(*this);
|
||||
if (auto constructor = annotation(_typeNameExpression.type()).typeConstructor)
|
||||
annotation(_typeNameExpression).typeConstructor = constructor;
|
||||
else
|
||||
solAssert(m_errorReporter.hasErrors());
|
||||
}
|
||||
|
||||
bool TypeRegistration::visit(UserDefinedTypeName const& _userDefinedTypeName)
|
||||
{
|
||||
if (annotation(_userDefinedTypeName).typeConstructor)
|
||||
return false;
|
||||
auto const* declaration = _userDefinedTypeName.pathNode().annotation().referencedDeclaration;
|
||||
if (!declaration)
|
||||
{
|
||||
m_errorReporter.typeError(0000_error, _typeClassInstantiation.typeClass().location(), "Expected a type class.");
|
||||
// TODO: fatal/non-fatal
|
||||
m_errorReporter.fatalTypeError(0000_error, _userDefinedTypeName.pathNode().location(), "Expected declaration.");
|
||||
return false;
|
||||
}
|
||||
declaration->accept(*this);
|
||||
if (!(annotation(_userDefinedTypeName).typeConstructor = annotation(*declaration).typeConstructor))
|
||||
{
|
||||
// TODO: fatal/non-fatal
|
||||
m_errorReporter.fatalTypeError(0000_error, _userDefinedTypeName.pathNode().location(), "Expected type declaration.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
optional<TypeConstructor> typeConstructor = typeConstructorFromTypeName(_typeClassInstantiation.typeConstructor());
|
||||
bool TypeRegistration::visit(TypeClassInstantiation const& _typeClassInstantiation)
|
||||
{
|
||||
if (annotation(_typeClassInstantiation).typeConstructor)
|
||||
return false;
|
||||
_typeClassInstantiation.typeConstructor().accept(*this);
|
||||
auto typeConstructor = annotation(_typeClassInstantiation.typeConstructor()).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&
|
||||
auto* instantiations = std::visit(util::GenericVisitor{
|
||||
[&](ASTPointer<IdentifierPath> _path) -> TypeClassInstantiations*
|
||||
{
|
||||
return annotation(*classDefinition).instantiations;
|
||||
if (TypeClassDefinition const* classDefinition = dynamic_cast<TypeClassDefinition const*>(_path->annotation().referencedDeclaration))
|
||||
return &annotation(*classDefinition).instantiations;
|
||||
m_errorReporter.typeError(0000_error, _typeClassInstantiation.typeClass().location(), "Expected a type class.");
|
||||
return nullptr;
|
||||
},
|
||||
[&](BuiltinClass _builtinClass) -> auto&
|
||||
[&](Token _token) -> TypeClassInstantiations*
|
||||
{
|
||||
return annotation().builtinClassInstantiations[_builtinClass];
|
||||
if (auto typeClass = builtinClassFromToken(_token))
|
||||
return &annotation().builtinClassInstantiations[*typeClass];
|
||||
m_errorReporter.typeError(0000_error, _typeClassInstantiation.typeClass().location(), "Expected a type class.");
|
||||
return nullptr;
|
||||
}
|
||||
}, typeClass->declaration);
|
||||
}, _typeClassInstantiation.typeClass().name());
|
||||
|
||||
if (!instantiations)
|
||||
return false;
|
||||
|
||||
if (
|
||||
auto [instantiation, newlyInserted] = instantiations.emplace(*typeConstructor, &_typeClassInstantiation);
|
||||
auto [instantiation, newlyInserted] = instantiations->emplace(*typeConstructor, &_typeClassInstantiation);
|
||||
!newlyInserted
|
||||
)
|
||||
{
|
||||
@ -144,17 +218,20 @@ bool TypeRegistration::visit(TypeClassInstantiation const& _typeClassInstantiati
|
||||
m_errorReporter.typeError(0000_error, _typeClassInstantiation.location(), ssl, "Duplicate type class instantiation.");
|
||||
}
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TypeRegistration::visit(TypeDefinition const& _typeDefinition)
|
||||
{
|
||||
m_typeSystem.declareTypeConstructor(
|
||||
TypeConstructor{&_typeDefinition},
|
||||
if (annotation(_typeDefinition).typeConstructor)
|
||||
return false;
|
||||
annotation(_typeDefinition).typeConstructor = m_typeSystem.declareTypeConstructor(
|
||||
_typeDefinition.name(),
|
||||
_typeDefinition.arguments() ? _typeDefinition.arguments()->parameters().size() : 0
|
||||
"t_" + *_typeDefinition.annotation().canonicalName + "_" + util::toString(_typeDefinition.id()),
|
||||
_typeDefinition.arguments() ? _typeDefinition.arguments()->parameters().size() : 0,
|
||||
&_typeDefinition
|
||||
);
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
TypeRegistration::Annotation& TypeRegistration::annotation(ASTNode const& _node)
|
||||
@ -162,7 +239,6 @@ TypeRegistration::Annotation& TypeRegistration::annotation(ASTNode const& _node)
|
||||
return m_analysis.annotation<TypeRegistration>(_node);
|
||||
}
|
||||
|
||||
|
||||
TypeRegistration::GlobalAnnotation& TypeRegistration::annotation()
|
||||
{
|
||||
return m_analysis.annotation<TypeRegistration>();
|
||||
|
@ -27,17 +27,34 @@ namespace solidity::frontend::experimental
|
||||
|
||||
class Analysis;
|
||||
|
||||
enum class BuiltinClass
|
||||
{
|
||||
Integer,
|
||||
Mul,
|
||||
Add,
|
||||
Equal,
|
||||
Less,
|
||||
LessOrEqual,
|
||||
Greater,
|
||||
GreaterOrEqual
|
||||
};
|
||||
|
||||
class TypeRegistration: public ASTConstVisitor
|
||||
{
|
||||
public:
|
||||
using TypeClassInstantiations = std::map<TypeConstructor, TypeClassInstantiation const*>;
|
||||
struct Annotation
|
||||
{
|
||||
Type type;
|
||||
// For type class definititions.
|
||||
TypeClassInstantiations instantiations;
|
||||
// For type definitions, type class definitions, type names and type name expressions.
|
||||
std::optional<TypeConstructor> typeConstructor;
|
||||
};
|
||||
struct GlobalAnnotation
|
||||
{
|
||||
std::map<BuiltinClass, TypeClass> builtinClasses;
|
||||
std::map<std::string, BuiltinClass> builtinClassesByName;
|
||||
std::map<PrimitiveClass, TypeClassInstantiations> primitiveClassInstantiations;
|
||||
std::map<BuiltinClass, TypeClassInstantiations> builtinClassInstantiations;
|
||||
std::map<Token, std::tuple<TypeClass, std::string>> operators;
|
||||
};
|
||||
@ -45,8 +62,12 @@ public:
|
||||
|
||||
bool analyze(SourceUnit const& _sourceUnit);
|
||||
private:
|
||||
bool visit(TypeClassDefinition const& _typeClassDefinition) override;
|
||||
bool visit(TypeClassInstantiation const& _typeClassInstantiation) override;
|
||||
bool visit(TypeDefinition const& _typeDefinition) override;
|
||||
bool visit(UserDefinedTypeName const& _typeName) override;
|
||||
void endVisit(ElementaryTypeNameExpression const& _typeName) override;
|
||||
bool visit(ElementaryTypeName const& _typeName) override;
|
||||
Annotation& annotation(ASTNode const& _node);
|
||||
GlobalAnnotation& annotation();
|
||||
|
||||
|
@ -29,69 +29,6 @@ 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{
|
||||
[](BuiltinClass _left, BuiltinClass _right) { return _left < _right; },
|
||||
[](TypeClassDefinition const* _left, TypeClassDefinition const* _right) { return _left->id() < _right->id(); },
|
||||
[](BuiltinClass, TypeClassDefinition const*) { return true; },
|
||||
[](TypeClassDefinition const*, BuiltinClass) { return false; },
|
||||
}, declaration, _rhs.declaration);
|
||||
}
|
||||
|
||||
bool TypeClass::operator==(TypeClass const& _rhs) const
|
||||
{
|
||||
return std::visit(util::GenericVisitor{
|
||||
[](BuiltinClass _left, BuiltinClass _right) { return _left == _right; },
|
||||
[](TypeClassDefinition const* _left, TypeClassDefinition const* _right) { return _left->id() == _right->id(); },
|
||||
[](BuiltinClass, TypeClassDefinition const*) { return false; },
|
||||
[](TypeClassDefinition const*, BuiltinClass) { return false; },
|
||||
}, declaration, _rhs.declaration);
|
||||
}
|
||||
|
||||
string TypeClass::toString() const
|
||||
{
|
||||
return std::visit(util::GenericVisitor{
|
||||
[](BuiltinClass _class) -> string {
|
||||
switch(_class)
|
||||
{
|
||||
case BuiltinClass::Type:
|
||||
return "type";
|
||||
case BuiltinClass::Kind:
|
||||
return "kind";
|
||||
case BuiltinClass::Integer:
|
||||
return "integer";
|
||||
case BuiltinClass::Mul:
|
||||
return "*";
|
||||
case BuiltinClass::Add:
|
||||
return "+";
|
||||
case BuiltinClass::Equal:
|
||||
return "==";
|
||||
case BuiltinClass::Less:
|
||||
return "<";
|
||||
case BuiltinClass::LessOrEqual:
|
||||
return "<=";
|
||||
case BuiltinClass::Greater:
|
||||
return ">";
|
||||
case BuiltinClass::GreaterOrEqual:
|
||||
return ">=";
|
||||
}
|
||||
solAssert(false);
|
||||
},
|
||||
[](TypeClassDefinition const* _declaration) { return _declaration->name(); },
|
||||
}, declaration);
|
||||
}
|
||||
|
||||
bool Sort::operator==(Sort const& _rhs) const
|
||||
{
|
||||
if (classes.size() != _rhs.classes.size())
|
||||
|
@ -18,16 +18,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
namespace solidity::frontend
|
||||
{
|
||||
class Declaration;
|
||||
class TypeClassDefinition;
|
||||
}
|
||||
|
||||
namespace solidity::frontend::experimental
|
||||
{
|
||||
|
||||
@ -36,12 +29,10 @@ class TypeSystem;
|
||||
struct TypeConstant;
|
||||
struct TypeVariable;
|
||||
|
||||
using Type = std::variant<TypeConstant, TypeVariable>;
|
||||
using Type = std::variant<std::monostate, TypeConstant, TypeVariable>;
|
||||
|
||||
enum class BuiltinType
|
||||
enum class PrimitiveType
|
||||
{
|
||||
Type,
|
||||
Sort,
|
||||
Void,
|
||||
Function,
|
||||
TypeFunction,
|
||||
@ -52,45 +43,70 @@ enum class BuiltinType
|
||||
Integer
|
||||
};
|
||||
|
||||
using TypeConstructor = std::variant<BuiltinType, Declaration const*>;
|
||||
}
|
||||
namespace std
|
||||
enum class PrimitiveClass
|
||||
{
|
||||
template<>
|
||||
struct less<solidity::frontend::experimental::TypeConstructor>
|
||||
{
|
||||
bool operator()(solidity::frontend::experimental::TypeConstructor const& _lhs, solidity::frontend::experimental::TypeConstructor const& _rhs) const;
|
||||
Type,
|
||||
Kind
|
||||
};
|
||||
}
|
||||
namespace solidity::frontend::experimental
|
||||
|
||||
struct TypeConstructor
|
||||
{
|
||||
public:
|
||||
TypeConstructor(TypeConstructor const& _typeConstructor): m_index(_typeConstructor.m_index) {}
|
||||
TypeConstructor& operator=(TypeConstructor const& _typeConstructor)
|
||||
{
|
||||
m_index = _typeConstructor.m_index;
|
||||
return *this;
|
||||
}
|
||||
bool operator<(TypeConstructor const& _rhs) const
|
||||
{
|
||||
return m_index < _rhs.m_index;
|
||||
}
|
||||
bool operator==(TypeConstructor const& _rhs) const
|
||||
{
|
||||
return m_index == _rhs.m_index;
|
||||
}
|
||||
bool operator!=(TypeConstructor const& _rhs) const
|
||||
{
|
||||
return m_index != _rhs.m_index;
|
||||
}
|
||||
private:
|
||||
friend class TypeSystem;
|
||||
TypeConstructor(size_t _index): m_index(_index) {}
|
||||
size_t m_index = 0;
|
||||
};
|
||||
|
||||
struct TypeConstant
|
||||
{
|
||||
TypeConstructor constructor;
|
||||
std::vector<Type> arguments;
|
||||
};
|
||||
|
||||
enum class BuiltinClass
|
||||
{
|
||||
Type,
|
||||
Kind,
|
||||
Integer,
|
||||
Mul,
|
||||
Add,
|
||||
Equal,
|
||||
Less,
|
||||
LessOrEqual,
|
||||
Greater,
|
||||
GreaterOrEqual
|
||||
};
|
||||
|
||||
struct TypeClass
|
||||
{
|
||||
std::variant<BuiltinClass, TypeClassDefinition const*> declaration;
|
||||
std::string toString() const;
|
||||
bool operator<(TypeClass const& _rhs) const;
|
||||
bool operator==(TypeClass const& _rhs) const;
|
||||
bool operator!=(TypeClass const& _rhs) const { return !operator==(_rhs); }
|
||||
public:
|
||||
TypeClass(TypeClass const& _typeClass): m_index(_typeClass.m_index) {}
|
||||
TypeClass& operator=(TypeClass const& _typeConstructor)
|
||||
{
|
||||
m_index = _typeConstructor.m_index;
|
||||
return *this;
|
||||
}
|
||||
bool operator<(TypeClass const& _rhs) const
|
||||
{
|
||||
return m_index < _rhs.m_index;
|
||||
}
|
||||
bool operator==(TypeClass const& _rhs) const
|
||||
{
|
||||
return m_index == _rhs.m_index;
|
||||
}
|
||||
bool operator!=(TypeClass const& _rhs) const
|
||||
{
|
||||
return m_index != _rhs.m_index;
|
||||
}
|
||||
private:
|
||||
friend class TypeSystem;
|
||||
TypeClass(size_t _index): m_index(_index) {}
|
||||
size_t m_index = 0;
|
||||
};
|
||||
|
||||
struct Sort
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include <fmt/format.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity;
|
||||
using namespace solidity::frontend;
|
||||
using namespace solidity::frontend::experimental;
|
||||
|
||||
@ -122,17 +123,36 @@ TypeEnvironment TypeEnvironment::clone() const
|
||||
|
||||
TypeSystem::TypeSystem()
|
||||
{
|
||||
Sort typeSort{{TypeClass{BuiltinClass::Type}}};
|
||||
m_typeConstructors[BuiltinType::TypeFunction] = TypeConstructorInfo{
|
||||
"tfun",
|
||||
{Arity{vector<Sort>{{typeSort},{typeSort}}, TypeClass{BuiltinClass::Kind}}}
|
||||
};
|
||||
m_typeConstructors[BuiltinType::Function] = TypeConstructorInfo{
|
||||
"fun",
|
||||
{
|
||||
Arity{vector<Sort>{{typeSort, typeSort}}, TypeClass{BuiltinClass::Type}},
|
||||
}
|
||||
auto declarePrimitiveClass = [&](std::string _name) {
|
||||
return std::visit(util::GenericVisitor{
|
||||
[](std::string _error) -> TypeClass {
|
||||
solAssert(false, _error);
|
||||
},
|
||||
[](TypeClass _class) -> TypeClass { return _class; }
|
||||
}, declareTypeClass(freshVariable({}), {}, _name, nullptr));
|
||||
};
|
||||
|
||||
m_primitiveTypeClasses.emplace(PrimitiveClass::Type, declarePrimitiveClass("type"));
|
||||
m_primitiveTypeClasses.emplace(PrimitiveClass::Kind, declarePrimitiveClass("kind"));
|
||||
|
||||
for (auto [type, name, arity]: std::initializer_list<std::tuple<PrimitiveType, const char*, uint64_t>> {
|
||||
{PrimitiveType::TypeFunction, "tfun", 2},
|
||||
{PrimitiveType::Function, "fun", 2},
|
||||
{PrimitiveType::Void, "void", 0},
|
||||
{PrimitiveType::Unit, "unit", 0},
|
||||
{PrimitiveType::Pair, "pair", 2},
|
||||
{PrimitiveType::Word, "word", 0},
|
||||
{PrimitiveType::Integer, "integer", 0},
|
||||
{PrimitiveType::Bool, "bool", 0},
|
||||
})
|
||||
m_primitiveTypeConstructors.emplace(type, declareTypeConstructor(name, name, arity, nullptr));
|
||||
|
||||
TypeClass classType = primitiveClass(PrimitiveClass::Type);
|
||||
TypeClass classKind = primitiveClass(PrimitiveClass::Kind);
|
||||
Sort typeSort{{classType}};
|
||||
m_typeConstructors.at(m_primitiveTypeConstructors.at(PrimitiveType::TypeFunction).m_index).arities = {Arity{vector<Sort>{{typeSort},{typeSort}}, classKind}};
|
||||
m_typeConstructors.at(m_primitiveTypeConstructors.at(PrimitiveType::Function).m_index).arities = {Arity{vector<Sort>{{typeSort, typeSort}}, classType}};
|
||||
m_typeConstructors.at(m_primitiveTypeConstructors.at(PrimitiveType::Function).m_index).arities = {Arity{vector<Sort>{{typeSort, typeSort}}, classType}};
|
||||
}
|
||||
|
||||
experimental::Type TypeSystem::freshVariable(Sort _sort)
|
||||
@ -143,18 +163,21 @@ experimental::Type TypeSystem::freshVariable(Sort _sort)
|
||||
|
||||
experimental::Type TypeSystem::freshTypeVariable(Sort _sort)
|
||||
{
|
||||
_sort.classes.emplace(TypeClass{BuiltinClass::Type});
|
||||
_sort.classes.emplace(primitiveClass(PrimitiveClass::Type));
|
||||
return freshVariable(_sort);
|
||||
}
|
||||
|
||||
experimental::Type TypeSystem::freshKindVariable(Sort _sort)
|
||||
{
|
||||
_sort.classes.emplace(TypeClass{BuiltinClass::Kind});
|
||||
_sort.classes.emplace(primitiveClass(PrimitiveClass::Kind));
|
||||
return freshVariable(_sort);
|
||||
}
|
||||
|
||||
vector<TypeEnvironment::UnificationFailure> TypeEnvironment::instantiate(TypeVariable _variable, Type _type)
|
||||
{
|
||||
for (auto typeVar: TypeEnvironmentHelpers{*this}.typeVars(_type))
|
||||
if (typeVar.index() == _variable.index())
|
||||
return {UnificationFailure{RecursiveUnification{_variable, _type}}};
|
||||
Sort typeSort = sort(_type);
|
||||
if (!(_variable.sort() <= typeSort))
|
||||
{
|
||||
@ -189,6 +212,9 @@ experimental::Type TypeEnvironment::resolveRecursive(Type _type) const
|
||||
[&](TypeVariable const&) -> Type {
|
||||
return _type;
|
||||
},
|
||||
[&](std::monostate) -> Type {
|
||||
return _type;
|
||||
}
|
||||
}, resolve(_type));
|
||||
}
|
||||
|
||||
@ -221,21 +247,25 @@ Sort TypeEnvironment::sort(Type _type) const
|
||||
return sort;
|
||||
},
|
||||
[](TypeVariable const& _variable) -> Sort { return _variable.sort(); },
|
||||
[](std::monostate) -> Sort { solAssert(false); }
|
||||
}, _type);
|
||||
}
|
||||
|
||||
void TypeSystem::declareTypeConstructor(TypeConstructor _typeConstructor, std::string _name, size_t _arguments)
|
||||
TypeConstructor TypeSystem::declareTypeConstructor(string _name, string _canonicalName, size_t _arguments, Declaration const* _declaration)
|
||||
{
|
||||
Sort baseSort{{TypeClass{BuiltinClass::Type}}};
|
||||
bool newlyInserted = m_typeConstructors.emplace(std::make_pair(_typeConstructor, TypeConstructorInfo{
|
||||
solAssert(m_canonicalTypeNames.insert(_canonicalName).second, "Duplicate canonical type name.");
|
||||
Sort baseSort{{primitiveClass(PrimitiveClass::Type)}};
|
||||
size_t index = m_typeConstructors.size();
|
||||
m_typeConstructors.emplace_back(TypeConstructorInfo{
|
||||
_name,
|
||||
{Arity{vector<Sort>{_arguments, baseSort}, TypeClass{BuiltinClass::Type}}}
|
||||
})).second;
|
||||
// TODO: proper error handling.
|
||||
solAssert(newlyInserted, "Type constructor already declared.");
|
||||
_canonicalName,
|
||||
{Arity{vector<Sort>{_arguments, baseSort}, primitiveClass(PrimitiveClass::Type)}},
|
||||
_declaration
|
||||
});
|
||||
return TypeConstructor{index};
|
||||
}
|
||||
|
||||
std::optional<std::string> TypeSystem::declareTypeClass(TypeClass _class, Type _typeVariable, std::map<std::string, Type> _functions)
|
||||
std::variant<TypeClass, std::string> TypeSystem::declareTypeClass(Type _typeVariable, std::map<std::string, Type> _functions, std::string _name, Declaration const* _declaration)
|
||||
{
|
||||
TypeVariable const* typeVariable = get_if<TypeVariable>(&_typeVariable);
|
||||
if (!typeVariable)
|
||||
@ -251,19 +281,34 @@ std::optional<std::string> TypeSystem::declareTypeClass(TypeClass _class, Type _
|
||||
return "Function " + functionName + " depends on invalid type variable.";
|
||||
}
|
||||
|
||||
if (!m_typeClasses.emplace(std::make_pair(_class, TypeClassInfo{
|
||||
size_t index = m_typeClasses.size();
|
||||
m_typeClasses.emplace_back(TypeClassInfo{
|
||||
_typeVariable,
|
||||
std::move(_functions)
|
||||
})).second)
|
||||
return "Type class already declared";
|
||||
return nullopt;
|
||||
std::move(_functions),
|
||||
_name,
|
||||
_declaration
|
||||
});
|
||||
TypeClass typeClass{index};
|
||||
|
||||
return typeClass;
|
||||
}
|
||||
|
||||
std::optional<experimental::Type> TypeEnvironment::typeClassFunction(TypeClass _class, std::string _name)
|
||||
{
|
||||
auto* type = util::valueOrNullptr(m_typeSystem.typeClassInfo(_class).functions, _name);
|
||||
if (!type)
|
||||
return nullopt;
|
||||
Type functionType = fresh(*type);
|
||||
auto typeVars = TypeEnvironmentHelpers{*this}.typeVars(functionType);
|
||||
solAssert(typeVars.size() == 1);
|
||||
solAssert(unify(typeVars.front(), m_typeSystem.freshTypeVariable({{_class}})).empty());
|
||||
return functionType;
|
||||
}
|
||||
|
||||
experimental::Type TypeSystem::type(TypeConstructor _constructor, std::vector<Type> _arguments) const
|
||||
{
|
||||
// TODO: proper error handling
|
||||
auto const& info = m_typeConstructors.at(_constructor);
|
||||
auto const& info = m_typeConstructors.at(_constructor.m_index);
|
||||
solAssert(info.arguments() == _arguments.size(), "Invalid arity.");
|
||||
return TypeConstant{_constructor, _arguments};
|
||||
}
|
||||
@ -292,6 +337,7 @@ experimental::Type TypeEnvironment::fresh(Type _type)
|
||||
}
|
||||
return mapping[_var.index()] = m_typeSystem.freshTypeVariable(_var.sort());
|
||||
},
|
||||
[](std::monostate) -> Type { solAssert(false); }
|
||||
}, resolve(_type));
|
||||
};
|
||||
return freshImpl(_type, freshImpl);
|
||||
@ -302,26 +348,24 @@ std::optional<std::string> TypeSystem::instantiateClass(Type _instanceVariable,
|
||||
if (!TypeSystemHelpers{*this}.isTypeConstant(_instanceVariable))
|
||||
return "Invalid instance variable.";
|
||||
auto [typeConstructor, typeArguments] = TypeSystemHelpers{*this}.destTypeConstant(_instanceVariable);
|
||||
auto& typeConstructorInfo = m_typeConstructors.at(typeConstructor);
|
||||
auto& typeConstructorInfo = m_typeConstructors.at(typeConstructor.m_index);
|
||||
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.";
|
||||
auto const& classInfo = typeClassInfo(_arity.typeClass);
|
||||
|
||||
TypeEnvironment newEnv = m_globalTypeEnvironment.clone();
|
||||
|
||||
std::set<size_t> typeVariables;
|
||||
|
||||
Type classVariable = classInfo->typeVariable;
|
||||
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)
|
||||
for (auto [name, classFunctionType]: classInfo.functions)
|
||||
{
|
||||
if (!_functionTypes.count(name))
|
||||
return "Missing function: " + name;
|
||||
|
@ -25,6 +25,10 @@
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
namespace solidity::frontend
|
||||
{
|
||||
class Declaration;
|
||||
}
|
||||
namespace solidity::frontend::experimental
|
||||
{
|
||||
|
||||
@ -40,12 +44,14 @@ public:
|
||||
Type fresh(Type _type);
|
||||
struct TypeMismatch { Type a; Type b; };
|
||||
struct SortMismatch { Type type; Sort sort; };
|
||||
using UnificationFailure = std::variant<TypeMismatch, SortMismatch>;
|
||||
struct RecursiveUnification { Type var; Type type; };
|
||||
using UnificationFailure = std::variant<TypeMismatch, SortMismatch, RecursiveUnification>;
|
||||
[[nodiscard]] std::vector<UnificationFailure> unify(Type _a, Type _b);
|
||||
Sort sort(Type _type) const;
|
||||
bool typeEquals(Type _lhs, Type _rhs) const;
|
||||
TypeSystem& typeSystem() { return m_typeSystem; }
|
||||
TypeSystem const& typeSystem() const { return m_typeSystem; }
|
||||
std::optional<Type> typeClassFunction(TypeClass _class, std::string _name);
|
||||
private:
|
||||
TypeEnvironment(TypeEnvironment&& _env): m_typeSystem(_env.m_typeSystem), m_typeVariables(std::move(_env.m_typeVariables)) {}
|
||||
[[nodiscard]] std::vector<TypeEnvironment::UnificationFailure> instantiate(TypeVariable _variable, Type _type);
|
||||
@ -59,7 +65,9 @@ public:
|
||||
struct TypeConstructorInfo
|
||||
{
|
||||
std::string name;
|
||||
std::string canonicalName;
|
||||
std::vector<Arity> arities;
|
||||
Declaration const* typeDeclaration = nullptr;
|
||||
size_t arguments() const
|
||||
{
|
||||
solAssert(!arities.empty());
|
||||
@ -70,33 +78,52 @@ public:
|
||||
{
|
||||
Type typeVariable;
|
||||
std::map<std::string, Type> functions;
|
||||
std::string name;
|
||||
Declaration const* classDeclaration = nullptr;
|
||||
};
|
||||
TypeSystem();
|
||||
TypeSystem(TypeSystem const&) = delete;
|
||||
TypeSystem const& operator=(TypeSystem const&) = delete;
|
||||
Type type(PrimitiveType _typeConstructor, std::vector<Type> _arguments) const
|
||||
{
|
||||
return type(m_primitiveTypeConstructors.at(_typeConstructor), std::move(_arguments));
|
||||
}
|
||||
Type type(TypeConstructor _typeConstructor, std::vector<Type> _arguments) const;
|
||||
std::string typeName(TypeConstructor _typeConstructor) const
|
||||
{
|
||||
// TODO: proper error handling
|
||||
return m_typeConstructors.at(_typeConstructor).name;
|
||||
return m_typeConstructors.at(_typeConstructor.m_index).name;
|
||||
}
|
||||
std::string canonicalName(TypeConstructor _typeConstructor) const
|
||||
{
|
||||
// TODO: proper error handling
|
||||
return m_typeConstructors.at(_typeConstructor.m_index).canonicalName;
|
||||
}
|
||||
TypeConstructor declareTypeConstructor(std::string _name, std::string _canonicalName, size_t _arguments, Declaration const* _declaration);
|
||||
TypeConstructor constructor(PrimitiveType _type) const
|
||||
{
|
||||
return m_primitiveTypeConstructors.at(_type);
|
||||
}
|
||||
TypeClass primitiveClass(PrimitiveClass _class) const
|
||||
{
|
||||
return m_primitiveTypeClasses.at(_class);
|
||||
}
|
||||
void declareTypeConstructor(TypeConstructor _typeConstructor, std::string _name, size_t _arguments);
|
||||
size_t constructorArguments(TypeConstructor _typeConstructor) const
|
||||
{
|
||||
// TODO: error handling
|
||||
return m_typeConstructors.at(_typeConstructor).arguments();
|
||||
return m_typeConstructors.at(_typeConstructor.m_index).arguments();
|
||||
}
|
||||
TypeConstructorInfo const& constructorInfo(TypeConstructor _typeConstructor) const
|
||||
{
|
||||
// TODO: error handling
|
||||
return m_typeConstructors.at(_typeConstructor);
|
||||
return m_typeConstructors.at(_typeConstructor.m_index);
|
||||
}
|
||||
TypeClassInfo const* typeClassInfo(TypeClass _class) const
|
||||
TypeConstructorInfo const& constructorInfo(PrimitiveType _typeConstructor) const
|
||||
{
|
||||
return util::valueOrNullptr(m_typeClasses, _class);
|
||||
return constructorInfo(constructor(_typeConstructor));
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<std::string> declareTypeClass(TypeClass _class, Type _typeVariable, std::map<std::string, Type> _functions);
|
||||
std::variant<TypeClass, std::string> declareTypeClass(Type _typeVariable, std::map<std::string, Type> _functions, std::string _name, Declaration const* _declaration);
|
||||
[[nodiscard]] std::optional<std::string> instantiateClass(Type _instanceVariable, Arity _arity, std::map<std::string, Type> _functions);
|
||||
|
||||
Type freshTypeVariable(Sort _sort);
|
||||
@ -106,10 +133,20 @@ public:
|
||||
TypeEnvironment& env() { return m_globalTypeEnvironment; }
|
||||
|
||||
Type freshVariable(Sort _sort);
|
||||
std::string typeClassName(TypeClass _class) const { return m_typeClasses.at(_class.m_index).name; }
|
||||
Declaration const* typeClassDeclaration(TypeClass _class) const { return m_typeClasses.at(_class.m_index).classDeclaration; }
|
||||
private:
|
||||
friend class TypeEnvironment;
|
||||
TypeClassInfo const& typeClassInfo(TypeClass _class) const
|
||||
{
|
||||
return m_typeClasses.at(_class.m_index);
|
||||
}
|
||||
size_t m_numTypeVariables = 0;
|
||||
std::map<TypeConstructor, TypeConstructorInfo> m_typeConstructors;
|
||||
std::map<TypeClass, TypeClassInfo> m_typeClasses;
|
||||
std::map<PrimitiveType, TypeConstructor> m_primitiveTypeConstructors;
|
||||
std::map<PrimitiveClass, TypeClass> m_primitiveTypeClasses;
|
||||
std::set<std::string> m_canonicalTypeNames;
|
||||
std::vector<TypeConstructorInfo> m_typeConstructors;
|
||||
std::vector<TypeClassInfo> m_typeClasses;
|
||||
TypeEnvironment m_globalTypeEnvironment{*this};
|
||||
};
|
||||
|
||||
|
@ -19,6 +19,10 @@
|
||||
|
||||
#include <libsolidity/ast/experimental/TypeSystemHelper.h>
|
||||
#include <libsolidity/ast/AST.h>
|
||||
|
||||
#include <libsolidity/analysis/experimental/Analysis.h>
|
||||
#include <libsolidity/analysis/experimental/TypeRegistration.h>
|
||||
|
||||
#include <libsolutil/Visitor.h>
|
||||
|
||||
#include <range/v3/to_container.hpp>
|
||||
@ -33,69 +37,70 @@ using namespace solidity::langutil;
|
||||
using namespace solidity::frontend;
|
||||
using namespace solidity::frontend::experimental;
|
||||
|
||||
std::optional<TypeConstructor> experimental::typeConstructorFromTypeName(TypeName const& _typeName)
|
||||
/*std::optional<TypeConstructor> experimental::typeConstructorFromTypeName(Analysis const& _analysis, TypeName const& _typeName)
|
||||
{
|
||||
if (auto const* elementaryTypeName = dynamic_cast<ElementaryTypeName const*>(&_typeName))
|
||||
{
|
||||
if (auto constructor = typeConstructorFromToken(elementaryTypeName->typeName().token()))
|
||||
if (auto constructor = typeConstructorFromToken(_analysis, 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 _analysis.annotation<TypeRegistration>(*referencedDeclaration).typeConstructor;
|
||||
}
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
std::optional<TypeConstructor> experimental::typeConstructorFromToken(langutil::Token _token)
|
||||
}*/
|
||||
/*
|
||||
std::optional<TypeConstructor> experimental::typeConstructorFromToken(Analysis const& _analysis, langutil::Token _token)
|
||||
{
|
||||
TypeSystem const& typeSystem = _analysis.typeSystem();
|
||||
switch(_token)
|
||||
{
|
||||
case Token::Void:
|
||||
return BuiltinType::Void;
|
||||
return typeSystem.builtinConstructor(BuiltinType::Void);
|
||||
case Token::Fun:
|
||||
return BuiltinType::Function;
|
||||
return typeSystem.builtinConstructor(BuiltinType::Function);
|
||||
case Token::Unit:
|
||||
return BuiltinType::Unit;
|
||||
return typeSystem.builtinConstructor(BuiltinType::Unit);
|
||||
case Token::Pair:
|
||||
return BuiltinType::Pair;
|
||||
return typeSystem.builtinConstructor(BuiltinType::Pair);
|
||||
case Token::Word:
|
||||
return BuiltinType::Word;
|
||||
return typeSystem.builtinConstructor(BuiltinType::Word);
|
||||
case Token::Integer:
|
||||
return BuiltinType::Integer;
|
||||
return typeSystem.builtinConstructor(BuiltinType::Integer);
|
||||
case Token::Bool:
|
||||
return BuiltinType::Bool;
|
||||
return typeSystem.builtinConstructor(BuiltinType::Bool);
|
||||
default:
|
||||
return nullopt;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
std::optional<TypeClass> experimental::typeClassFromToken(langutil::Token _token)
|
||||
std::optional<BuiltinClass> experimental::builtinClassFromToken(langutil::Token _token)
|
||||
{
|
||||
switch (_token)
|
||||
{
|
||||
case Token::Integer:
|
||||
return TypeClass{BuiltinClass::Integer};
|
||||
return BuiltinClass::Integer;
|
||||
case Token::Mul:
|
||||
return TypeClass{BuiltinClass::Mul};
|
||||
return BuiltinClass::Mul;
|
||||
case Token::Add:
|
||||
return TypeClass{BuiltinClass::Add};
|
||||
return BuiltinClass::Add;
|
||||
case Token::Equal:
|
||||
return TypeClass{BuiltinClass::Equal};
|
||||
return BuiltinClass::Equal;
|
||||
case Token::LessThan:
|
||||
return TypeClass{BuiltinClass::Less};
|
||||
return BuiltinClass::Less;
|
||||
case Token::LessThanOrEqual:
|
||||
return TypeClass{BuiltinClass::LessOrEqual};
|
||||
return BuiltinClass::LessOrEqual;
|
||||
case Token::GreaterThan:
|
||||
return TypeClass{BuiltinClass::Greater};
|
||||
return BuiltinClass::Greater;
|
||||
case Token::GreaterThanOrEqual:
|
||||
return TypeClass{BuiltinClass::GreaterOrEqual};
|
||||
return BuiltinClass::GreaterOrEqual;
|
||||
default:
|
||||
return nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
std::optional<TypeClass> experimental::typeClassFromTypeClassName(TypeClassName const& _typeClass)
|
||||
{
|
||||
return std::visit(util::GenericVisitor{
|
||||
@ -110,16 +115,16 @@ std::optional<TypeClass> experimental::typeClassFromTypeClassName(TypeClassName
|
||||
}
|
||||
}, _typeClass.name());
|
||||
}
|
||||
|
||||
*/
|
||||
experimental::Type TypeSystemHelpers::tupleType(vector<Type> _elements) const
|
||||
{
|
||||
if (_elements.empty())
|
||||
return typeSystem.type(BuiltinType::Unit, {});
|
||||
return typeSystem.type(PrimitiveType::Unit, {});
|
||||
if (_elements.size() == 1)
|
||||
return _elements.front();
|
||||
Type result = _elements.back();
|
||||
for (Type type: _elements | ranges::views::reverse | ranges::views::drop_exactly(1))
|
||||
result = typeSystem.type(BuiltinType::Pair, {type, result});
|
||||
result = typeSystem.type(PrimitiveType::Pair, {type, result});
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -127,15 +132,11 @@ vector<experimental::Type> TypeSystemHelpers::destTupleType(Type _tupleType) con
|
||||
{
|
||||
if (!isTypeConstant(_tupleType))
|
||||
return {_tupleType};
|
||||
TypeConstructor pairConstructor = typeSystem.constructor(PrimitiveType::Pair);
|
||||
auto [constructor, arguments] = destTypeConstant(_tupleType);
|
||||
if (auto const* builtinType = get_if<BuiltinType>(&constructor))
|
||||
{
|
||||
if (*builtinType == BuiltinType::Unit)
|
||||
return {};
|
||||
else if (*builtinType != BuiltinType::Pair)
|
||||
return {_tupleType};
|
||||
}
|
||||
else
|
||||
if (constructor == typeSystem.constructor(PrimitiveType::Unit))
|
||||
return {};
|
||||
if (constructor != pairConstructor)
|
||||
return {_tupleType};
|
||||
solAssert(arguments.size() == 2);
|
||||
|
||||
@ -147,8 +148,7 @@ vector<experimental::Type> TypeSystemHelpers::destTupleType(Type _tupleType) con
|
||||
if (!isTypeConstant(tail))
|
||||
break;
|
||||
auto [tailConstructor, tailArguments] = destTypeConstant(tail);
|
||||
auto const* builtinType = get_if<BuiltinType>(&tailConstructor);
|
||||
if(!builtinType || *builtinType != BuiltinType::Pair)
|
||||
if (tailConstructor != pairConstructor)
|
||||
break;
|
||||
solAssert(tailArguments.size() == 2);
|
||||
result.emplace_back(tailArguments.front());
|
||||
@ -185,14 +185,13 @@ bool TypeSystemHelpers::isTypeConstant(Type _type) const
|
||||
|
||||
experimental::Type TypeSystemHelpers::functionType(experimental::Type _argType, experimental::Type _resultType) const
|
||||
{
|
||||
return typeSystem.type(BuiltinType::Function, {_argType, _resultType});
|
||||
return typeSystem.type(PrimitiveType::Function, {_argType, _resultType});
|
||||
}
|
||||
|
||||
tuple<experimental::Type, experimental::Type> TypeSystemHelpers::destFunctionType(Type _functionType) const
|
||||
{
|
||||
auto [constructor, arguments] = destTypeConstant(_functionType);
|
||||
auto const* builtinType = get_if<BuiltinType>(&constructor);
|
||||
solAssert(builtinType && *builtinType == BuiltinType::Function);
|
||||
solAssert(constructor == typeSystem.constructor(PrimitiveType::Function));
|
||||
solAssert(arguments.size() == 2);
|
||||
return make_tuple(arguments.front(), arguments.back());
|
||||
}
|
||||
@ -202,20 +201,18 @@ bool TypeSystemHelpers::isFunctionType(Type _type) const
|
||||
if (!isTypeConstant(_type))
|
||||
return false;
|
||||
auto constructor = get<0>(destTypeConstant(_type));
|
||||
auto const* builtinType = get_if<BuiltinType>(&constructor);
|
||||
return builtinType && *builtinType == BuiltinType::Function;
|
||||
return constructor == typeSystem.constructor(PrimitiveType::Function);
|
||||
}
|
||||
|
||||
experimental::Type TypeSystemHelpers::typeFunctionType(experimental::Type _argType, experimental::Type _resultType) const
|
||||
{
|
||||
return typeSystem.type(BuiltinType::TypeFunction, {_argType, _resultType});
|
||||
return typeSystem.type(PrimitiveType::TypeFunction, {_argType, _resultType});
|
||||
}
|
||||
|
||||
tuple<experimental::Type, experimental::Type> TypeSystemHelpers::destTypeFunctionType(Type _functionType) const
|
||||
{
|
||||
auto [constructor, arguments] = destTypeConstant(_functionType);
|
||||
auto const* builtinType = get_if<BuiltinType>(&constructor);
|
||||
solAssert(builtinType && *builtinType == BuiltinType::TypeFunction);
|
||||
solAssert(constructor == typeSystem.constructor(PrimitiveType::TypeFunction));
|
||||
solAssert(arguments.size() == 2);
|
||||
return make_tuple(arguments.front(), arguments.back());
|
||||
}
|
||||
@ -225,8 +222,7 @@ bool TypeSystemHelpers::isTypeFunctionType(Type _type) const
|
||||
if (!isTypeConstant(_type))
|
||||
return false;
|
||||
auto constructor = get<0>(destTypeConstant(_type));
|
||||
auto const* builtinType = get_if<BuiltinType>(&constructor);
|
||||
return builtinType && *builtinType == BuiltinType::TypeFunction;
|
||||
return constructor == typeSystem.constructor(PrimitiveType::TypeFunction);
|
||||
}
|
||||
|
||||
vector<experimental::Type> TypeEnvironmentHelpers::typeVars(Type _type) const
|
||||
@ -243,7 +239,7 @@ vector<experimental::Type> TypeEnvironmentHelpers::typeVars(Type _type) const
|
||||
if (indices.emplace(_var.index()).second)
|
||||
typeVars.emplace_back(_var);
|
||||
},
|
||||
// TODO: move to env helpers?
|
||||
[](std::monostate) { solAssert(false); }
|
||||
}, env.resolve(_type));
|
||||
};
|
||||
typeVarsImpl(_type, typeVarsImpl);
|
||||
@ -259,83 +255,39 @@ std::string TypeSystemHelpers::sortToString(Sort _sort) const
|
||||
case 0:
|
||||
return "()";
|
||||
case 1:
|
||||
return _sort.classes.begin()->toString();
|
||||
return typeSystem.typeClassName(*_sort.classes.begin());
|
||||
default:
|
||||
{
|
||||
std::stringstream stream;
|
||||
stream << "(";
|
||||
for (auto typeClass: _sort.classes | ranges::views::drop_last(1))
|
||||
stream << typeClass.toString() << ", ";
|
||||
stream << _sort.classes.rbegin()->toString() << ")";
|
||||
stream << typeSystem.typeClassName(typeClass) << ", ";
|
||||
stream << typeSystem.typeClassName(*_sort.classes.rbegin()) << ")";
|
||||
return stream.str();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string TypeEnvironmentHelpers::canonicalTypeName(Type _type) const
|
||||
string TypeEnvironmentHelpers::canonicalTypeName(Type _type) const
|
||||
{
|
||||
return visit(util::GenericVisitor{
|
||||
[&](TypeConstant const& _type) {
|
||||
[&](TypeConstant _type) -> string {
|
||||
std::stringstream stream;
|
||||
auto printTypeArguments = [&]() {
|
||||
if (!_type.arguments.empty())
|
||||
{
|
||||
stream << "$";
|
||||
for (auto type: _type.arguments | ranges::views::drop_last(1))
|
||||
stream << env.typeSystem().constructorInfo(_type.constructor).canonicalName;
|
||||
if (!_type.arguments.empty())
|
||||
{
|
||||
stream << "$";
|
||||
for (auto type: _type.arguments | ranges::views::drop_last(1))
|
||||
stream << canonicalTypeName(type) << "$";
|
||||
stream << canonicalTypeName(_type.arguments.back());
|
||||
stream << "$";
|
||||
}
|
||||
};
|
||||
std::visit(util::GenericVisitor{
|
||||
[&](Declaration const* _declaration) {
|
||||
if (auto const* typeDeclarationAnnotation = dynamic_cast<TypeDeclarationAnnotation const*>(&_declaration->annotation()))
|
||||
stream << *typeDeclarationAnnotation->canonicalName;
|
||||
else
|
||||
// TODO: canonical name
|
||||
stream << _declaration->name();
|
||||
printTypeArguments();
|
||||
},
|
||||
[&](BuiltinType _builtinType) {
|
||||
switch(_builtinType)
|
||||
{
|
||||
case BuiltinType::Type:
|
||||
stream << "type";
|
||||
break;
|
||||
case BuiltinType::Sort:
|
||||
stream << "sort";
|
||||
break;
|
||||
case BuiltinType::Void:
|
||||
stream << "void";
|
||||
break;
|
||||
case BuiltinType::Function:
|
||||
stream << "fun";
|
||||
break;
|
||||
case BuiltinType::TypeFunction:
|
||||
stream << "tfun";
|
||||
break;
|
||||
case BuiltinType::Unit:
|
||||
stream << "unit";
|
||||
break;
|
||||
case BuiltinType::Pair:
|
||||
stream << "pair";
|
||||
break;
|
||||
case BuiltinType::Word:
|
||||
stream << "word";
|
||||
break;
|
||||
case BuiltinType::Bool:
|
||||
stream << "bool";
|
||||
break;
|
||||
case BuiltinType::Integer:
|
||||
stream << "integer";
|
||||
break;
|
||||
}
|
||||
printTypeArguments();
|
||||
}
|
||||
}, _type.constructor);
|
||||
stream << canonicalTypeName(_type.arguments.back());
|
||||
stream << "$";
|
||||
}
|
||||
return stream.str();
|
||||
},
|
||||
[](TypeVariable const&)-> string {
|
||||
[](TypeVariable) -> string {
|
||||
solAssert(false);
|
||||
},
|
||||
[](std::monostate) -> string {
|
||||
solAssert(false);
|
||||
},
|
||||
}, env.resolve(_type));
|
||||
@ -343,60 +295,41 @@ std::string TypeEnvironmentHelpers::canonicalTypeName(Type _type) const
|
||||
|
||||
std::string TypeEnvironmentHelpers::typeToString(Type const& _type) const
|
||||
{
|
||||
std::map<TypeConstructor, std::function<string(std::vector<Type>)>> formatters{
|
||||
{env.typeSystem().constructor(PrimitiveType::Function), [&](auto const& _args) {
|
||||
solAssert(_args.size() == 2);
|
||||
return fmt::format("{} -> {}", typeToString(_args.front()), typeToString(_args.back()));
|
||||
}},
|
||||
{env.typeSystem().constructor(PrimitiveType::Unit), [&](auto const& _args) {
|
||||
solAssert(_args.size() == 0);
|
||||
return "()";
|
||||
}},
|
||||
{env.typeSystem().constructor(PrimitiveType::Pair), [&](auto const&) {
|
||||
auto tupleTypes = TypeSystemHelpers{env.typeSystem()}.destTupleType(_type);
|
||||
string result = "(";
|
||||
for (auto type: tupleTypes | ranges::views::drop_last(1))
|
||||
result += typeToString(type) + ", ";
|
||||
result += typeToString(tupleTypes.back()) + ")";
|
||||
return result;
|
||||
}},
|
||||
};
|
||||
return std::visit(util::GenericVisitor{
|
||||
[&](TypeConstant const& _type) {
|
||||
if (auto* formatter = util::valueOrNullptr(formatters, _type.constructor))
|
||||
return (*formatter)(_type.arguments);
|
||||
std::stringstream stream;
|
||||
auto printTypeArguments = [&]() {
|
||||
if (!_type.arguments.empty())
|
||||
{
|
||||
stream << "(";
|
||||
for (auto type: _type.arguments | ranges::views::drop_last(1))
|
||||
stream << typeToString(type) << ", ";
|
||||
stream << typeToString(_type.arguments.back());
|
||||
stream << ")";
|
||||
}
|
||||
};
|
||||
std::visit(util::GenericVisitor{
|
||||
[&](Declaration const* _declaration) {
|
||||
stream << env.typeSystem().typeName(_declaration);
|
||||
printTypeArguments();
|
||||
},
|
||||
[&](BuiltinType _builtinType) {
|
||||
switch (_builtinType)
|
||||
{
|
||||
case BuiltinType::Function:
|
||||
solAssert(_type.arguments.size() == 2);
|
||||
stream << fmt::format("{} -> {}", typeToString(_type.arguments.front()), typeToString(_type.arguments.back()));
|
||||
break;
|
||||
case BuiltinType::Unit:
|
||||
solAssert(_type.arguments.empty());
|
||||
stream << "()";
|
||||
break;
|
||||
case BuiltinType::Pair:
|
||||
{
|
||||
auto tupleTypes = TypeSystemHelpers{env.typeSystem()}.destTupleType(_type);
|
||||
stream << "(";
|
||||
for (auto type: tupleTypes | ranges::views::drop_last(1))
|
||||
stream << typeToString(type) << ", ";
|
||||
stream << typeToString(tupleTypes.back()) << ")";
|
||||
break;
|
||||
}
|
||||
case BuiltinType::Type:
|
||||
{
|
||||
solAssert(_type.arguments.size() == 1);
|
||||
stream << "TYPE(" << typeToString(_type.arguments.front()) << ")";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
stream << env.typeSystem().typeName(_builtinType);
|
||||
printTypeArguments();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}, _type.constructor);
|
||||
stream << env.typeSystem().constructorInfo(_type.constructor).name;
|
||||
if (!_type.arguments.empty())
|
||||
{
|
||||
stream << "(";
|
||||
for (auto type: _type.arguments | ranges::views::drop_last(1))
|
||||
stream << typeToString(type) << ", ";
|
||||
stream << typeToString(_type.arguments.back());
|
||||
stream << ")";
|
||||
}
|
||||
return stream.str();
|
||||
},
|
||||
[](TypeVariable const& _type) {
|
||||
[&](TypeVariable const& _type) {
|
||||
std::stringstream stream;
|
||||
std::string varName;
|
||||
size_t index = _type.index();
|
||||
@ -410,17 +343,18 @@ std::string TypeEnvironmentHelpers::typeToString(Type const& _type) const
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
stream << ":" << _type.sort().classes.begin()->toString();
|
||||
stream << ":" << env.typeSystem().typeClassName(*_type.sort().classes.begin());
|
||||
break;
|
||||
default:
|
||||
stream << ":(";
|
||||
for (auto typeClass: _type.sort().classes | ranges::views::drop_last(1))
|
||||
stream << typeClass.toString() << ", ";
|
||||
stream << _type.sort().classes.rbegin()->toString();
|
||||
stream << env.typeSystem().typeClassName(typeClass) << ", ";
|
||||
stream << env.typeSystem().typeClassName(*_type.sort().classes.rbegin());
|
||||
stream << ")";
|
||||
break;
|
||||
}
|
||||
return stream.str();
|
||||
},
|
||||
[](std::monostate) -> string { solAssert(false); }
|
||||
}, env.resolve(_type));
|
||||
}
|
||||
|
@ -23,11 +23,12 @@
|
||||
|
||||
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);
|
||||
class Analysis;
|
||||
enum class BuiltinClass;
|
||||
//std::optional<TypeConstructor> typeConstructorFromTypeName(Analysis const& _analysis, TypeName const& _typeName);
|
||||
//std::optional<TypeConstructor> typeConstructorFromToken(Analysis const& _analysis, langutil::Token _token);
|
||||
//std::optional<TypeClass> typeClassFromTypeClassName(TypeClassName const& _typeClass);
|
||||
std::optional<BuiltinClass> builtinClassFromToken(langutil::Token _token);
|
||||
|
||||
struct TypeSystemHelpers
|
||||
{
|
||||
|
@ -45,8 +45,8 @@ struct IRGenerationContext
|
||||
}
|
||||
struct QueuedFunction
|
||||
{
|
||||
FunctionDefinition const* function;
|
||||
Type type;
|
||||
FunctionDefinition const* function = nullptr;
|
||||
Type type = std::monostate{};
|
||||
};
|
||||
std::list<QueuedFunction> functionQueue;
|
||||
std::map<FunctionDefinition const*, std::vector<Type>> generatedFunctions;
|
||||
|
@ -108,13 +108,13 @@ string IRGenerator::generate(ContractDefinition const& _contract)
|
||||
|
||||
while (!m_context.functionQueue.empty())
|
||||
{
|
||||
auto [function, type] = m_context.functionQueue.front();
|
||||
auto queueEntry = m_context.functionQueue.front();
|
||||
m_context.functionQueue.pop_front();
|
||||
auto& generatedTypes = m_context.generatedFunctions[function];
|
||||
if (!util::contains_if(generatedTypes, [&, type=type](auto _generatedType) { return m_context.env->typeEquals(_generatedType, type); }))
|
||||
auto& generatedTypes = m_context.generatedFunctions.insert(std::make_pair(queueEntry.function, vector<Type>{})).first->second;
|
||||
if (!util::contains_if(generatedTypes, [&](auto const& _generatedType) { return m_context.env->typeEquals(_generatedType, queueEntry.type); }))
|
||||
{
|
||||
m_context.generatedFunctions[function].emplace_back(type);
|
||||
code << generate(*function, type);
|
||||
generatedTypes.emplace_back(queueEntry.type);
|
||||
code << generate(*queueEntry.function, queueEntry.type);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,7 +99,7 @@ private:
|
||||
solAssert(varDecl, "External reference in inline assembly to something that is not a variable declaration.");
|
||||
auto type = m_context.analysis.annotation<TypeInference>(*varDecl).type;
|
||||
solAssert(type);
|
||||
solAssert(m_context.env->typeEquals(*type, m_context.analysis.typeSystem().type(BuiltinType::Word, {})));
|
||||
solAssert(m_context.env->typeEquals(*type, m_context.analysis.typeSystem().type(PrimitiveType::Word, {})));
|
||||
string value = IRNames::localVariable(*varDecl);
|
||||
return yul::Identifier{_identifier.debugData, yul::YulString{value}};
|
||||
}
|
||||
@ -200,28 +200,25 @@ 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);
|
||||
auto const* typeClassDeclaration = _context.analysis.typeSystem().typeClassDeclaration(_class);
|
||||
if (typeClassDeclaration)
|
||||
return _context.analysis.annotation<TypeRegistration>(*typeClassDeclaration).instantiations;
|
||||
// TODO: better mechanism than fetching by name.
|
||||
auto& annotation = _context.analysis.annotation<TypeRegistration>();
|
||||
return annotation.builtinClassInstantiations.at(annotation.builtinClassesByName.at(_context.analysis.typeSystem().typeClassName(_class)));
|
||||
}
|
||||
}
|
||||
|
||||
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 = TypeEnvironmentHelpers{env}.typeVars(genericFunctionType);
|
||||
std::optional<Type> genericFunctionType = env.typeClassFunction(_class, _name);
|
||||
solAssert(genericFunctionType);
|
||||
auto typeVars = TypeEnvironmentHelpers{env}.typeVars(*genericFunctionType);
|
||||
solAssert(typeVars.size() == 1);
|
||||
solAssert(env.unify(genericFunctionType, _type).empty());
|
||||
solAssert(env.unify(*genericFunctionType, _type).empty());
|
||||
auto typeClassInstantiation = get<0>(helper.destTypeConstant(env.resolve(typeVars.front())));
|
||||
|
||||
auto const& instantiations = typeClassInstantiations(m_context, _class);
|
||||
@ -247,26 +244,26 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
||||
auto expressionType = type(_memberAccess.expression());
|
||||
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);
|
||||
auto const* declaration = m_context.analysis.typeSystem().constructorInfo(constructor).typeDeclaration;
|
||||
solAssert(declaration);
|
||||
if (auto const* typeClassDefinition = dynamic_cast<TypeClassDefinition const*>(declaration))
|
||||
{
|
||||
optional<TypeClass> typeClass = m_context.analysis.annotation<TypeInference>(*typeClassDefinition).typeClass;
|
||||
solAssert(typeClass);
|
||||
solAssert(m_expressionDeclaration.emplace(
|
||||
&_memberAccess,
|
||||
&resolveTypeClassFunction(*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);
|
||||
}
|
||||
|
||||
void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
|
Loading…
Reference in New Issue
Block a user