This commit is contained in:
Daniel Kirchner 2023-06-25 07:50:09 +02:00
parent 5bfe862bc4
commit fd1db21d64
11 changed files with 263 additions and 296 deletions

View File

@ -43,10 +43,14 @@ bool DebugWarner::visitNode(ASTNode const& _node)
if (typeInferenceAnnotation.type) if (typeInferenceAnnotation.type)
{ {
Type type = *typeInferenceAnnotation.type; 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}})
sortString = ":" + TypeSystemHelpers{m_analysis.typeSystem()}.sortToString(m_analysis.typeSystem().env().sort(type));
m_errorReporter.info( m_errorReporter.info(
0000_error, 0000_error,
_node.location(), _node.location(),
"Inferred type: " + m_analysis.typeSystem().env().typeToString(type) + ":" + TypeSystemHelpers{m_analysis.typeSystem()}.sortToString(m_analysis.typeSystem().env().sort(type)) "Inferred type: " + TypeEnvironmentHelpers{m_analysis.typeSystem().env()}.typeToString(type) + sortString
); );
} }
return true; return true;

View File

@ -90,7 +90,7 @@ bool TypeInference::visit(FunctionDefinition const& _functionDefinition)
functionAnnotation.type = functionType; functionAnnotation.type = functionType;
m_errorReporter.info(0000_error, _functionDefinition.location(), m_env->typeToString(*functionAnnotation.type)); m_errorReporter.info(0000_error, _functionDefinition.location(), TypeEnvironmentHelpers{*m_env}.typeToString(*functionAnnotation.type));
return false; return false;
} }
@ -162,7 +162,7 @@ bool TypeInference::visit(TypeClassDefinition const& _typeClassDefinition)
solAssert(functionDefinitionType); solAssert(functionDefinitionType);
auto functionType = m_env->fresh(*functionDefinitionType); auto functionType = m_env->fresh(*functionDefinitionType);
functionTypes[functionDefinition->name()] = functionType; functionTypes[functionDefinition->name()] = functionType;
auto typeVars = TypeSystemHelpers{m_typeSystem}.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); unify(typeVars.front(), typeVar);
@ -175,9 +175,7 @@ bool TypeInference::visit(TypeClassDefinition const& _typeClassDefinition)
m_errorReporter.fatalTypeError(0000_error, _typeClassDefinition.location(), *error); m_errorReporter.fatalTypeError(0000_error, _typeClassDefinition.location(), *error);
solAssert(typeVariableAnnotation.type); solAssert(typeVariableAnnotation.type);
TypeSystemHelpers helper{m_typeSystem}; unify(*typeVariableAnnotation.type, m_typeSystem.freshTypeVariable(Sort{{TypeClass{&_typeClassDefinition}}}), _typeClassDefinition.location());
unify(*typeVariableAnnotation.type, helper.kindType(m_typeSystem.freshTypeVariable(Sort{{TypeClass{&_typeClassDefinition}}})), _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)
// TODO: recursion-safety? // TODO: recursion-safety?
instantiation->accept(*this); instantiation->accept(*this);
@ -190,19 +188,30 @@ void TypeInference::unify(Type _a, Type _b, langutil::SourceLocation _location,
if (!_env) if (!_env)
_env = m_env; _env = m_env;
for (auto failure: _env->unify(_a, _b)) for (auto failure: _env->unify(_a, _b))
{
TypeEnvironmentHelpers helper{*_env};
std::visit(util::GenericVisitor{ std::visit(util::GenericVisitor{
[&](TypeEnvironment::TypeMismatch _typeMismatch) { [&](TypeEnvironment::TypeMismatch _typeMismatch) {
m_errorReporter.typeError(0000_error, _location, fmt::format("Cannot unify {} and {}.", _env->typeToString(_typeMismatch.a), _env->typeToString(_typeMismatch.b))); m_errorReporter.typeError(
0000_error,
_location,
fmt::format(
"Cannot unify {} and {}.",
helper.typeToString(_typeMismatch.a),
helper.typeToString(_typeMismatch.b))
);
}, },
[&](TypeEnvironment::SortMismatch _sortMismatch) { [&](TypeEnvironment::SortMismatch _sortMismatch) {
m_errorReporter.typeError(0000_error, _location, fmt::format( m_errorReporter.typeError(0000_error, _location, fmt::format(
"{} does not have sort {}", "{} does not have sort {}",
_env->typeToString(_sortMismatch.type), helper.typeToString(_sortMismatch.type),
TypeSystemHelpers{m_typeSystem}.sortToString(_sortMismatch.sort) TypeSystemHelpers{m_typeSystem}.sortToString(_sortMismatch.sort)
)); ));
} }
}, failure); }, failure);
}
} }
bool TypeInference::visit(InlineAssembly const& _inlineAssembly) bool TypeInference::visit(InlineAssembly const& _inlineAssembly)
{ {
@ -262,29 +271,29 @@ bool TypeInference::visit(ElementaryTypeNameExpression const& _expression)
switch(_expression.type().typeName().token()) switch(_expression.type().typeName().token())
{ {
case Token::Word: case Token::Word:
expressionAnnotation.type = helper.kindType(m_wordType); expressionAnnotation.type = m_wordType;
break; break;
case Token::Void: case Token::Void:
expressionAnnotation.type = helper.kindType(m_voidType); expressionAnnotation.type = m_voidType;
break; break;
case Token::Integer: case Token::Integer:
expressionAnnotation.type = helper.kindType(m_integerType); expressionAnnotation.type = m_integerType;
break; break;
case Token::Unit: case Token::Unit:
expressionAnnotation.type = helper.kindType(m_unitType); expressionAnnotation.type = m_unitType;
break; break;
case Token::Bool: case Token::Bool:
expressionAnnotation.type = helper.kindType(m_boolType); expressionAnnotation.type = m_boolType;
break; break;
case Token::Pair: case Token::Pair:
{ {
auto leftType = m_typeSystem.freshTypeVariable({}); auto leftType = m_typeSystem.freshTypeVariable({});
auto rightType = m_typeSystem.freshTypeVariable({}); auto rightType = m_typeSystem.freshTypeVariable({});
expressionAnnotation.type = expressionAnnotation.type =
helper.functionType( helper.typeFunctionType(
helper.kindType(helper.tupleType({leftType, rightType})), helper.tupleType({leftType, rightType}),
helper.kindType(m_typeSystem.type(BuiltinType::Pair, {leftType, rightType})) m_typeSystem.type(BuiltinType::Pair, {leftType, rightType})
); );
break; break;
} }
case Token::Fun: case Token::Fun:
@ -292,15 +301,15 @@ bool TypeInference::visit(ElementaryTypeNameExpression const& _expression)
auto argType = m_typeSystem.freshTypeVariable({}); auto argType = m_typeSystem.freshTypeVariable({});
auto resultType = m_typeSystem.freshTypeVariable({}); auto resultType = m_typeSystem.freshTypeVariable({});
expressionAnnotation.type = expressionAnnotation.type =
helper.functionType( helper.typeFunctionType(
helper.kindType(helper.tupleType({argType, resultType})), helper.tupleType({argType, resultType}),
helper.kindType(m_typeSystem.type(BuiltinType::Function, {argType, resultType})) m_typeSystem.type(BuiltinType::Function, {argType, resultType})
); );
break; break;
} }
default: default:
m_errorReporter.typeError(0000_error, _expression.location(), "Only elementary types are supported."); m_errorReporter.typeError(0000_error, _expression.location(), "Only elementary types are supported.");
expressionAnnotation.type = helper.kindType(m_typeSystem.freshTypeVariable({})); expressionAnnotation.type = m_typeSystem.freshTypeVariable({});
break; break;
} }
return false; return false;
@ -356,29 +365,21 @@ bool TypeInference::visit(BinaryOperation const& _binaryOperation)
{ {
_binaryOperation.leftExpression().accept(*this); _binaryOperation.leftExpression().accept(*this);
_binaryOperation.rightExpression().accept(*this); _binaryOperation.rightExpression().accept(*this);
auto getType = [&](std::optional<Type> _type) -> Type { solAssert(leftAnnotation.type);
solAssert(_type); solAssert(rightAnnotation.type);
if (helper.isKindType(*_type)) Type leftType = *leftAnnotation.type;
return helper.destKindType(*_type); Type rightType = *rightAnnotation.type;
else operationAnnotation.type = helper.functionType(leftType, rightType);
{
m_errorReporter.typeError(0000_error, _binaryOperation.leftExpression().location(), "Expected type but got " + m_env->typeToString(*leftAnnotation.type));
return m_typeSystem.freshTypeVariable({});
}
};
Type leftType = getType(leftAnnotation.type);
Type rightType = getType(rightAnnotation.type);
operationAnnotation.type = helper.kindType(helper.functionType(leftType, rightType));
} }
else else
{ {
m_errorReporter.typeError(0000_error, _binaryOperation.location(), "Invalid binary operations in type context."); m_errorReporter.typeError(0000_error, _binaryOperation.location(), "Invalid binary operations in type context.");
operationAnnotation.type = helper.kindType(m_typeSystem.freshTypeVariable({})); operationAnnotation.type = m_typeSystem.freshTypeVariable({});
} }
return false; return false;
case ExpressionContext::Sort: case ExpressionContext::Sort:
m_errorReporter.typeError(0000_error, _binaryOperation.location(), "Invalid binary operation in sort context."); m_errorReporter.typeError(0000_error, _binaryOperation.location(), "Invalid binary operation in sort context.");
operationAnnotation.type = helper.kindType(m_typeSystem.freshTypeVariable({})); operationAnnotation.type = m_typeSystem.freshTypeVariable({});
return false; return false;
} }
return false; return false;
@ -408,7 +409,6 @@ bool TypeInference::visit(VariableDeclaration const& _variableDeclaration)
auto& variableAnnotation = annotation(_variableDeclaration); auto& variableAnnotation = annotation(_variableDeclaration);
solAssert(!variableAnnotation.type); solAssert(!variableAnnotation.type);
TypeSystemHelpers helper{m_typeSystem};
switch (m_expressionContext) switch (m_expressionContext)
{ {
case ExpressionContext::Term: case ExpressionContext::Term:
@ -418,20 +418,14 @@ bool TypeInference::visit(VariableDeclaration const& _variableDeclaration)
_variableDeclaration.typeExpression()->accept(*this); _variableDeclaration.typeExpression()->accept(*this);
auto& typeExpressionAnnotation = annotation(*_variableDeclaration.typeExpression()); auto& typeExpressionAnnotation = annotation(*_variableDeclaration.typeExpression());
solAssert(typeExpressionAnnotation.type); solAssert(typeExpressionAnnotation.type);
if (helper.isKindType(*typeExpressionAnnotation.type)) variableAnnotation.type = *typeExpressionAnnotation.type;
variableAnnotation.type = helper.destKindType(*typeExpressionAnnotation.type);
else
{
m_errorReporter.typeError(0000_error, _variableDeclaration.typeExpression()->location(), "Expected type, but got " + m_env->typeToString(*typeExpressionAnnotation.type));
variableAnnotation.type = m_typeSystem.freshTypeVariable({});
}
return false; return false;
} }
variableAnnotation.type = m_typeSystem.freshTypeVariable({}); variableAnnotation.type = m_typeSystem.freshTypeVariable({});
return false; return false;
case ExpressionContext::Type: case ExpressionContext::Type:
variableAnnotation.type = helper.kindType(m_typeSystem.freshTypeVariable({})); variableAnnotation.type = m_typeSystem.freshTypeVariable({});
if (_variableDeclaration.typeExpression()) if (_variableDeclaration.typeExpression())
{ {
ScopedSaveAndRestore expressionContext{m_expressionContext, ExpressionContext::Sort}; ScopedSaveAndRestore expressionContext{m_expressionContext, ExpressionContext::Sort};
@ -487,7 +481,6 @@ TypeInference::GlobalAnnotation& TypeInference::annotation()
experimental::Type TypeInference::handleIdentifierByReferencedDeclaration(langutil::SourceLocation _location, Declaration const& _declaration) experimental::Type TypeInference::handleIdentifierByReferencedDeclaration(langutil::SourceLocation _location, Declaration const& _declaration)
{ {
TypeSystemHelpers helper{m_typeSystem};
switch(m_expressionContext) switch(m_expressionContext)
{ {
case ExpressionContext::Term: case ExpressionContext::Term:
@ -561,12 +554,12 @@ experimental::Type TypeInference::handleIdentifierByReferencedDeclaration(langut
{ {
ScopedSaveAndRestore expressionContext{m_expressionContext, ExpressionContext::Term}; ScopedSaveAndRestore expressionContext{m_expressionContext, ExpressionContext::Term};
typeClass->accept(*this); typeClass->accept(*this);
return helper.kindType(m_typeSystem.freshTypeVariable(Sort{{TypeClass{typeClass}}})); return m_typeSystem.freshTypeVariable(Sort{{TypeClass{typeClass}}});
} }
else else
{ {
m_errorReporter.typeError(0000_error, _location, "Expected type class."); m_errorReporter.typeError(0000_error, _location, "Expected type class.");
return helper.kindType(m_typeSystem.freshTypeVariable({})); return m_typeSystem.freshTypeVariable({});
} }
break; break;
} }
@ -585,7 +578,6 @@ bool TypeInference::visit(Identifier const& _identifier)
return false; return false;
} }
TypeSystemHelpers helper{m_typeSystem};
switch(m_expressionContext) switch(m_expressionContext)
{ {
case ExpressionContext::Term: case ExpressionContext::Term:
@ -595,7 +587,7 @@ bool TypeInference::visit(Identifier const& _identifier)
case ExpressionContext::Type: case ExpressionContext::Type:
{ {
// TODO: register free type variable name! // TODO: register free type variable name!
identifierAnnotation.type = helper.kindType(m_typeSystem.freshTypeVariable({})); identifierAnnotation.type = m_typeSystem.freshTypeVariable({});
return false; return false;
} }
case ExpressionContext::Sort: case ExpressionContext::Sort:
@ -616,34 +608,17 @@ void TypeInference::endVisit(TupleExpression const& _tupleExpression)
auto componentTypes = _tupleExpression.components() | ranges::views::transform([&](auto _expr) -> Type { auto componentTypes = _tupleExpression.components() | ranges::views::transform([&](auto _expr) -> Type {
auto& componentAnnotation = annotation(*_expr); auto& componentAnnotation = annotation(*_expr);
solAssert(componentAnnotation.type); solAssert(componentAnnotation.type);
switch(m_expressionContext) return *componentAnnotation.type;
{
case ExpressionContext::Term:
return *componentAnnotation.type;
case ExpressionContext::Type:
if (helper.isKindType(*componentAnnotation.type))
return helper.destKindType(*componentAnnotation.type);
else
{
m_errorReporter.typeError(0000_error, _expr->location(), "Expected type, but got " + m_env->typeToString(*componentAnnotation.type));
return m_typeSystem.freshTypeVariable({});
}
case ExpressionContext::Sort:
return *componentAnnotation.type;
}
solAssert(false);
}) | ranges::to<vector<Type>>; }) | ranges::to<vector<Type>>;
switch (m_expressionContext) switch (m_expressionContext)
{ {
case ExpressionContext::Term: case ExpressionContext::Term:
expressionAnnotation.type = helper.tupleType(componentTypes);
break;
case ExpressionContext::Type: case ExpressionContext::Type:
expressionAnnotation.type = helper.kindType(helper.tupleType(componentTypes)); expressionAnnotation.type = helper.tupleType(componentTypes);
break; break;
case ExpressionContext::Sort: case ExpressionContext::Sort:
{ {
Type type = helper.kindType(m_typeSystem.freshTypeVariable({})); Type type = m_typeSystem.freshTypeVariable({});
for (auto componentType: componentTypes) for (auto componentType: componentTypes)
unify(type, componentType, _tupleExpression.location()); unify(type, componentType, _tupleExpression.location());
expressionAnnotation.type = type; expressionAnnotation.type = type;
@ -725,8 +700,6 @@ bool TypeInference::visit(TypeClassInstantiation const& _typeClassInstantiation)
auto& argumentSortAnnotation = annotation(*_typeClassInstantiation.argumentSorts()); auto& argumentSortAnnotation = annotation(*_typeClassInstantiation.argumentSorts());
solAssert(argumentSortAnnotation.type); solAssert(argumentSortAnnotation.type);
arguments = TypeSystemHelpers{m_typeSystem}.destTupleType(*argumentSortAnnotation.type); arguments = TypeSystemHelpers{m_typeSystem}.destTupleType(*argumentSortAnnotation.type);
for (auto& argument: arguments)
argument = TypeSystemHelpers{m_typeSystem}.destKindType(argument);
arity.argumentSorts = arguments | ranges::views::transform([&](Type _type) { arity.argumentSorts = arguments | ranges::views::transform([&](Type _type) {
return m_env->sort(_type); return m_env->sort(_type);
}) | ranges::to<vector<Sort>>; }) | ranges::to<vector<Sort>>;
@ -743,7 +716,8 @@ bool TypeInference::visit(TypeClassInstantiation const& _typeClassInstantiation)
solAssert(functionDefinition); solAssert(functionDefinition);
subNode->accept(*this); subNode->accept(*this);
solAssert(annotation(*functionDefinition).type); solAssert(annotation(*functionDefinition).type);
functionTypes[functionDefinition->name()] = *annotation(*functionDefinition).type; if (!functionTypes.emplace(functionDefinition->name(), *annotation(*functionDefinition).type).second)
m_errorReporter.typeError(0000_error, subNode->location(), "Multiple definitions of function " + functionDefinition->name() + " during type class instantiation.");
} }
if (auto error = m_typeSystem.instantiateClass(type, arity, std::move(functionTypes))) if (auto error = m_typeSystem.instantiateClass(type, arity, std::move(functionTypes)))
@ -762,9 +736,6 @@ void TypeInference::endVisit(MemberAccess const& _memberAccess)
if (helper.isTypeConstant(*expressionAnnotation.type)) if (helper.isTypeConstant(*expressionAnnotation.type))
{ {
Type expressionType = *expressionAnnotation.type; Type expressionType = *expressionAnnotation.type;
// TODO: unify this, s.t. this is always or never a kind type.
if (helper.isKindType(expressionType))
expressionType = helper.destKindType(expressionType);
auto constructor = std::get<0>(helper.destTypeConstant(expressionType)); auto constructor = std::get<0>(helper.destTypeConstant(expressionType));
if (auto* typeMember = util::valueOrNullptr(annotation().members.at(constructor), _memberAccess.memberName())) if (auto* typeMember = util::valueOrNullptr(annotation().members.at(constructor), _memberAccess.memberName()))
{ {
@ -807,26 +778,19 @@ bool TypeInference::visit(TypeDefinition const& _typeDefinition)
ScopedSaveAndRestore expressionContext{m_expressionContext, ExpressionContext::Type}; ScopedSaveAndRestore expressionContext{m_expressionContext, ExpressionContext::Type};
_typeDefinition.typeExpression()->accept(*this); _typeDefinition.typeExpression()->accept(*this);
underlyingType = annotation(*_typeDefinition.typeExpression()).type; underlyingType = annotation(*_typeDefinition.typeExpression()).type;
// TODO: settle the kind type mess.
if (underlyingType && helper.isKindType(*underlyingType))
underlyingType = helper.destKindType(*underlyingType);
} }
vector<Type> arguments; vector<Type> arguments;
if (_typeDefinition.arguments()) if (_typeDefinition.arguments())
for (size_t i = 0; i < _typeDefinition.arguments()->parameters().size(); ++i) for (size_t i = 0; i < _typeDefinition.arguments()->parameters().size(); ++i)
// TODO: GENERALIZE // TODO: GENERALIZE?
arguments.emplace_back(m_typeSystem.freshTypeVariable({})); arguments.emplace_back(m_typeSystem.freshTypeVariable({}));
Type type = m_typeSystem.type(TypeConstructor{&_typeDefinition}, arguments); Type type = m_typeSystem.type(TypeConstructor{&_typeDefinition}, arguments);
if (arguments.empty()) if (arguments.empty())
typeDefinitionAnnotation.type = helper.kindType(m_typeSystem.type(TypeConstructor{&_typeDefinition}, arguments)); typeDefinitionAnnotation.type = m_typeSystem.type(TypeConstructor{&_typeDefinition}, arguments);
else else
typeDefinitionAnnotation.type = typeDefinitionAnnotation.type = helper.typeFunctionType(helper.tupleType(arguments), type);
helper.functionType(
helper.kindType(helper.tupleType(arguments)),
helper.kindType(type)
);
auto& typeMembers = annotation().members[&_typeDefinition]; auto& typeMembers = annotation().members[&_typeDefinition];
@ -859,16 +823,8 @@ void TypeInference::endVisit(FunctionCall const& _functionCall)
switch(m_expressionContext) switch(m_expressionContext)
{ {
case ExpressionContext::Term: case ExpressionContext::Term:
argTypes.emplace_back(*argAnnotation.type);
break;
case ExpressionContext::Type: case ExpressionContext::Type:
if (helper.isKindType(*argAnnotation.type)) argTypes.emplace_back(*argAnnotation.type);
argTypes.emplace_back(helper.destKindType(*argAnnotation.type));
else
{
m_errorReporter.typeError(0000_error, arg->location(), "Expected type, but got " + m_env->typeToString(*argAnnotation.type));
argTypes.emplace_back(m_typeSystem.freshTypeVariable({}));
}
break; break;
case ExpressionContext::Sort: case ExpressionContext::Sort:
m_errorReporter.typeError(0000_error, _functionCall.location(), "Function call in sort context."); m_errorReporter.typeError(0000_error, _functionCall.location(), "Function call in sort context.");
@ -890,11 +846,11 @@ void TypeInference::endVisit(FunctionCall const& _functionCall)
} }
case ExpressionContext::Type: case ExpressionContext::Type:
{ {
Type argTuple = helper.kindType(helper.tupleType(argTypes)); Type argTuple = helper.tupleType(argTypes);
Type genericFunctionType = helper.functionType(argTuple, m_typeSystem.freshKindVariable({})); Type genericFunctionType = helper.typeFunctionType(argTuple, m_typeSystem.freshKindVariable({}));
unify(functionType, genericFunctionType, _functionCall.location()); unify(functionType, genericFunctionType, _functionCall.location());
functionCallAnnotation.type = m_env->resolve(std::get<1>(helper.destFunctionType(m_env->resolve(genericFunctionType)))); functionCallAnnotation.type = m_env->resolve(std::get<1>(helper.destTypeFunctionType(m_env->resolve(genericFunctionType))));
break; break;
} }
case ExpressionContext::Sort: case ExpressionContext::Sort:

View File

@ -69,8 +69,6 @@ string TypeClass::toString() const
return "type"; return "type";
case BuiltinClass::Kind: case BuiltinClass::Kind:
return "kind"; return "kind";
case BuiltinClass::Constraint:
return "contraint";
case BuiltinClass::Integer: case BuiltinClass::Integer:
return "integer"; return "integer";
case BuiltinClass::Mul: case BuiltinClass::Mul:

View File

@ -44,6 +44,7 @@ enum class BuiltinType
Sort, Sort,
Void, Void,
Function, Function,
TypeFunction,
Unit, Unit,
Pair, Pair,
Word, Word,
@ -73,7 +74,6 @@ enum class BuiltinClass
{ {
Type, Type,
Kind, Kind,
Constraint,
Integer, Integer,
Mul, Mul,
Add, Add,

View File

@ -36,151 +36,6 @@ using namespace std;
using namespace solidity::frontend; using namespace solidity::frontend;
using namespace solidity::frontend::experimental; using namespace solidity::frontend::experimental;
std::string TypeEnvironment::canonicalTypeName(Type _type) const
{
return visit(util::GenericVisitor{
[&](TypeConstant const& _type) {
std::stringstream stream;
auto printTypeArguments = [&]() {
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) {
printTypeArguments();
if (auto const* typeDeclarationAnnotation = dynamic_cast<TypeDeclarationAnnotation const*>(&_declaration->annotation()))
stream << *typeDeclarationAnnotation->canonicalName;
else
// TODO: canonical name
stream << _declaration->name();
},
[&](BuiltinType _builtinType) {
printTypeArguments();
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::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;
}
}
}, _type.constructor);
return stream.str();
},
[](TypeVariable const&)-> string {
solAssert(false);
},
}, resolve(_type));
}
std::string TypeEnvironment::typeToString(Type const& _type) const
{
return std::visit(util::GenericVisitor{
[&](TypeConstant const& _type) {
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 << m_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{m_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 << m_typeSystem.typeName(_builtinType);
printTypeArguments();
break;
}
}
}, _type.constructor);
return stream.str();
},
[](TypeVariable const& _type) {
std::stringstream stream;
stream << "'var" << _type.index();
switch (_type.sort().classes.size())
{
case 0:
break;
case 1:
stream << ":" << _type.sort().classes.begin()->toString();
break;
default:
stream << ":(";
for (auto typeClass: _type.sort().classes | ranges::views::drop_last(1))
stream << typeClass.toString() << ", ";
stream << _type.sort().classes.rbegin()->toString();
stream << ")";
break;
}
return stream.str();
},
}, resolve(_type));
}
vector<TypeEnvironment::UnificationFailure> TypeEnvironment::unify(Type _a, Type _b) vector<TypeEnvironment::UnificationFailure> TypeEnvironment::unify(Type _a, Type _b)
{ {
vector<UnificationFailure> failures; vector<UnificationFailure> failures;
@ -267,15 +122,10 @@ TypeEnvironment TypeEnvironment::clone() const
TypeSystem::TypeSystem() TypeSystem::TypeSystem()
{ {
Sort kindSort{{TypeClass{BuiltinClass::Kind}}};
Sort typeSort{{TypeClass{BuiltinClass::Type}}}; Sort typeSort{{TypeClass{BuiltinClass::Type}}};
m_typeConstructors[BuiltinType::Type] = TypeConstructorInfo{ m_typeConstructors[BuiltinType::TypeFunction] = TypeConstructorInfo{
"type", "tfun",
{Arity{vector<Sort>{{typeSort}}, TypeClass{BuiltinClass::Kind}}} {Arity{vector<Sort>{{typeSort},{typeSort}}, TypeClass{BuiltinClass::Kind}}}
};
m_typeConstructors[BuiltinType::Sort] = TypeConstructorInfo{
"constraint",
{Arity{vector<Sort>{{kindSort}}, TypeClass{BuiltinClass::Constraint}}}
}; };
m_typeConstructors[BuiltinType::Function] = TypeConstructorInfo{ m_typeConstructors[BuiltinType::Function] = TypeConstructorInfo{
"fun", "fun",
@ -392,7 +242,7 @@ std::optional<std::string> TypeSystem::declareTypeClass(TypeClass _class, Type _
return "Invalid type variable."; return "Invalid type variable.";
for (auto [functionName, functionType]: _functions) for (auto [functionName, functionType]: _functions)
{ {
auto typeVars = TypeSystemHelpers{*this}.typeVars(functionType); auto typeVars = TypeEnvironmentHelpers{m_globalTypeEnvironment}.typeVars(functionType);
if (typeVars.empty()) if (typeVars.empty())
return "Function " + functionName + " does not depend on class variable."; return "Function " + functionName + " does not depend on class variable.";
if (typeVars.size() > 2) if (typeVars.size() > 2)
@ -479,7 +329,7 @@ std::optional<std::string> TypeSystem::instantiateClass(Type _instanceVariable,
_functionTypes.erase(name); _functionTypes.erase(name);
if (!newEnv.typeEquals(instanceFunctionType, classFunctionType)) if (!newEnv.typeEquals(instanceFunctionType, classFunctionType))
return "Type mismatch for function " + name + " " + newEnv.typeToString(instanceFunctionType) + " != " + newEnv.typeToString(classFunctionType); return "Type mismatch for function " + name + " " + TypeEnvironmentHelpers{newEnv}.typeToString(instanceFunctionType) + " != " + TypeEnvironmentHelpers{newEnv}.typeToString(classFunctionType);
} }
typeConstructorInfo.arities.emplace_back(_arity); typeConstructorInfo.arities.emplace_back(_arity);

View File

@ -42,10 +42,10 @@ public:
struct SortMismatch { Type type; Sort sort; }; struct SortMismatch { Type type; Sort sort; };
using UnificationFailure = std::variant<TypeMismatch, SortMismatch>; using UnificationFailure = std::variant<TypeMismatch, SortMismatch>;
[[nodiscard]] std::vector<UnificationFailure> unify(Type _a, Type _b); [[nodiscard]] std::vector<UnificationFailure> unify(Type _a, Type _b);
std::string canonicalTypeName(Type _type) const;
std::string typeToString(Type const& _type) const;
Sort sort(Type _type) const; Sort sort(Type _type) const;
bool typeEquals(Type _lhs, Type _rhs) const; bool typeEquals(Type _lhs, Type _rhs) const;
TypeSystem& typeSystem() { return m_typeSystem; }
TypeSystem const& typeSystem() const { return m_typeSystem; }
private: private:
TypeEnvironment(TypeEnvironment&& _env): m_typeSystem(_env.m_typeSystem), m_typeVariables(std::move(_env.m_typeVariables)) {} 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); [[nodiscard]] std::vector<TypeEnvironment::UnificationFailure> instantiate(TypeVariable _variable, Type _type);

View File

@ -26,6 +26,8 @@
#include <range/v3/view/drop_last.hpp> #include <range/v3/view/drop_last.hpp>
#include <range/v3/view/reverse.hpp> #include <range/v3/view/reverse.hpp>
#include <fmt/format.h>
using namespace std; using namespace std;
using namespace solidity::langutil; using namespace solidity::langutil;
using namespace solidity::frontend; using namespace solidity::frontend;
@ -156,11 +158,6 @@ vector<experimental::Type> TypeSystemHelpers::destTupleType(Type _tupleType) con
return result; return result;
} }
experimental::Type TypeSystemHelpers::functionType(experimental::Type _argType, experimental::Type _resultType) const
{
return typeSystem.type(BuiltinType::Function, {_argType, _resultType});
}
tuple<TypeConstructor, vector<experimental::Type>> TypeSystemHelpers::destTypeConstant(Type _type) const tuple<TypeConstructor, vector<experimental::Type>> TypeSystemHelpers::destTypeConstant(Type _type) const
{ {
using ResultType = tuple<TypeConstructor, vector<Type>>; using ResultType = tuple<TypeConstructor, vector<Type>>;
@ -186,6 +183,11 @@ bool TypeSystemHelpers::isTypeConstant(Type _type) const
}, _type); }, _type);
} }
experimental::Type TypeSystemHelpers::functionType(experimental::Type _argType, experimental::Type _resultType) const
{
return typeSystem.type(BuiltinType::Function, {_argType, _resultType});
}
tuple<experimental::Type, experimental::Type> TypeSystemHelpers::destFunctionType(Type _functionType) const tuple<experimental::Type, experimental::Type> TypeSystemHelpers::destFunctionType(Type _functionType) const
{ {
auto [constructor, arguments] = destTypeConstant(_functionType); auto [constructor, arguments] = destTypeConstant(_functionType);
@ -204,7 +206,30 @@ bool TypeSystemHelpers::isFunctionType(Type _type) const
return builtinType && *builtinType == BuiltinType::Function; return builtinType && *builtinType == BuiltinType::Function;
} }
vector<experimental::Type> TypeSystemHelpers::typeVars(Type _type) const experimental::Type TypeSystemHelpers::typeFunctionType(experimental::Type _argType, experimental::Type _resultType) const
{
return typeSystem.type(BuiltinType::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(arguments.size() == 2);
return make_tuple(arguments.front(), arguments.back());
}
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;
}
vector<experimental::Type> TypeEnvironmentHelpers::typeVars(Type _type) const
{ {
set<size_t> indices; set<size_t> indices;
vector<Type> typeVars; vector<Type> typeVars;
@ -219,33 +244,13 @@ vector<experimental::Type> TypeSystemHelpers::typeVars(Type _type) const
typeVars.emplace_back(_var); typeVars.emplace_back(_var);
}, },
// TODO: move to env helpers? // TODO: move to env helpers?
}, typeSystem.env().resolve(_type)); }, env.resolve(_type));
}; };
typeVarsImpl(_type, typeVarsImpl); typeVarsImpl(_type, typeVarsImpl);
return typeVars; return typeVars;
} }
experimental::Type TypeSystemHelpers::kindType(Type _type) const
{
return typeSystem.type(BuiltinType::Type, {_type});
}
experimental::Type TypeSystemHelpers::destKindType(Type _type) const
{
auto [constructor, arguments] = destTypeConstant(_type);
solAssert(constructor == TypeConstructor{BuiltinType::Type});
solAssert(arguments.size() == 1);
return arguments.front();
}
bool TypeSystemHelpers::isKindType(Type _type) const
{
if (!isTypeConstant(_type))
return false;
auto constructor = get<0>(destTypeConstant(_type));
return constructor == TypeConstructor{BuiltinType::Type};
}
std::string TypeSystemHelpers::sortToString(Sort _sort) const std::string TypeSystemHelpers::sortToString(Sort _sort) const
{ {
@ -265,4 +270,151 @@ std::string TypeSystemHelpers::sortToString(Sort _sort) const
return stream.str(); return stream.str();
} }
} }
} }
std::string TypeEnvironmentHelpers::canonicalTypeName(Type _type) const
{
return visit(util::GenericVisitor{
[&](TypeConstant const& _type) {
std::stringstream stream;
auto printTypeArguments = [&]() {
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) {
printTypeArguments();
if (auto const* typeDeclarationAnnotation = dynamic_cast<TypeDeclarationAnnotation const*>(&_declaration->annotation()))
stream << *typeDeclarationAnnotation->canonicalName;
else
// TODO: canonical name
stream << _declaration->name();
},
[&](BuiltinType _builtinType) {
printTypeArguments();
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;
}
}
}, _type.constructor);
return stream.str();
},
[](TypeVariable const&)-> string {
solAssert(false);
},
}, env.resolve(_type));
}
std::string TypeEnvironmentHelpers::typeToString(Type const& _type) const
{
return std::visit(util::GenericVisitor{
[&](TypeConstant const& _type) {
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);
return stream.str();
},
[](TypeVariable const& _type) {
std::stringstream stream;
stream << "'var" << _type.index();
switch (_type.sort().classes.size())
{
case 0:
break;
case 1:
stream << ":" << _type.sort().classes.begin()->toString();
break;
default:
stream << ":(";
for (auto typeClass: _type.sort().classes | ranges::views::drop_last(1))
stream << typeClass.toString() << ", ";
stream << _type.sort().classes.rbegin()->toString();
stream << ")";
break;
}
return stream.str();
},
}, env.resolve(_type));
}

