diff options
| -rw-r--r-- | source/slang/slang-check-inheritance.cpp | 34 | ||||
| -rw-r--r-- | tests/experiments/generic/multilevel-inheritance.slang | 31 |
2 files changed, 60 insertions, 5 deletions
diff --git a/source/slang/slang-check-inheritance.cpp b/source/slang/slang-check-inheritance.cpp index 164828bac..49ca3d3ac 100644 --- a/source/slang/slang-check-inheritance.cpp +++ b/source/slang/slang-check-inheritance.cpp @@ -858,13 +858,37 @@ void SharedSemanticsContext::_mergeFacetLists( // SubtypeWitness* baseIsSubtypeOfFacet = foundFacet->subtypeWitness; - auto selfIsSubtypeOfFacet = _getASTBuilder()->getTransitiveSubtypeWitness( - selfIsSubtypeOfBase, - baseIsSubtypeOfFacet); + // Check if this would create an unwanted struct->struct->interface conformance + // We want to prevent transitive witnesses of the form: struct Child -> struct Parent -> + // interface IFoo + bool shouldSkipTransitiveWitness = false; - indirectFacet->setSubtypeWitness(_getASTBuilder(), selfIsSubtypeOfFacet); + auto selfType = selfIsSubtypeOfBase->getSub(); + auto baseType = selfIsSubtypeOfBase->getSup(); + auto facetType = baseIsSubtypeOfFacet->getSup(); - ioMergedFacets.add(indirectFacet); + if (selfType && baseType && facetType) + { + auto selfDeclRef = isDeclRefTypeOf<StructDecl>(selfType); + auto baseDeclRef = isDeclRefTypeOf<StructDecl>(baseType); + auto facetDeclRef = isDeclRefTypeOf<InterfaceDecl>(facetType); + + // Only skip if we have struct->struct->interface + // and the struct->struct witness is not the identity witness + shouldSkipTransitiveWitness = selfDeclRef && baseDeclRef && facetDeclRef && + !isTypeEqualityWitness(selfIsSubtypeOfBase); + } + + if (!shouldSkipTransitiveWitness) + { + auto selfIsSubtypeOfFacet = _getASTBuilder()->getTransitiveSubtypeWitness( + selfIsSubtypeOfBase, + baseIsSubtypeOfFacet); + + indirectFacet->setSubtypeWitness(_getASTBuilder(), selfIsSubtypeOfFacet); + + ioMergedFacets.add(indirectFacet); + } } // We picked one `foundFacet` above to be added to the merged diff --git a/tests/experiments/generic/multilevel-inheritance.slang b/tests/experiments/generic/multilevel-inheritance.slang new file mode 100644 index 000000000..f3db67d70 --- /dev/null +++ b/tests/experiments/generic/multilevel-inheritance.slang @@ -0,0 +1,31 @@ +//TEST:SIMPLE(filecheck=CHECK): -target spirv -gnone -std 2026 +//TEST:SIMPLE(filecheck=CHECK): -target spirv -gminimal -std 2026 +//TEST:SIMPLE(filecheck=CHECK_LEGACY): -target spirv -gnone -std 2025 +//TEST:SIMPLE(filecheck=CHECK_LEGACY): -target spirv -gminimal -std 2025 +//TEST:SIMPLE(filecheck=CHECK_LEGACY): -target spirv -gnone -std legacy +//TEST:SIMPLE(filecheck=CHECK_LEGACY): -target spirv -gminimal -std legacy + +// CHECK: error 30811 +// CHECK: struct Child : Parent {}; +// CHECK: error 38029 +// CHECK: getObject<Child>(); + +// CHECK_LEGACY: warning 30816 +// CHECK_LEGACY: struct Child : Parent {}; +// CHECK_LEGACY: error 38029 +// CHECK_LEGACY: getObject<Child>(); + +interface IFoo {}; +struct Parent : IFoo {}; +struct Child : Parent {}; + +T getObject<T>() where T : IFoo +{ + return T(); +} + +[shader("compute")] +void main() +{ + getObject<Child>(); +} |
