A substitution map contains conformances, and a conformance can contain
a substitution map. This will always be a DAG, but not a tree, and to
avoid exponential blowup in certain edge cases, let's cache the work to
avoid visiting the same substitution map repeatedly, if multiple
conformances refer to the same substitution map.
Tracking seen declarations and substitution maps only detects the
situation where the opaque type's underlying type contains itself
with the same substitution map. However, it is also possible to
recurse with a different substitution map.
In general termination is undecidable with a problem like this,
so instead of trying to catch cycles, just impose a termination
limit.
This converts a stack overflow into an assertion, which is still
not ideal; we should really diagnose something instead. But this
is a first step.
While the intent behind this functor was noble, it has grown in complexity
considerably over the years, and it seems to be nothing but a source of
crashes in practice. I don't want to deal with it anymore, so I've decided
to just subsume all usages with LookUpConformanceInModule instead.
Convert a bunch of places where we're dumping to stderr and calling
`abort` over to using `ABORT` such that the message gets printed to
the pretty stack trace. This ensures it gets picked up by
CrashReporter.
There were two problems that have been there for years:
- SubstitutionMap::lookupConformance() assumes that every concrete conformance
in the path has a root normal conformance. But calling getRootNormalConformance()
on a self conformance would assert.
- SelfProtocolConformance::getAssociatedConformance() was not implemented. While
self-conforming protocols do not have associated types, they can inherit from
other protocols, and we model this with an associated conformance requirement
having a subject type of `Self`.
Both problems were hidden by the fact that ProtocolConformanceRef::subst()
directly handled self-conforming existentials without calling into the
substitution map. But that is the wrong place for other reasons. The refactoring
in a209ff8869 exposed both of the above issues.
Fixes rdar://problem/151162470.
The abstract conformance hack is no longer necessary, so now all of the
cases can all be handled by ProtocolConformanceRef::getAssociatedConformance(),
without having to dispatch on the conformance kind.
Instead of passing in the substituted type, we pass in the
InFlightSubstitution. This allows the substituted type to be
recovered if needed, but we can now skip computing it for
the common case of LookUpConformanceInSubstitutionMap.
Suppose protocol P has a primary associated type A, and we have
a `any P<S>` value. We form the generalization signature <T>
with substitution map {T := S}, and the existential signature
<T, Self where T == Self.A>.
Now, if we call a protocol requirement that takes Self.A.A.A,
we see this is fixed concrete type, because the reduced type of
Self.A.A.A is T.A.A in the existential signature.
However, this type parameter is not formed from the
conformance requirements of the generalization signature
(there aren't any), so we cannot directly apply the outer
substitution map.
Instead, change the outer substitution conformance lookup
callback to check if the reduced type parameter is valid
in the generalization signature, and not just rooted in a
generic parameter of the generalization signature.
If it isn't, fall back to global conformance lookup.
A better fix would introduce new requirements into the
generalization signature to handle this, or store them
separately in the generic environment itself. But this is fine
for now.
- Fixes https://github.com/swiftlang/swift/issues/79763.
- Fixes rdar://problem/146111083.
This replaces the oddly-named mapIntoTypeExpansionContext() method
on SubstitutionMap itself in favor of a global function, just like
the ones that take Type and ProtocolConformanceRef.
We implement getIdentitySubstitutionMap() by passing in
a no-op substitution callback. Remove the unnecessary
getCanonicalType() call, to ensure that the abstract
conformance in the identity substitution map uses the
sugared form of the subject type.
Some requirement machine work
Rename requirement to Value
Rename more things to Value
Fix integer checking for requirement
some docs and parser changes
Minor fixes
There was a bunch of logic to lazily populate replacement types
corresponding to reducible generic parameters. This didn't seem
to have a clear purpose so let's remove it.
Although I don't plan to bring over new assertions wholesale
into the current qualification branch, it's entirely possible
that various minor changes in main will use the new assertions;
having this basic support in the release branch will simplify that.
(This is why I'm adding the includes as a separate pass from
rewriting the individual assertions)
We should check if the type parameter actually conforms to our
protocol before we do the global lookup, otherwise we might
return an abstract conformance instead of an invalid conformance.
I don't know if there's any way to exercise this today though.