View File

@ -39,11 +39,18 @@ struct TypeSystemHelpers
Type functionType(Type _argType, Type _resultType) const; Type functionType(Type _argType, Type _resultType) const;
std::tuple<Type, Type> destFunctionType(Type _functionType) const; std::tuple<Type, Type> destFunctionType(Type _functionType) const;
bool isFunctionType(Type _type) const; bool isFunctionType(Type _type) const;
std::vector<Type> typeVars(Type _type) const; Type typeFunctionType(Type _argType, Type _resultType) const;
std::tuple<Type, Type> destTypeFunctionType(Type _functionType) const;
bool isTypeFunctionType(Type _type) const;
std::string sortToString(Sort _sort) const; std::string sortToString(Sort _sort) const;
Type kindType(Type _type) const; };
bool isKindType(Type _type) const;
Type destKindType(Type _type) const; struct TypeEnvironmentHelpers
{
TypeEnvironment const& env;
std::string typeToString(Type const& _type) const;
std::string canonicalTypeName(Type _type) const;
std::vector<Type> typeVars(Type _type) const;
}; };
} }

View File

@ -18,6 +18,7 @@
#include <libsolidity/codegen/experimental/Common.h> #include <libsolidity/codegen/experimental/Common.h>
#include <libsolidity/ast/experimental/TypeSystem.h> #include <libsolidity/ast/experimental/TypeSystem.h>
#include <libsolidity/ast/experimental/TypeSystemHelper.h>
#include <libsolutil/CommonIO.h> #include <libsolutil/CommonIO.h>
@ -37,7 +38,7 @@ string IRNames::function(TypeEnvironment const& _env, FunctionDefinition const&
if (_function.isConstructor()) if (_function.isConstructor())
return constructor(*_function.annotation().contract); return constructor(*_function.annotation().contract);
return "fun_" + _function.name() + "_" + to_string(_function.id()) + "$" + _env.canonicalTypeName(_type) + "$"; return "fun_" + _function.name() + "_" + to_string(_function.id()) + "$" + TypeEnvironmentHelpers{_env}.canonicalTypeName(_type) + "$";
} }
string IRNames::function(VariableDeclaration const& _varDecl) string IRNames::function(VariableDeclaration const& _varDecl)

