diff --git a/libsolidity/analysis/experimental/TypeInference.cpp b/libsolidity/analysis/experimental/TypeInference.cpp index 8b4291522..2fc250d2e 100644 --- a/libsolidity/analysis/experimental/TypeInference.cpp +++ b/libsolidity/analysis/experimental/TypeInference.cpp @@ -121,22 +121,18 @@ bool TypeInference::visit(TypeClassDefinition const& _typeClassDefinition) Type typeVar = m_typeSystem.freshTypeVariable({}); - auto& typeMembers = annotation().members[typeConstructor(&_typeClassDefinition)]; - for (auto subNode: _typeClassDefinition.subNodes()) { subNode->accept(*this); auto const* functionDefinition = dynamic_cast(subNode.get()); solAssert(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); 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, 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{ @@ -146,7 +142,18 @@ bool TypeInference::visit(TypeClassDefinition const& _typeClassDefinition) util::unreachable(); } }, 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(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()); for (auto instantiation: m_analysis.annotation(_typeClassDefinition).instantiations | ranges::views::values) @@ -258,15 +265,24 @@ bool TypeInference::visit(BinaryOperation const& _binaryOperation) unify(*functionType, genericFunctionType, _binaryOperation.location()); 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 { m_errorReporter.typeError(0000_error, _binaryOperation.location(), "Binary operation in term context not yet supported."); operationAnnotation.type = m_typeSystem.freshTypeVariable({}); - return false; } + return false; case ExpressionContext::Type: if (_binaryOperation.getOperator() == Token::Colon) { @@ -395,7 +411,13 @@ experimental::Type TypeInference::handleIdentifierByReferencedDeclaration(langut else if (dynamic_cast(&_declaration)) return m_env->fresh(*declarationAnnotation.type); else if (dynamic_cast(&_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 solAssert(false); break; @@ -539,6 +561,8 @@ bool TypeInference::visit(TypeClassInstantiation const& _typeClassInstantiation) // visiting the type class will re-visit this instantiation typeClass->accept(*this); // 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; } else @@ -719,7 +743,7 @@ void TypeInference::endVisit(FunctionCall const& _functionCall) case ExpressionContext::Type: { 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()); functionCallAnnotation.type = m_env->resolve(std::get<1>(helper.destTypeFunctionType(m_env->resolve(genericFunctionType)))); break; diff --git a/libsolidity/ast/experimental/TypeSystem.cpp b/libsolidity/ast/experimental/TypeSystem.cpp index 91bbcb5d9..ddcc7337b 100644 --- a/libsolidity/ast/experimental/TypeSystem.cpp +++ b/libsolidity/ast/experimental/TypeSystem.cpp @@ -148,9 +148,9 @@ TypeSystem::TypeSystem() m_primitiveTypeConstructors.emplace(type, declareTypeConstructor(name, name, arity, nullptr)); TypeClass classType = primitiveClass(PrimitiveClass::Type); - TypeClass classKind = primitiveClass(PrimitiveClass::Kind); + //TypeClass classKind = primitiveClass(PrimitiveClass::Kind); Sort typeSort{{classType}}; - m_typeConstructors.at(m_primitiveTypeConstructors.at(PrimitiveType::TypeFunction).m_index).arities = {Arity{vector{{typeSort},{typeSort}}, classKind}}; + m_typeConstructors.at(m_primitiveTypeConstructors.at(PrimitiveType::TypeFunction).m_index).arities = {Arity{vector{{typeSort},{typeSort}}, classType}}; m_typeConstructors.at(m_primitiveTypeConstructors.at(PrimitiveType::Function).m_index).arities = {Arity{vector{{typeSort, typeSort}}, classType}}; m_typeConstructors.at(m_primitiveTypeConstructors.at(PrimitiveType::Function).m_index).arities = {Arity{vector{{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::vector argumentTypes; 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); } else diff --git a/libsolidity/ast/experimental/TypeSystemHelper.cpp b/libsolidity/ast/experimental/TypeSystemHelper.cpp index 3f4a3dd25..75095a709 100644 --- a/libsolidity/ast/experimental/TypeSystemHelper.cpp +++ b/libsolidity/ast/experimental/TypeSystemHelper.cpp @@ -304,12 +304,13 @@ std::string TypeEnvironmentHelpers::typeToString(Type const& _type) const solAssert(_args.size() == 0); return "()"; }}, - {env.typeSystem().constructor(PrimitiveType::Pair), [&](auto const&) { - auto tupleTypes = TypeSystemHelpers{env.typeSystem()}.destTupleType(_type); + {env.typeSystem().constructor(PrimitiveType::Pair), [&](auto const& _arguments) { + auto tupleTypes = TypeSystemHelpers{env.typeSystem()}.destTupleType(_arguments.back()); string result = "("; - for (auto type: tupleTypes | ranges::views::drop_last(1)) - result += typeToString(type) + ", "; - result += typeToString(tupleTypes.back()) + ")"; + result += typeToString(_arguments.front()); + for (auto type: tupleTypes) + result += ", " + typeToString(type); + result += ")"; return result; }}, };