Skip to content

Conversation

@slavapestov
Copy link
Contributor

This fixes a regression introduced by e3c8f42, but the root cause was actually a subtle invariant violation in IRGen.

FulfillmentMap's use of canonical types as keys assumes that canonical type equality is sufficient for checking if two types "are the same". However, this is not true when those types contain type parameters, because two distinct type parameters might belong to the same equivalence class.

Thus, when we take the type's context substitution map, and apply it to each type parameter in our given list of requirements, the substitution operation could output a different but equivalent type parameter.

However, it turns out that in practice, we only end up here with a type that is either fully substituted, or is exactly the declared interface type of their nominal.

In the latter case, the type's substitution map is the identity substitution map, so we can just detect this case and skip the call to subst(). This avoids the problem.

I added an assertion that will fire if this assumption is ever violated in the future. To support the general case, we will need to pass down a generic signature that describes the type parameters that appear in the given type, and use this signature to reduce the type of each lookup key before we proceed.

Fixes rdar://160649141.

…tadata()

This fixes a regression introduced by e3c8f42,
but the root cause was actually a subtle invariant violation
in IRGen.

FulfillmentMap's use of canonical types as keys assumes that
canonical type equality is sufficient for checking if two types
"are the same". However, this is not true when those types
contain type parameters, because two distinct type parameters
might belong to the same equivalence class.

Thus, when we take the type's context substitution map, and
apply it to each type parameter in our given list of
requirements, the substitution operation could output a
different but equivalent type parameter.

However, it turns out that in practice, we only end up here
with a type that is either fully substituted, or is exactly
the declared interface type of their nominal.

In the latter case, the type's substitution map is the
identity substitution map, so we can just detect this case and
skip the call to subst(). This avoids the problem.

I added an assertion that will fire if this assumption is ever
violated in the future. To support the general case, we will
need to pass down a generic signature that describes the
type parameters that appear in the given type, and use this
signature to reduce the type of each lookup key before we
proceed.

Fixes rdar://160649141.
@slavapestov slavapestov marked this pull request as draft November 6, 2025 03:51
@slavapestov
Copy link
Contributor Author

@aschwaighofer @rjmccall This fixes the provided test case, but some validation tests now fail because it is in fact not true that the type we get here is always either fully substituted or the declared interface type. So this needs a real fix where we either pass down the right generic signature for reduction, or we map the type into the right generic environment so that we can then do ASSERT(!type->hasTypeParameter()) here.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant