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.
A `GenericSignatureBuilder` only needs to be finalized when we need to
compute a generic signature from it or otherwise require diagnostics.
Canonical generic signature builders don’t need either of those, so unless we
are performing the expensive idempotency checking, only do the minimal work
to “process delayed requirements”.
This gives a 3x speedup in type-checking time for the “trivial” example
let x = [1, 2]
because we do a lot less work on deserialization of generic environments.
Part of rdar://problem/32116933.
The GenericSignatureBuilder requires `finalize()` to be called before a
generic signature can be retrieved with `getGenericSignature()`. Most of the former isn’t strictly needed unless you want a generic signature, and the
latter is potentially expensive. `computeGenericSignature()` combines the two
operations together, since they are conceptually related. Update most of the
callers to the former two functions to use `computeGenericSignature()`.
Archetype anchors are (re-)computed often, but shouldn't change all
that much. Cache them in the equivalence class for a ~15% speedup
type-checking the standard library.
This stops after 5 recurrences of the same associated type. It is a
gross hack and a terrible idea, here as a placeholder to prevent us
from running off the rails in ill-formed code. This will go away when
we get further along the path with recursive protocol constraints.
Now that we detect recursion based on repetition within the potential
archetypes, we no longer rely on passing down "visited" sets to
detect/diagnose recursion. Remove them.
Rather than detecting recursion and bailing early, delay requirements
that would form recursive types. Note that we aren't actually
processing them later.
Teach addInheritedRequirements() to take an UnresolvedType, so the
requirements it adds can be delayed if needed. More importantly, teach
the primary caller (addConformanceRequirement) not to use
getNestedType directly; instead, form an appropriate Type and let the
type-resolution machinery handle it.
Apply the same logic used for self-derived conformance constraints,
where we drop constraints derived from concrete conformances, to the
remaining kinds of constraints covered by isSelfDerivedSource().
Factor out a core operation of RequirementSource that walks the
potential archetypes from the root to the end of the path, enumerating
each partial RequirementSource along with the potential archetype to
which it applies. Use it for getting the final archetype to which the
RequirementSource refers, as well as simplifying the self-derived
check for conformance requirements.
When an otherwise abstract conformance constraint is derived from a
concrete conformance, retain the abstract conformance by removing the
requirement source that involves the concrete conformance. This
eliminates our reliance on the concrete conformance, which is not
retained as part of the generic signature.
Fixes rdar://problem/31163470 and rdar://problem/31520386.
When a requirement mentions a concrete type, that type might utter
other types (e.g., Set<T>) that infer requirements (here, T:
Hashable). Perform requirement inference for such types.
Part of rdar://problem/31520386.
Rather than true (an error occurred) or false (the constraint was
resolved), introduce ConstraintResult to better model what
happened. NFC for now, but the intent here is to report unresolved
constraints through this mechanism.
The dependent type that is the subject of a ProtocolRequirement
source is independently computable based on the root potential
archetype of the source and the potential archetype to which the
requirement applies, i.e., it's just the dependent member type that
gets from the former to the later. Compute this directly, rather than
relying on the passed-down dependent type.
This is possible now because we no longer capriciously rebase
requirements onto the representatives of equivalence classes, nor
destroy any other structural information in the formation of potential
archetypes.
As we've done with layout requirements, introduce a new entry point
(addTypeRequirement) that handles unresolved type requirements of the
form `T: U`, resolves the types, and then can
1. Diagnose any immediate problems with the types,
2. Delay the type requirement if one of the types cannot be resolved,
or
3. Break it into one or more "direct" requirements.
This allows us to clean up and centralize a bunch of checking that was
scattered/duplicated across the GSB and type checker.
When we resolve() a type that is being used in a constraint, allow
that resolution to fail. If it does fail, then record the constraint
we were trying to address (via a stub that, currently, just drops it)
and continue on. NFC for now; this is intended to allow us to limit
the explosion of types in recursive systems.
The general self-derived check doesn't really make sense for
conformance constraints, because we want to distinguish among
different protocol conformances.
Diagnose redundant same-type constraints using most of the same
machinery for diagnosing other redundant constraints. However,
same-type constraints are particularly interesting because
redundancies can be spelled in a number of different ways. Address
this using the connected components of the subgraph involving only
derived requirements (which is already used for the minimized generic
signature). Then, separate all of the non-derived requirements into
the intracomponent requirements and intercomponent requirements:
* All of the intracomponent requirements are redundant by definition,
because the components are defined by derived constraints.
* For the intercomponent requirements, form a spanning tree among the
various components and diagnose as redundant any edges that do not
extend the spanning tree.
It's better to compute this information once while we're sorting
through all of the same-type constraints, so we can use it later when
performing queries (e.g., enumerating requirements).
As we've done with all of the other kinds of constraints, keep track
of all of the layout constraints on the equivalence class. Use the
normal mechanism to diagnose conflicts between different layout
constraints, warn about duplicate layout constraints, etc.
As we've been doing with other kinds of constraints, track *all* of
the requirement sources for deriving same-type constraints within the
equivalence class, then remove self-derived constraints at the end.
There is no checking for duplicated same-type constraints yet.
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.