summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoraidanfnv <aidanf@nvidia.com>2025-07-23 18:42:24 -0700
committerGitHub <noreply@github.com>2025-07-24 01:42:24 +0000
commit26b9a176e08ec6918d6fdebe1d7b586336f6f0fd (patch)
tree5a625c1dd35754ba559d9d30fdbf3afcd1190f7d
parent9666fbcab891156fb058d6a1b8f427ccc3ffecab (diff)
Skip creating transitive witnesses for interface conformances that are inherited through structs (#7597)
* Eliminate null-pointer reference in multilevel struct interface inheritance * Add test * Replace witness nullptr guard with conformance check to skip the witness * Update test * Skip creating transitive witness entirely for struct-struct-interface * format code (#14) Co-authored-by: slangbot <186143334+slangbot@users.noreply.github.com> * Removes casts, check for identity witness --------- Co-authored-by: slangbot <ellieh+slangbot@nvidia.com> Co-authored-by: slangbot <186143334+slangbot@users.noreply.github.com>
-rw-r--r--source/slang/slang-check-inheritance.cpp34
-rw-r--r--tests/experiments/generic/multilevel-inheritance.slang31
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>();
+}