Funnel all places where we create a generic signature builder to compute
the generic signature through a single entry point in the GSB
(`computeGenericSignature()`), and make `finalize` and `getGenericSignature`
private so no new uses crop up.
Tighten up the signature of `computeGenericSignature()` so it only works on
GSB rvalues, and ensure that all clients consider the GSB dead after that
point by clearing out the internal representation of the GSB.
We had two similar loops that performed name lookup for nested types on a
potential archetype, so consolidate those into a single implementation on
the equivalence class itself.
Once we compute a generic signature from a generic signature builder,
all queries involving that generic signature will go through a separate
(canonicalized) builder, and the original builder can no longer be used.
The canonicalization process then creates a new, effectively identical
generic signature builder. How silly.
Once we’ve computed the signature of a generic signature builder, “register”
it with the ASTContext, allowing us to move the existing generic signature
builder into place as the canonical generic signature builder. The builder
requires minimal patching but is otherwise fully usable.
Thanks to Slava Pestov for the idea!
Funnel all places where we create a generic signature builder to compute
the generic signature through a single entry point in the GSB
(`computeGenericSignature()`), and make `finalize` and `getGenericSignature`
private so no new uses crop up.
Tighten up the signature of `computeGenericSignature()` so it only works on
GSB rvalues, and ensure that all clients consider the GSB dead after that
point by clearing out the internal representation of the GSB.
We had two similar loops that performed name lookup for nested types on a
potential archetype, so consolidate those into a single implementation on
the equivalence class itself.
Same-type constraints are rederived based on the potential archetypes
within an equivalence class and the same-type constraints that link
them. In some cases, there may be parts that connect those same-type
constraints that are stored in "delayed" requirements (for which one
or both end-points have not been realized in a potential archetype);
consider those as well for connectedness.
In a sense, this is an artifact of the generic signature builder's
approach of realizing potential archetypes too readily, and this can
likely be simplified in the future. For now, it's important for the
minimization of same-type constraints in generic signatures.
Queries through the GenericSignatureBuilder about a particular type
parameter only really need information about the equivalence class in which that type parameter resides. Introduce a new entry point
GenericSignatureBuilder::resolveEquivalenceClass() that only
For now, resolveEquivalanceClass() is a thin layer over
resolveArchetype().
Introduce support for writing a GraphViz graph describing the
same-type constraints within an equivalence class. This visualization
helps debugging the minimization algorithm.
LLVM's GraphWriter is actually kinda awful, so there is some hackery
here both to dodge an overzealous static assertion and to munge the
output into an undirected graph.
NFC except for debugging.
When we detect that a requirement source is self-derived, identify the
redundant subpath and remove it to produce a new, smaller requirement
source that computes the same result. We were doing this form the
limited case where the redundant subpath ended at the end of the
requirement source; generalize that notion.
Fixes SR-5601.
When a potential archetype refers to a concrete (non-associated) type
declaration, we bind to that concrete type. Add a new requirement
source kind for this case that is always derived, separating it from
the nested-type-name-match source.
One important aspect of this is that typealiases in protocols that
"override" an associated type an inherited protocol will generate the
same requirement signature as the equivalent protocol that uses a
same-type constraint, making the suppression of the "hey, this is
equivalent to a same-type constraint now!" warning an ABI-preserving
change.
With this, remove a now-unnecessary hack for nested-name-match
requirement sources.
More correctly fix SR-5485: we were retaining self-derived conformance
sources when we shouldn't, which led to spurious "redundant
conformance" diagnostics and (much worse) incorrect minimized generic
signatures. Now, when we detect a self-derived conformance source,
return the minimal source that will derive the same conformance... and
retain that one if it's new.
processDelayedRequirements() was putting reprocessed-but-still-unresolved
requirements directly into the global delayed-requirements queue,
which meant that they didn't benefit from the optimization of putting
delayed requirements into the appropriate equivalence class.
Revise the meaning of UnresolvedHandlingKind::ReturnUnresolved (and
change its name to GenerateUnresolved) to still generate the
unresolved constraint, but notify the caller that it remained
unresolved. That way, we can track what happens when reprocessing
requirements (the statistics are *really* useful), but we still get
the optimization from putting delayed requirements onto the
equivalence class that can resolve them.
With this change, type checking the standard library is now only 1%
slower with ``enable-recursive-constraints`.
When a requirement is delayed, we know the equivalence class that
would have to change to make the requirement potentially
resolvable. Record the delayed requirement on that equivalence class.
When an equivalence class is modified for any reason, move all of the
delayed requirements to the global delayed-requirements queue so
they'll be reprocessed. This cuts the number of
reprocessed-but-still-unresolved requirements in half when
type-checking the standard library, taking us from 4x slower to 3x
slower.
Replace the overly-general bumpGeneration() with a "modified()"
operation on EquivalenceClass, indicating that the given
EquivalenceClass has been modified in some way. There are no
modifications in the system that do not directly affect an equivalence
class.
When we fail to resolve a particular type to a potential archetype,
track which equivalence class would have to change for the resolution
of that type to succeed. For now, this is "just" more bookkeeping.
Whenever we need a complete, well-formed potential archetype,
reprocess any delayed requirements, so that we pick up additional
requirements on that potential archetype.
This relies on us tracking a generation count for the GSB instance as
a whole, which gets bumped each time we add some new requirement or
create a new potential archetype, and only actually reprocessing
delayed requirements when the generation count exceeds the point at
which we last processed delayed requirements.
This gets the most basic recursive protocol constraint working
end-to-end and doesn't seem to break things.
Inheritance of a protocol from JavaScriptCore's JSExport protocol is
used to indicate that the methods and properties of that protocol
should be exported to JavaScript. The actual check to determine
whether a protocol (directly) inherits JSExport is performed via the
Objective-C runtime. Note that the presence of JSExport in the
protocol hierarchy is not sufficient; the protocol must directly
inherit JSExport.
Swift warns about redundant conformance requirements and eliminates
them from the requirement signature (and, therefore, the Objective-C
metadata). This behavior is incorrect for JSExport, because the
conformance is actually needed for this API to work properly.
Recognize a protocol's inheritance JSExport specifically (by
name) when computing the requirement signature of the protocol. When
we find such a redundancy, suppress the "redundant conformance
constraint" diagnostic and add a new (hidden) attribute
@_restatedObjCConformance(proto). The attribute is used only by Objective-C
protocol metadata emission to ensure that we get the expected metadata
in the Objective-C runtime.
Fixes rdar://problem/32674145.
This reverts commit afbdbae9d9.
Commit ded45a6e1c more than triples the
type checking time when building Swift.o, so I am going to revert that ,
and it looks like this needs to be reverted as well if that commit is
reverted.
All of this is dead code now that we don't use
ArchetypeResolutionKind::AlwaysPartial and, therefore, cannot ever
produce an unresolved potential archetype.
PotentiallArchetype::getNestedType(Identifier...) was using
ArchetypeResolutionKind::AlwaysPartial, even though only one client
(the code that itself handles AlwaysPartial) needed it. Add an
ArchetypeResolutionKind parameter to pass through, updating clients
accordingly.
Eliminates 5 effective uses of AlwaysPartial. Only two left!
When a concrete requirement is invalid due to the concrete type
lacking a conformance to a particular, required protocol, don't emit
that incorrect requirement---it causes invalid states further down the
line.
Fixes SR-5014 / rdar://problem/32402482.
While here, fix a comment that Huon noticed trailed off into oblivion.
Centralize and simplify the handling of conformance requirements
resolved by same-type-to-concrete requirements in a few ways:
* Always store a ProtocolConformanceRef in via-superclass and
via-concrete requirement sources, so we never lose this information.
* When concretizing a nested type based on its parent, use the
via-concrete conformance information rather than performing lookup
again, simplifying this operation considerably and avoiding
redundant lookups.
* When adding a conformance requirement to a potential archetype that
is equivalent to a concrete type, attempt to find and record the
conformance.
Fixes SR-4295 / rdar://problem/31372308.
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.
NestedTypeUpdate was mostly just the internal name for
ArchetypeResolutionKind, but the translation was a bit lossy and there
was no point in having separate enums. Standardize on
ArchetypeResolutionKind, adding a new case (WellFormed) to capture the
idea that we can create a new potential archetype only when we know
there is a nested type with that name---and avoid creating unresolved
potential archetypes.
Rather than performing typo correction at the very end of finalize(),
do it as part of delayed requirement handling when we cannot otherwise
make progress. This is a cleaner way to cope with typo correction that
gives us a better chance of getting to a sane result.
Fixes rdar://problem/31048352 by eliminating the need for tracking the
number of unresolved potential archetypes altogether. Fixes
rdar://problem/32077627.
Whenever we form a potential archetype that is unresolved (because it
names a member wasn't known at the time the potential archetype was
formed), create a corresponding delayed requirement to resolve the
potential archetype. This ensures that all potential archetypes get a
chance to be resolve, fixing the
nested type should have matched associated type
assertion in rdar://problem/31401161 (and others).
DelayedRequirements were using the general RequirementKind, which was
at best an approximation (we smoothed over the difference between
Superclass and Conformance requirements). Split out the Kind into its
own type, so we can extend it with GSB-specific kinds.
When we infer a requirement from the result type of a function, don't
warn if that requirement was also stated explicitly. This has been a
point of confusion since we introduced the redundancy warnings,
because users don't consider to result type to be an "input" to the
function in the way the compiler does. So, while technically it is
"correct" to warn, it's unintuitive---so stop.
Fixes SR-5072 / rdar://problem/31357967.
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.
Potential archetypes can resolve to either an associated type or a
typealias. Generalize the latter to "any concrete type", both because
the current implementation is unnecessarily narrow (typealiases aren't
actually special in this regard) and to get us closer to handling
lookups via superclass constraints when resolving these types.
Recursive concrete and superclass constraints are detected
per-equivalence-class; record them that way.
Use that information to drop recursive concrete and superclass
constraints from the resulting signature, which frees the canonical
generic signature builder from having to worry about such recursive
constraints. This eliminates the invalid-code crashes introduced in
the prior commit that disabled finalization for the canonical GSBs, as
well as fixing one other random crash-on-invalid.