-
Notifications
You must be signed in to change notification settings - Fork 377
Fix Enum Constructor Specialization in Generic Types #8996
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
dc0921f to
49b0816
Compare
49b0816 to
061665a
Compare
tangent-vector
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great. Thank you again for digging down (well, up in terms of the compiler's dataflow) to the root cause of the problem.
I would like to hear your response to the two questions I raised about the code, but I don't know if either of those can/should turn into an actual code change.
| } | ||
| for (auto decor : innerInst->getDecorations()) | ||
|
|
||
| if (innerInst) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we think this conditional is still good/necessary?
Unless we have a reason to believe that innerInst could be null for valid input code, I would rather see a SLANG_ASSERT(innerInst) than an if(innerInst). Either way, this code seems unrelated to the actual fix.
| RequirementWitness( | ||
| m_astBuilder->getMemberDeclRef(getDefaultDeclRef(context->parentDecl), synFunc))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm really happy with this fix. Thank you for taking the time to root cause this by chasing the invalid code all the way back to the source.
I also want to say that I greatly appreciate the quality of your PR description; it explains the root cause and the reason why this is the right fix clearly in terms of the architecture of the compiler and its rules/invariants.
For any other contributors who happen to see this PR or this comment: this is a good example of taking the time to look past the appealing simplicity of an LLM's initial analysis and keep digging until you, the human, can be confident that you've actually fixed the problem.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My one concrete question about the code of the fix is: is there are reason why this couldn't just be:
RequirementWitness(getDefaultDeclRef(synFunc))
My intuition is that using getDefaultDeclRef(synFunc) would yield the same DeclRef that you are currently constructing with the more complicated expression, but at the same time there could easily be something I'm missing.
Fix Enum Constructor Specialization in Generic Types
This PR fixes an issue where synthesized constructors for enums nested within generic types were failing to specialize correctly.
The Problem
When
slangsynthesizes a requirement witness (like a constructor) for an enum, it creates a new function declaration (synFunc) and adds it to the AST. The original code was creating aDirectDeclRefto this new function:A
DirectDeclRefrepresents a reference to a declaration without any context. It effectively treats the function as if it exists globally or independently.This becomes a problem when the enum is nested within a generic type (e.g.,
struct Test<T> { enum Inner { ... } }). The constructor forInnerinherently depends on the generic parameters of its parent (e.g.,T). When the compiler later attempts to specializeTest<int>, it encounters theDirectDeclRef. Because this reference has no base or parent pointer, the compiler cannot trace it back to the genericTest<T>, and thus has no way to substituteintforT. This results in an invalid reference to an unspecialized generic constructor within a specialized type context, leading to verification failures or incorrect IR.The Fix
The fix is to construct the witness using a
MemberDeclRefthat is rooted at the parent declaration:getDefaultDeclRef(context->parentDecl)retrieves the correct reference to the parent enum (which correctly links back to the generic struct).getMemberDeclRefcreates a reference tosynFuncrelative to that parent.This constructs a proper chain of references:
Constructor -> Enum -> Generic Struct. When the compiler specializesTest<int>, it can now traverse this chain, identify that the constructor is part of a generic instantiation, and correctly apply substitutions to produce the specialized constructor forTest<int>.Inner.This PR also adds a few nullptr checks and removes the duplicated
findWitnessValwithfindWitnessTableEntry.Fixes: #8887