Skip to content

Conversation

@kaizhangNV
Copy link
Contributor

@kaizhangNV kaizhangNV commented Jan 16, 2026

Close #9622.

The root cause of this issue is that we diagnose the error too early when collecting the inheritance info of a generic type parameter, because some of the checking might not be ready. Assume this case:

interface IFoo<T> where T:XXX where T.Differential == T
func<U, Foo>()
   where U:XXX
   where U == U.Differential
   where Foo : IFoo<U>
   where Foo.Differential : IFoo<U.Differential>

this code will report error that typeof(S) doesn't have member of Differential. That is because we check Foo.Differential while Foo : IFoo<U> is being checked.

The reason of this is because of following sequence:

  • checking Type constraints Foo : IFoo<U>
    • checking GenericAppExpr IFoo<U> : it will find a candidate - IFoo<T> T:XXX where T.Differential == T
      • it will check constraint of this generic: check whether "U.Differential == U" is satisfied
        • collect inheritance info of U.Differential

Now in collecting the inheritance info of U.Differential, we will find the dependent generic parent of U, which is the func again, so we will check all the type constraints of func, and finally it will start checking Foo.Differential : IFoo<U.Differential>. But note that Foo : IFoo<U> is still being checked now, so the Foo's type is unknown, we cannot lookup the member of Differential. Therefore, error will be reported.

The current solution for this issue is that we will use subVisitor to suppress the error in this case because it's ok to have error in this case. If there is error, the inheritance info will be incomplete, then the upper level caller will also fail because it can't find all the type constraints to satisfy the requirement. And we also disable the cache in this case, so in the later inheritance info collection when every thing is ready, there will still be chance to get the complete inheritance info.

@kaizhangNV kaizhangNV requested a review from a team as a code owner January 16, 2026 05:27
@kaizhangNV kaizhangNV added the pr: non-breaking PRs without breaking changes label Jan 16, 2026
NV-xiaoyongs added a commit to NV-xiaoyongs/slang that referenced this pull request Jan 16, 2026
NV-xiaoyongs added a commit to NV-xiaoyongs/slang that referenced this pull request Jan 19, 2026
NV-xiaoyongs added a commit to NV-xiaoyongs/slang that referenced this pull request Jan 20, 2026
NV-xiaoyongs added a commit to NV-xiaoyongs/slang that referenced this pull request Jan 20, 2026
@kaizhangNV kaizhangNV changed the title Issue 9622 Fix a cyclic reference issue while checking type constraints Jan 20, 2026
Copy link
Collaborator

@jkwak-work jkwak-work left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks reasonable enough.
But I am not familiar enough to tell if there is a better way to solve the problem or not.

Copy link
Collaborator

@csyonghe csyonghe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to get to the bottom of the type constraint checking process and investigate why we are checking the generic parent again during checking the generic constraints, since this shouldn't happen.

When we check where Foo : IFoo<U>, the first two constraints should have already been checked and we should already have the inheritance info for U and U.Differential, so checking IFoo<U> shouldn't trigger recalculation of inheritance info of U.

A possible cause is that while checking generic constraints, we were disabling caching of inheritance info because a following constraint can add more facets to a generic type parameter. It feels to me that instead of disabling caching completely, we should just incrementally update the inheritance info of the constrained type.


void removeInheritanceInfoFromCache(DeclRef<Decl>& key)
{
if (m_mapDeclRefToInheritanceInfo.tryGetValue(key))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we can just call remove directly without checking existence first.

NV-xiaoyongs added a commit to NV-xiaoyongs/slang that referenced this pull request Jan 22, 2026
NV-xiaoyongs added a commit that referenced this pull request Jan 23, 2026
@kaizhangNV kaizhangNV marked this pull request as draft January 26, 2026 04:01
@kaizhangNV
Copy link
Contributor Author

Mark this to draft, as we might need further refactor to get a better fix for this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr: non-breaking PRs without breaking changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cannot Access Associated Types of Abstract Generic Parameters at Struct Level

3 participants