When creating disjunctions with favored constraints in constraint
optimization, we actually ended up duplicating the constraint that we
favor, resulting with extra constraints in the disjunction.
Noticed while debugging other issues.
Track the types we've seen instead of the type declarations we've
passed through, which eliminates some holes relating to generic types.
Detect infinite expansions by imposing an arbitrary limit.
Fixes rdar://30355804
This is still disabled by default, and as with the previous
implementation does not pass all tests if enabled.
Rather than looking for applicable function constraints and then looking
at the bind overload disjunctions associated with those, instead
directly collect all bind overload disjunctions and revise the enabled
elements of those disjunctions by attempting to bind them simultaneously
with the elements of other disjunctions that are linked to this one
through applicable function constraints.
Now that mayHaveSuperclass() is back to its old meaning, we can't
piggy-back off of it anymore and must add a new bit of logic
for class-constrained existential to superclass conversions.
Also re-organize the code a bit.
Make sure we use the right 'self' type in various places. When
calling a Self-returning class method on a subclass existential,
the following has to happen correctly:
- The existential is opened to produce an archetype with a superclass
constraint.
- The archetype is upcast to a class type to produce the 'self'
parameter for the call.
- The method call returns a value with the same type as the 'self'
parameter.
- The return value is downcast to the opened archetype.
- The opened archetype is converted back to an existential.
Some SILGen tests in an upcoming patch exercise this code path.
* Use the presence of an argument type to check for associated values
hasOnlyCasesWithoutAssociatedValues returns true for any serialized
enum declaration whether or not it has cases. This never really came
up because it's mostly relevant to Sema's proto-deriving mechanism. Fix
this by using the presence of the case's argument type instead.
* Separate checks for presence of cases and enum simplicity
Necessary because the old behavior was an artifact of the
implementation.
An earlier patch fixed the case where some tuple elements
were lvalue types. However this only looked into tuples
nested one level deep, when a more correct fix checks the
lvalue recursive property of the type.
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.
If the -enable-experimental-subclass-existentials staging flag
is on, resolveType() now allows protocol compositions to contain
class types. It also diagnoses if a composition has more than one
superclass requirement.
Also, change diagnostics that talked about 'protocol composition'
to 'protocol-constrained type'.
Since such types can now contain a superclass constraint, it's not
correct to call them protocol composition.
"Protocol-constrained type" isn't quite accurate either because
'Any' has no protocols, and 'AnyObject' will have no protocols but
a general class constraint; but those are edge cases which won't
come up in these diagnostics.
If the member came from a class, we're not going to substitute
the 'Self' type. Instead, we open the existential, upcast the
archetype up to the class type and access the member as if it
were a class member in the usual way.
This function takes a member of a class and a base type, and returns
the correct 'self' type to substitute into the member's type.
When accessing a member of a subclass existential, if the member
was found via the superclass constraint, we have to erase the
existential down to the class type to calculate the member's
substituted type.
We already had special logic to handle class-constrained archetypes
in the callers of getSuperclassForDecl(); move this check into the
method, and add a similar check for subclass existentials, which
now support the getSuperclass() method.
This consolidates calculations which need to look at every
protocol in an existential type. Soon we will also have to
deal with superclass constrained existentials, so start
updating call sites that look at all protocols to use the
new ExistentialLayout and correctly handle a class constraint
as well.
Also, eventually I will kill off the AnyObject protocol and
model it as a protocol composition with no protocols or
superclass, but the requiresClass() flag set.
This is not quite modeled this way yet and AnyObject still
exists, but the new abstraction is a step in the right
direction.
A protocol extension can add additional generic constraints on
'Self' or associated types thereof. In particular, 'Self' itself
can have a superclass constraint placed on it.
There were a couple of problems with this corner case:
- Type aliases defined in protocols that 'Self' conforms to _as a
concrete type_ to were not handled properly, triggering an assertion.
For example,
protocol P { typealias T = ... }
class C : P {}
protocol Q {}
extension Q where Self : C { ... T ... }
The conformance o P comes from the 'Self : C' constraint.
- If the type was found in a superclass of 'Self', we used the wrong
base type for the substitution.
For example,
protocol P {}
class C<T> { typealias A = T }
class D : C<Int> {}
extension P where Self : D { ... A ... }
The substituted type of 'A' should be computed with a self type
of C<Int> here.
Also, take another stab at cleaning up the mess that is
resolveTypeInContext() and related bits of code.
Don't pass in the opened type; instead have the caller call
simplifyType() if needed. Also, make computeSubstitutions()
bail out if there's no generic signature, which allowed
unifying several generic vs non-generic code paths.
Hopefully there is enough short circuiting in there now that
we're not doing any extra work in the non-generic case.
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.
There are a handful of things, but the primary ones are that we really
don't want to track depth of recursion so much as whether we are
processing at the "top level" of constraints we're looking at or not so
that we can determine whether we can disable elements from a
disjunction.
Related, there are places where we can bail out earlier if we know
that *any* neighboring constraint passes.
Also updating the way we gather neighboring constraints to be
independent of the function that simplifies them. The original code was
wrong in that in bailed as soon as one of the simplifications
failed (which meant we might not gather all of them).
We want to validate both type in same-type or conformance constraints,
even when the first type is ill-formed, so we don't leave null types
around for later phases to crash on.
Fixes rdar://problem/31093854.