This commit is contained in:
Daniel Kirchner 2023-06-27 00:16:28 +02:00
parent 48b35bd921
commit 8135e28821
14 changed files with 655 additions and 511 deletions

View File

@ -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,

View File

@ -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)
{

View File

@ -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;
};
}

View File

@ -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>();

View File

@ -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();

View File

@ -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())

View File

@ -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

View File

@ -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;

View File

@ -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};
};

View File

@ -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));
}

View File

@ -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
{

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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)