Refusing to acknowledge unavailable conformances at this point in the
requirement machine doesn't allow us to make use of unavailable
conformances from unavailable contexts, something which code currently
depends on. Limit the new filtering behavior to `Sendable` conformances
where we need them, as a narrow fix for this regression. We'll revisit
the approach here later.
Fixes rdar://94154905.
When determining whether a superclass conforms to a particular protocol,
skip unavailable conformances. This way, we don't minimize away a
constraint that might only apply to subclasses of the specified
superclass.
Fixes rdar://91853658.
A conformance requirement on a concrete type parameter is redundant if the
concrete type conforms to the protocol.
The replacement path for the conformance rule is based on a concrete
conformance rule introduced by the property map. Since the concrete
conformance rule is not associated with a requirement ID, this would
normally muffle the redundancy warning, because we don't want to
suggest removing a rule that depends on a non-redundant, non-explicit
rule.
However, concrete conformance rules don't actually appear in the
minimal signature, so skip them when computing the set of non-redundant,
non-explicit rules to ensure that the original conformance requirement
is still diagnosed as redundant.
See the comment at the top of ConcreteContraction.cpp for a detailed explanation.
This can be turned off with the -disable-requirement-machine-concrete-contraction
pass, mostly meant for testing. A few tests now run with this pass both enabled
and disabled, to exercise code paths which are otherwise trivially avoided by
concrete contraction.
Fixes rdar://problem/88135912.
Consider a signature with a conformance requirement, and two
identical superclass requirements, both of which make the
conformance requirement redundant.
The conformance will have two requirement sources, the explicit
source and a derived source based on one of the two superclass
requirements, whichever one was processed first.
If we end up marking the *other* superclass requirement as
redundant, we would incorrectly conclude that the conformance
was not redundant. Instead, if a derived source is based on a
redundant requirement, we can't just discard it right away;
instead, we have to check if that source could have been
derived some other way.
It's mostly redundant, we already have TypeBase::isExactSuperclassOf().
The only difference between the two is that the TypeChecker method
admitted self-conforming class-constrained existentials (like C & P
where P is an @objc protocol with no static methods) as subclasses
of themselves.
This was actually not sound in the general case, because you can
call static methods and required initializers on the *class* C,
so I'm going to unilaterally ban this, but since the importer
creates such types, I have to allow it if the class is an
imported class.
Extend the inputs to InheritedTypeRequest, SuperclassTypeRequest, and
EnumRawTypeRequest to also take a TypeResolutionStage, describing what
level of type checking is required. The GenericSignatureBuilder relies
only on structural information, while other clients care about the
full interface type.
Only the full interface type will be cached, and the contextual type
(if requested) will depend on that.
If a generic parameter has both a class and protocol constraint,
walking up to the class's superclass would cause us to subsequently
ignore any initializer requirements in the protocol.
Fixes <https://bugs.swift.org/browse/SR-1663>, <rdar://problem/22722738>.
If the class itself is generic and we're looking up a nested type
from a conformance, we would pass an interface type to
mapTypeOutOfContext() and crash.
The full state of the GSB isn’t all that useful for testing, creates a ton of noise and gets in the way of some cleanups we’d like to make in the interface.
Stop dumping it as part of `-debug-generic-signatures`.
The full state of the GSB isn’t all that useful for testing, creates a ton of noise and gets in the way of some cleanups we’d like to make in the interface.
Stop dumping it as part of `-debug-generic-signatures`.
When type-checking a function or subscript that itself does not have generic
parameters (but is within a generic context), we were creating a generic
signature builder which will always produce the same generic signature as
the enclosing context. Stop creating that generic signature builder.
Instead, teach the CompleteGenericTypeResolver to use the generic signature
+ the canonical generic signature builder for that signature to resolve
types, which also eliminates some extraneous re-type-checking.
Improves type-checking performance of the standard library by 36%.
The full state of the GSB isn’t all that useful for testing, creates a ton of noise and gets in the way of some cleanups we’d like to make in the interface.
Stop dumping it as part of `-debug-generic-signatures`.
When type-checking a function or subscript that itself does not have generic
parameters (but is within a generic context), we were creating a generic
signature builder which will always produce the same generic signature as
the enclosing context. Stop creating that generic signature builder.
Instead, teach the CompleteGenericTypeResolver to use the generic signature
+ the canonical generic signature builder for that signature to resolve
types, which also eliminates some extraneous re-type-checking.
Improves type-checking performance of the standard library by 36%.
Rather than abusing the "superclass" requirement source with a null
protocol conformance, introduce a separate "structurally derived"
requirement source kind for structurally-derived requirements that
don't need any additional information, e.g., the class layout
requirement derived from a superclass requirement.
The previous commit tightened up our choice of requirement sources for
superclass and layout constraints, but always assumed a match
existed. In cases where it does not, don't fail; rather, use an
abstract source, which we do elsewhere when we're synthesizing
requirements.
This is a defensive approach to cope with cases where we might not
have precisely the same value within one of our recorded
constraints. This currently only occurs when there are errors (hence
the elimination of the odd "hasError()"), but will come up more often
when we're deriving information from a combination of constraints.
This was previously handled very late, by the type checker, which led
to weird ordering dependencies and meant that we could end up with
well-formed code where the GSB was left with unresolved types. We want
such states to never exist, so make sure we can resolve everything in
the GSB.
This PR addresses TODOs from #8241.
- It supports merging for layout constraints, e.g., if both a _Trivial constraint and a _Trivial(64) constraint appear on a type parameter, we keep only _Trivial(64) as a more specific layout constraint. We do a similar thing for ref-counted/native-ref-counted. The overall idea is to keep the more specific of two compatible layout constraints.
- The presence of a superclass constraint implies a layout constraint, e.g., a superclass constraint implies _Class or _NativeClass
We were emitting a superclass constraint for each connected component
of derived same-type constraints within an equivalence class, when in
fact we only need one superclass constraint for the entire equivalence
class.
Move the storage for the protocols to which a particular potential
archetype conforms into EquivalenceClass, so that it is more easily
shared. More importantly, keep track of *all* of the constraint
sources that produced a particular conformance requirement, so we can
revisit them later, which provides a number of improvements:
* We can drop self-derived requirements at the end, once we've
established all of the equivalence classes
* We diagnose redundant conformance requirements, e.g., "T: Sequence"
is redundant if "T: Collection" is already specified.
* We can choose the best path when forming the conformance access
path.
Start reshuffling RequirementSource to store more information about
requirements in protocols. As a small step, track the source locations
for requirements written within the protocols themselves.
Note: there's a QoI regression here where we get duplicated
diagnostics (due to multiple generic signature builders being built
from a bad signature).
Use the same infrastructure we have for same-type-to-concrete
constraints to check superclass constraints. Specifically,
* Track all superclass constraints; never "update" a requirement source
* Remove self-derived superclass constraints
* Pick the best superclass constraint within each connected component
of an equivalence class and use that for requirement generation.
* Diagnose conflicting superclass requirements during finalization
* Diagnose redundant superclass requirements (during finalization)
Use TrailingObjects to help us efficiently store the root potential
archetype within requirement sources, so we can reconstruct the
complete path from the point where a requirement was created to the
potential archetype it affects.
The test changes are because we are now dumping the root potential
archetype as part of -debug-generic-signatures.
This was necessary when we would 'adopt' archetypes from outer
contexts, but that is long gone, and the only thing it accomplished
was emitting duplicate diagnostics.
Unify the handling of the "inheritance" clauses of a generic type
parameter, associated type, or protocol, walking them in a
TypeRepr-preserving manner and adding requirements as they are
discovered. This sets the stage for providing better source-location
information [*].
This eliminates a redundant-but-different code path for protocol
"inheritance" clauses, which was using
ProtocolDecl::getInheritedProtocols() rather than looking at the
actual TypeReprs, and unifies the logic with that of associated types
and type parameters. This eliminates a near-DRY violation, sets us up
for simplifying the "inherited protocols" part of ProtocolDecl, and
sets us up better for the soon-to-be-proposed
class C { }
protocol P: C { }
[*] We still drop it, but now we have a FIXME!
Reimplement the RequirementSource class, which captures how
a particular requirement is satisfied by a generic signature. The
primary goal of this rework is to keep the complete path one follows
in a generic signature to get from some explicit requirement in the
generic signature to some derived requirement or type, e.g.,
1) Start at an explicit requirement "C: Collection"
2) Go to the inherited protocol Sequence,
3) Get the "Iterator" associated type
4) Get its conformance to "IteratorProtocol"
5) Get the "Element" associated type
We don't currently capture all of the information we want in the path,
but the basic structure is there, and should also allow us to capture
more source-location information, find the "optimal" path, etc. There are
are a number of potential uses:
* IRGen could eventually use this to dig out the witness tables and
type metadata it needs, instead of using its own fulfillment
strategy
* SubstitutionMap could use this to lookup conformances, rather than
it's egregious hacks
* The canonical generic signature builder could use this to lookup
conformances as needed, e.g., for the recursive-conformances case.
... and probably more simplifications, once we get this right.
Clean up the representation of PotentialArchetype in a few small ways:
* Eliminate the GenericTypeParamType* at the root, and instead just
store a GenericParamKey. That makes the potential archetypes
independent of a particular set of generic parameters.
* Give potential archetypes a link back to their owning
ArchetypeBuilder, so we can get contextual information (etc.) when
needed. We can remove the "builder" arguments as a separate step.
Also, collapse getName()/getDebugName()/getFullName() into
getNestedName() and getDebugName(). Generic parameters don't have
"names" per se, so they should only show up in debug dumps.
In support of the former, clean up some of the diagnostics emitted by
the archetype builder that were using 'Identifier' or 'StringRef'
where they should have been using a 'Type' (i.e., the type behind the
dependent archetype).
Teach GenericEnvironment to lazily populate its mapping from generic
parameters to context types when queried (e.g., during
substitutition) rather than assuming that will be pre-populated before
any queries occur.
We're still forcing all of the archetypes when the generic environment
is created by the archetype builder; baby steps!