From d655302465457c5d3285ae5339201a0769cc38dc Mon Sep 17 00:00:00 2001 From: Yong He Date: Thu, 5 Sep 2024 11:24:19 -0700 Subject: Support `where` clause and type equality constraint. (#4986) * Support `where` clause. * Fix. * Fix parser. * Enhance test to cover traditional __generic syntax. * Update user-guide. * Support `where` clause on associatedtype. * Fix. * Put in more comments. --- source/slang/slang-check-inheritance.cpp | 157 +++++++++++++++++++++++-------- 1 file changed, 120 insertions(+), 37 deletions(-) (limited to 'source/slang/slang-check-inheritance.cpp') diff --git a/source/slang/slang-check-inheritance.cpp b/source/slang/slang-check-inheritance.cpp index 20f41c1bb..0d3929901 100644 --- a/source/slang/slang-check-inheritance.cpp +++ b/source/slang/slang-check-inheritance.cpp @@ -97,6 +97,51 @@ namespace Slang return info; } + void SharedSemanticsContext::getDependentGenericParentImpl(DeclRef& genericParent, DeclRef declRef) + { + auto mergeParent = [](DeclRef& currentParent, DeclRef newParent) + { + if (!currentParent) + { + currentParent = newParent; + return; + } + if (currentParent == newParent) + return; + if (newParent.getDecl()->isChildOf(currentParent.getDecl())) + currentParent = newParent; + }; + + if (declRef.as()) + { + if (!genericParent) + mergeParent(genericParent, declRef.getParent().as()); + return; + } + else if (auto lookupDeclRef = as(declRef.declRefBase)) + { + if (auto lookupSourceDeclRef = isDeclRefTypeOf(lookupDeclRef->getLookupSource())) + getDependentGenericParentImpl(genericParent, lookupSourceDeclRef); + } + else if (auto genericAppDeclRef = as(declRef.declRefBase)) + { + for (Index i = 0; i < genericAppDeclRef->getArgCount(); i++) + { + if (auto argDeclRef = isDeclRefTypeOf(genericAppDeclRef->getArg(i))) + { + getDependentGenericParentImpl(genericParent, argDeclRef); + } + } + } + } + + DeclRef SharedSemanticsContext::getDependentGenericParent(DeclRef declRef) + { + DeclRef genericParent; + getDependentGenericParentImpl(genericParent, declRef); + return genericParent; + } + InheritanceInfo SharedSemanticsContext::_calcInheritanceInfo(DeclRef declRef, DeclRefType* declRefType, InheritanceCircularityInfo* circularityInfo) { // This method is the main engine for computing linearized inheritance @@ -305,39 +350,82 @@ namespace Slang // We now look at the structure of the declaration itself // to help us enumerate the direct bases. // - if (auto aggTypeDeclBaseRef = declRef.as()) + auto currentDeclRef = declRef; + for (; currentDeclRef;) { - // In the case where we have an aggregate type or `extension` - // declaration, we can use the explicit list of direct bases. - // - for (auto typeConstraintDeclRef : getMembersOfType(_getASTBuilder(), aggTypeDeclBaseRef)) + if (auto aggTypeDeclBaseRef = currentDeclRef.as()) { - visitor.ensureDecl(typeConstraintDeclRef, DeclCheckState::CanUseBaseOfInheritanceDecl); - - // Note: In certain cases something takes the *syntactic* form of an inheritance - // clause, but it is not actually something that should be treated as implying - // a subtype relationship. For example, an `enum` declaration can use what looks - // like an inheritance clause to indicate its underlying "tag type." - // - // We skip such pseudo-inheritance relationships for the purposes of determining - // the linearized list of bases. + // In the case where we have an aggregate type or `extension` + // declaration, we can use the explicit list of direct bases. // - if (typeConstraintDeclRef.getDecl()->hasModifier()) - continue; + for (auto typeConstraintDeclRef : getMembersOfType(_getASTBuilder(), aggTypeDeclBaseRef)) + { + // Note: In certain cases something takes the *syntactic* form of an inheritance + // clause, but it is not actually something that should be treated as implying + // a subtype relationship. For example, an `enum` declaration can use what looks + // like an inheritance clause to indicate its underlying "tag type." + // + // We skip such pseudo-inheritance relationships for the purposes of determining + // the linearized list of bases. + // + if (typeConstraintDeclRef.getDecl()->hasModifier()) + continue; - // The base type and subtype witness can easily be determined - // using the `InheritanceDecl`. - // - auto baseType = getSup(astBuilder, typeConstraintDeclRef); - auto satisfyingWitness = astBuilder->getDeclaredSubtypeWitness( - selfType, - baseType, - typeConstraintDeclRef); + // The only case we will ever see a GenericTypeConstraintDecl inside a AggTypeDecl is when + // AggTypeDecl is a associatedtype decl. In this case, we will only lookup the type constraint + // if the constraint is on the associated type itself. + // + auto genericTypeConstraintDeclRef = typeConstraintDeclRef.as(); + if (genericTypeConstraintDeclRef) + { + // If the base expr on the constraint isn't even a `VarExpr`, then it can't be referencing + // the associated type itself and we can skip this constraint. + if (!genericTypeConstraintDeclRef.getDecl()->sub.type + && !as(genericTypeConstraintDeclRef.getDecl()->sub.exp)) + continue; + } + + visitor.ensureDecl(typeConstraintDeclRef, DeclCheckState::CanUseBaseOfInheritanceDecl); - addDirectBaseType(baseType, satisfyingWitness); + // For generic type constraint decls, always make sure it is about the type being checked. + // + if (genericTypeConstraintDeclRef) + { + auto subType = getSub(astBuilder, genericTypeConstraintDeclRef); + if (subType != selfType) + continue; + } + else if (currentDeclRef != declRef) + { + continue; + } + // The base type and subtype witness can easily be determined + // using the `InheritanceDecl`. + // + auto baseType = getSup(astBuilder, typeConstraintDeclRef); + auto satisfyingWitness = astBuilder->getDeclaredSubtypeWitness( + selfType, + baseType, + typeConstraintDeclRef); + + addDirectBaseType(baseType, satisfyingWitness); + } } + if (currentDeclRef.as()) + { + // If the current type is an associated type, continue inspecting the base/parent of the + // associatedtype to discover additional constraints defined on the parent associatedtype decls. + // + if (auto lookupDeclRef = as(currentDeclRef.declRefBase)) + { + currentDeclRef = isDeclRefTypeOf(lookupDeclRef->getLookupSource()).as(); + continue; + } + } + break; } - else if (auto genericTypeParamDeclRef = declRef.as()) + + if (auto genericDeclRef = getDependentGenericParent(declRef)) { // The constraints placed on a generic type parameter are siblings of that // parameter in its parent `GenericDecl`, so we need to enumerate all of @@ -349,13 +437,11 @@ namespace Slang // representation would need to take into account canonicalization of // constraints. - auto genericDeclRef = genericTypeParamDeclRef.getParent().as(); - SLANG_ASSERT(genericDeclRef); ensureDecl(&visitor, genericDeclRef.getDecl(), DeclCheckState::CanSpecializeGeneric); if (auto extensionDecl = as(genericDeclRef.getDecl()->inner)) { - if (isDeclRefTypeOf(extensionDecl->targetType.type) == genericTypeParamDeclRef) + if (isDeclRefTypeOf(extensionDecl->targetType.type) == declRef) { // If `T` is a generic parameter where the same generic is an extension on `T`, // then we need to add the extension itself as a facet. @@ -377,13 +463,10 @@ namespace Slang auto superType = getSup(astBuilder, constraintDeclRef); // We only consider constraints where the type represented - // by `genericTypeParamDeclRef` is the subtype, since those + // by `declRef` is the subtype, since those // constraints are the ones that give us information about // the declared supertypes. // - // TODO: consider whether other kinds of constraints could - // also apply here. - // auto subDeclRefType = as(subType); if (!subDeclRefType) { @@ -394,7 +477,7 @@ namespace Slang if (!subDeclRefType) continue; } - if (subDeclRefType->getDeclRef() != genericTypeParamDeclRef) + if (subDeclRefType->getDeclRef() != declRef) continue; // Because the constraint is a declared inheritance relationship, @@ -402,9 +485,9 @@ namespace Slang // as in all the preceding cases. // auto satisfyingWitness = _getASTBuilder()->getDeclaredSubtypeWitness( - selfType, - superType, - constraintDeclRef); + selfType, + superType, + constraintDeclRef); addDirectBaseType(superType, satisfyingWitness); } } -- cgit v1.2.3