This commit is contained in:
Daniel Kirchner 2023-06-27 01:39:18 +02:00
parent 156d5c7cb7
commit ea9dfca1ae
3 changed files with 44 additions and 19 deletions

View File

@ -121,22 +121,18 @@ bool TypeInference::visit(TypeClassDefinition const& _typeClassDefinition)
Type typeVar = m_typeSystem.freshTypeVariable({}); Type typeVar = m_typeSystem.freshTypeVariable({});
auto& typeMembers = annotation().members[typeConstructor(&_typeClassDefinition)];
for (auto subNode: _typeClassDefinition.subNodes()) for (auto subNode: _typeClassDefinition.subNodes())
{ {
subNode->accept(*this); subNode->accept(*this);
auto const* functionDefinition = dynamic_cast<FunctionDefinition const*>(subNode.get()); auto const* functionDefinition = dynamic_cast<FunctionDefinition const*>(subNode.get());
solAssert(functionDefinition); solAssert(functionDefinition);
auto functionType = m_env->fresh(getType(*functionDefinition)); auto functionType = m_env->fresh(getType(*functionDefinition));
functionTypes[functionDefinition->name()] = functionType; if (!functionTypes.emplace(functionDefinition->name(), functionType).second)
m_errorReporter.fatalTypeError(0000_error, functionDefinition->location(), "Function in type class declared multiple times.");
auto typeVars = TypeEnvironmentHelpers{*m_env}.typeVars(functionType); auto typeVars = TypeEnvironmentHelpers{*m_env}.typeVars(functionType);
if(typeVars.size() != 1) if(typeVars.size() != 1)
m_errorReporter.fatalTypeError(0000_error, functionDefinition->location(), "Function in type class may only depend on the type class variable."); m_errorReporter.fatalTypeError(0000_error, functionDefinition->location(), "Function in type class may only depend on the type class variable.");
unify(typeVars.front(), typeVar, functionDefinition->location()); 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.");
} }
TypeClass typeClass = std::visit(util::GenericVisitor{ TypeClass typeClass = std::visit(util::GenericVisitor{
@ -146,7 +142,18 @@ bool TypeInference::visit(TypeClassDefinition const& _typeClassDefinition)
util::unreachable(); util::unreachable();
} }
}, m_typeSystem.declareTypeClass(typeVar, std::move(functionTypes), _typeClassDefinition.name(), &_typeClassDefinition)); }, m_typeSystem.declareTypeClass(typeVar, std::move(functionTypes), _typeClassDefinition.name(), &_typeClassDefinition));
annotation(_typeClassDefinition).typeClass = typeClass;
auto& typeMembers = annotation().members[typeConstructor(&_typeClassDefinition)];
for (auto subNode: _typeClassDefinition.subNodes())
{
auto const* functionDefinition = dynamic_cast<FunctionDefinition const*>(subNode.get());
solAssert(functionDefinition);
auto functionType = m_env->typeClassFunction(typeClass, functionDefinition->name());
solAssert(functionType);
typeMembers[functionDefinition->name()] = TypeMember{*functionType};
}
unify(getType(_typeClassDefinition.typeVariable()), m_typeSystem.freshTypeVariable({{typeClass}}), _typeClassDefinition.location()); unify(getType(_typeClassDefinition.typeVariable()), m_typeSystem.freshTypeVariable({{typeClass}}), _typeClassDefinition.location());
for (auto instantiation: m_analysis.annotation<TypeRegistration>(_typeClassDefinition).instantiations | ranges::views::values) for (auto instantiation: m_analysis.annotation<TypeRegistration>(_typeClassDefinition).instantiations | ranges::views::values)
@ -258,15 +265,24 @@ bool TypeInference::visit(BinaryOperation const& _binaryOperation)
unify(*functionType, genericFunctionType, _binaryOperation.location()); unify(*functionType, genericFunctionType, _binaryOperation.location());
operationAnnotation.type = m_env->resolve(std::get<1>(helper.destFunctionType(m_env->resolve(genericFunctionType)))); operationAnnotation.type = m_env->resolve(std::get<1>(helper.destFunctionType(m_env->resolve(genericFunctionType))));
}
return false; else if (_binaryOperation.getOperator() == Token::Colon)
{
_binaryOperation.leftExpression().accept(*this);
{
ScopedSaveAndRestore expressionContext{m_expressionContext, ExpressionContext::Type};
_binaryOperation.rightExpression().accept(*this);
}
Type leftType = getType(_binaryOperation.leftExpression());
unify(leftType, getType(_binaryOperation.rightExpression()), _binaryOperation.location());
operationAnnotation.type = leftType;
} }
else else
{ {
m_errorReporter.typeError(0000_error, _binaryOperation.location(), "Binary operation 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({}); operationAnnotation.type = m_typeSystem.freshTypeVariable({});
return false;
} }
return false;
case ExpressionContext::Type: case ExpressionContext::Type:
if (_binaryOperation.getOperator() == Token::Colon) if (_binaryOperation.getOperator() == Token::Colon)
{ {
@ -395,7 +411,13 @@ experimental::Type TypeInference::handleIdentifierByReferencedDeclaration(langut
else if (dynamic_cast<TypeClassDefinition const*>(&_declaration)) else if (dynamic_cast<TypeClassDefinition const*>(&_declaration))
return m_env->fresh(*declarationAnnotation.type); return m_env->fresh(*declarationAnnotation.type);
else if (dynamic_cast<TypeDefinition const*>(&_declaration)) else if (dynamic_cast<TypeDefinition const*>(&_declaration))
return m_env->fresh(*declarationAnnotation.type); {
// TODO: can we avoid this?
Type type = *declarationAnnotation.type;
if (TypeSystemHelpers{m_typeSystem}.isTypeFunctionType(type))
type = std::get<1>(TypeSystemHelpers{m_typeSystem}.destTypeFunctionType(type));
return m_env->fresh(type);
}
else else
solAssert(false); solAssert(false);
break; break;
@ -539,6 +561,8 @@ bool TypeInference::visit(TypeClassInstantiation const& _typeClassInstantiation)
// visiting the type class will re-visit this instantiation // visiting the type class will re-visit this instantiation
typeClass->accept(*this); typeClass->accept(*this);
// TODO: more error handling? Should be covered by the visit above. // TODO: more error handling? Should be covered by the visit above.
if (!annotation(*typeClass).typeClass)
m_errorReporter.typeError(0000_error, _typeClassInstantiation.typeClass().location(), "Expected type class.");
return annotation(*typeClass).typeClass; return annotation(*typeClass).typeClass;
} }
else else
@ -719,7 +743,7 @@ void TypeInference::endVisit(FunctionCall const& _functionCall)
case ExpressionContext::Type: case ExpressionContext::Type:
{ {
Type argTuple = helper.tupleType(argTypes); Type argTuple = helper.tupleType(argTypes);
Type genericFunctionType = helper.typeFunctionType(argTuple, m_typeSystem.freshKindVariable({})); Type genericFunctionType = helper.typeFunctionType(argTuple, m_typeSystem.freshTypeVariable({}));
unify(functionType, genericFunctionType, _functionCall.location()); unify(functionType, genericFunctionType, _functionCall.location());
functionCallAnnotation.type = m_env->resolve(std::get<1>(helper.destTypeFunctionType(m_env->resolve(genericFunctionType)))); functionCallAnnotation.type = m_env->resolve(std::get<1>(helper.destTypeFunctionType(m_env->resolve(genericFunctionType))));
break; break;

View File

@ -148,9 +148,9 @@ TypeSystem::TypeSystem()
m_primitiveTypeConstructors.emplace(type, declareTypeConstructor(name, name, arity, nullptr)); m_primitiveTypeConstructors.emplace(type, declareTypeConstructor(name, name, arity, nullptr));
TypeClass classType = primitiveClass(PrimitiveClass::Type); TypeClass classType = primitiveClass(PrimitiveClass::Type);
TypeClass classKind = primitiveClass(PrimitiveClass::Kind); //TypeClass classKind = primitiveClass(PrimitiveClass::Kind);
Sort typeSort{{classType}}; 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::TypeFunction).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}}; 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}}; m_typeConstructors.at(m_primitiveTypeConstructors.at(PrimitiveType::Function).m_index).arities = {Arity{vector<Sort>{{typeSort, typeSort}}, classType}};
} }
@ -269,7 +269,7 @@ TypeConstructor TypeSystem::declareTypeConstructor(string _name, string _canonic
std::generate_n(std::back_inserter(argumentSorts), _arguments, [&](){ return Sort{{primitiveClass(PrimitiveClass::Type)}}; }); std::generate_n(std::back_inserter(argumentSorts), _arguments, [&](){ return Sort{{primitiveClass(PrimitiveClass::Type)}}; });
std::vector<Type> argumentTypes; std::vector<Type> argumentTypes;
std::generate_n(std::back_inserter(argumentTypes), _arguments, [&](){ return freshVariable({}); }); std::generate_n(std::back_inserter(argumentTypes), _arguments, [&](){ return freshVariable({}); });
auto error = instantiateClass(type(constructor, argumentTypes), Arity{argumentSorts, primitiveClass(PrimitiveClass::Kind)}, {}); auto error = instantiateClass(type(constructor, argumentTypes), Arity{argumentSorts, primitiveClass(PrimitiveClass::Type)}, {});
solAssert(!error, *error); solAssert(!error, *error);
} }
else else

View File

@ -304,12 +304,13 @@ std::string TypeEnvironmentHelpers::typeToString(Type const& _type) const
solAssert(_args.size() == 0); solAssert(_args.size() == 0);
return "()"; return "()";
}}, }},
{env.typeSystem().constructor(PrimitiveType::Pair), [&](auto const&) { {env.typeSystem().constructor(PrimitiveType::Pair), [&](auto const& _arguments) {
auto tupleTypes = TypeSystemHelpers{env.typeSystem()}.destTupleType(_type); auto tupleTypes = TypeSystemHelpers{env.typeSystem()}.destTupleType(_arguments.back());
string result = "("; string result = "(";
for (auto type: tupleTypes | ranges::views::drop_last(1)) result += typeToString(_arguments.front());
result += typeToString(type) + ", "; for (auto type: tupleTypes)
result += typeToString(tupleTypes.back()) + ")"; result += ", " + typeToString(type);
result += ")";
return result; return result;
}}, }},
}; };