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-decl.cpp | 63 +++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 23 deletions(-) (limited to 'source/slang/slang-check-decl.cpp') diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index ad3f94fc3..02e3241a9 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -2278,14 +2278,18 @@ namespace Slang markSelfDifferentialMembersOfType(as(context->parentDecl), context->conformingType); + witnessTable->add(requirementDeclRef.getDecl(), RequirementWitness(context->conformingType)); if (doesTypeSatisfyAssociatedTypeConstraintRequirement(context->conformingType, requirementDeclRef, witnessTable)) { - witnessTable->add(requirementDeclRef.getDecl(), RequirementWitness(context->conformingType)); // Increase the epoch so that future calls to Type::getCanonicalType will return the up-to-date folded types. m_astBuilder->incrementEpoch(); return true; } + else + { + witnessTable->m_requirementDictionary.remove(requirementDeclRef.getDecl()); + } // Something went wrong. return false; @@ -2471,19 +2475,16 @@ namespace Slang // conformance on the synthesized decl. checkAggTypeConformance(aggTypeDecl); - if (doesTypeSatisfyAssociatedTypeConstraintRequirement(satisfyingType, requirementDeclRef, witnessTable)) + witnessTable->add(requirementDeclRef.getDecl(), RequirementWitness(satisfyingType)); + if (!doesTypeSatisfyAssociatedTypeConstraintRequirement(satisfyingType, requirementDeclRef, witnessTable)) { - witnessTable->add(requirementDeclRef.getDecl(), RequirementWitness(satisfyingType)); - - // Incrase the epoch so that future calls to Type::getCanonicalType will return the up-to-date folded types. - m_astBuilder->incrementEpoch(); - return true; + // Note: the call to `doesTypeSatisfyAssociatedTypeConstraintRequirement` should always succeed. + // If not, there is something wrong with the code synthesis logic. For now we just return false + // instead of crashing so the user can work around the issues. + witnessTable->m_requirementDictionary.remove(requirementDeclRef.getDecl()); + return false; } - - // Note: the call to `doesTypeSatisfyAssociatedTypeConstraintRequirement` should always succeed. - // If not, there is something wrong with the code synthesis logic. For now we just return false - // instead of crashing so the user can work around the issues. - return false; + return true; } void SemanticsDeclHeaderVisitor::visitGenericTypeConstraintDecl(GenericTypeConstraintDecl* decl) @@ -2497,7 +2498,7 @@ namespace Slang CheckConstraintSubType(decl->sub); decl->sub = TranslateTypeNodeForced(decl->sub); decl->sup = TranslateTypeNodeForced(decl->sup); - if (!isValidGenericConstraintType(decl->sup) && !as(decl->sub.type)) + if (!decl->isEqualityConstraint && !isValidGenericConstraintType(decl->sup) && !as(decl->sub.type)) { getSink()->diagnose(decl->sup.exp, Diagnostics::invalidTypeForConstraint, decl->sup); } @@ -3548,18 +3549,28 @@ namespace Slang bool SemanticsVisitor::doesTypeSatisfyAssociatedTypeConstraintRequirement(Type* satisfyingType, DeclRef requiredAssociatedTypeDeclRef, RefPtr witnessTable) { + SLANG_UNUSED(satisfyingType); + // We will enumerate the type constraints placed on the // associated type and see if they can be satisfied. // bool conformance = true; Val* witness = nullptr; - for (auto requiredConstraintDeclRef : getMembersOfType(m_astBuilder, requiredAssociatedTypeDeclRef)) + for (auto requiredConstraintDeclRef : getMembersOfType(m_astBuilder, requiredAssociatedTypeDeclRef)) { // Grab the type we expect to conform to from the constraint. auto requiredSuperType = getSup(m_astBuilder, requiredConstraintDeclRef); + auto subType = getSub(m_astBuilder, requiredConstraintDeclRef); + // Perform a search for a witness to the subtype relationship. - witness = tryGetSubtypeWitness(satisfyingType, requiredSuperType); + witness = tryGetSubtypeWitness(subType, requiredSuperType); + if (witness) + { + auto genConstraint = as(requiredConstraintDeclRef.getDecl()); + if (genConstraint && genConstraint->isEqualityConstraint && !isTypeEqualityWitness(witness)) + witness = nullptr; + } if (witness) { // If a subtype witness was found, then the conformance @@ -3588,6 +3599,15 @@ namespace Slang if (declRefType->getDeclRef().getDecl()->hasModifier()) return false; } + + // Register the satisfying type to the witness table + // before checking the constraints, since the subtype of + // the constraints maybe referencing the satisfying type via + // witness lookups. + auto requirementWitness = RequirementWitness(satisfyingType->getCanonicalType()); + witnessTable->m_requirementDictionary[requiredAssociatedTypeDeclRef.getDecl()] + = requirementWitness; + // We need to confirm that the chosen type `satisfyingType`, // meets all the constraints placed on the associated type // requirement `requiredAssociatedTypeDeclRef`. @@ -3601,15 +3621,11 @@ namespace Slang // TODO: if any conformance check failed, we should probably include // that in an error message produced about not satisfying the requirement. - if(conformance) + if (!conformance) { - // If all the constraints were satisfied, then the chosen - // type can indeed satisfy the interface requirement. - witnessTable->add( - requiredAssociatedTypeDeclRef.getDecl(), - RequirementWitness(satisfyingType->getCanonicalType())); + witnessTable->m_requirementDictionary.remove(requiredAssociatedTypeDeclRef.getDecl()); } - + return conformance; } @@ -9667,7 +9683,8 @@ namespace Slang ASTNodeType::DeclRefType); auto typeParamDecl = as(genericTypeConstraintDecl.getDecl()->sub.type)->getDeclRef().getDecl(); List* constraintTypes = genericConstraints.tryGetValue(typeParamDecl); - assert(constraintTypes); + if (!constraintTypes) + continue; constraintTypes->add(genericTypeConstraintDecl.getDecl()->getSup().type); } -- cgit v1.2.3