View File

@ -25,6 +25,7 @@
#include <libsolidity/analysis/experimental/Analysis.h> #include <libsolidity/analysis/experimental/Analysis.h>
#include <libsolidity/analysis/experimental/TypeInference.h> #include <libsolidity/analysis/experimental/TypeInference.h>
#include <libsolidity/ast/experimental/TypeSystemHelper.h>
#include <libyul/YulStack.h> #include <libyul/YulStack.h>
#include <libyul/AsmPrinter.h> #include <libyul/AsmPrinter.h>
@ -128,7 +129,8 @@ string IRGenerator::generate(FunctionDefinition const& _function, Type _type)
solAssert(type); solAssert(type);
for (auto err: newEnv.unify(*type, _type)) for (auto err: newEnv.unify(*type, _type))
{ {
solAssert(false, newEnv.typeToString(*type) + " <-> " + newEnv.typeToString(_type)); TypeEnvironmentHelpers helper{newEnv};
solAssert(false, helper.typeToString(*type) + " <-> " + helper.typeToString(_type));
} }
std::stringstream code; std::stringstream code;
code << "function " << IRNames::function(newEnv, _function, _type) << "("; code << "function " << IRNames::function(newEnv, _function, _type) << "(";

View File

@ -219,7 +219,7 @@ FunctionDefinition const& IRGeneratorForStatements::resolveTypeClassFunction(Typ
Type genericFunctionType = typeClassInfo->functions.at(_name); Type genericFunctionType = typeClassInfo->functions.at(_name);
TypeEnvironment env = m_context.env->clone(); TypeEnvironment env = m_context.env->clone();
auto typeVars = helper.typeVars(genericFunctionType); auto typeVars = TypeEnvironmentHelpers{env}.typeVars(genericFunctionType);
solAssert(typeVars.size() == 1); 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 typeClassInstantiation = get<0>(helper.destTypeConstant(env.resolve(typeVars.front())));
@ -245,9 +245,6 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
{ {
TypeSystemHelpers helper{m_context.analysis.typeSystem()}; TypeSystemHelpers helper{m_context.analysis.typeSystem()};
auto expressionType = type(_memberAccess.expression()); auto expressionType = type(_memberAccess.expression());
// TODO: avoid kind destruction
if (helper.isKindType(expressionType))
expressionType = helper.destKindType(expressionType);
auto constructor = std::get<0>(helper.destTypeConstant(expressionType)); auto constructor = std::get<0>(helper.destTypeConstant(expressionType));
auto memberAccessType = type(_memberAccess); auto memberAccessType = type(_memberAccess);
std::visit(util::GenericVisitor{ std::visit(util::GenericVisitor{