Under certain circumstances, introducing a concrete same-type or
superclass constraint can re-introduce conformance constraints
which were previously redundant.
For example, consider this code, which we correctly support today:
protocol P {
associatedtype T : Q
}
protocol Q {}
class SomeClass<U : Q> {}
struct Outer<T> where T : P {
func inner<U>(_: U) where T == SomeClass<U>, U : Q {}
}
The constraint 'T == SomeClass<U>' makes the outer constraint
`T : P' redundant, because SomeClass already conforms to P.
It also introduces an implied same-type constraint 'U == T.T'.
However, whereas 'T : P' together with 'U == T.T' make 'U : Q'
redundant, the introduction of the constraint 'T == SomeClass<U>'
removes 'T : P', so we re-introduce an explicit constraint 'U : Q'
in order to get a valid generic signature.
This code path did the right thing for constraints derived via
concrete same-type constraints, but it did not handle superclass
constraints.
As a result, this case was broken:
struct Outer<T> where T : P {
func inner<U>(_: U) where T : SomeClass<U>, U : Q {}
}
This is the same example as above, except T is related via a
superclass constraint to SomeClass<U>, instead of via a concrete
same-type constraint.
The subtlety here is that we must check if the superclass type
actually conforms to the requirement source's protocol, because it
is possible to have a superclass-constrained generic parameter
where some conformances are abstract. Eg, if SomeClass did not
conform to another protocol P2, we could write
func foo<T, U>(_: T, _: U) where T : SomeClass<U>, T : P2 {}
In this case, 'T : P2' is an abstract conformance on the type 'T'.
The common case where this would come up in real code is when you
have a class that conforms to a protocol with an associated type,
and one of the protocol requirements was fulfilled by a default in
a protocol extension, eg:
protocol P {
associatedtype T : Q
func foo()
}
extension P {
func foo() {}
}
class ConformsWithDefault<T : Q> : P {}
The above used to crash; now it will type-check correctly.
Fixes <rdar://problem/44736411>, <https://bugs.swift.org/browse/SR-8814>..
Name lookup might find an associated type whose protocol is not in our
conforms-to list, if we have a superclass constraint and the superclass
conforms to the associated type's protocol.
We used to return an unresolved type in this case, which would result in
the constraint getting delayed forever and dropped.
While playing wack-a-mole with regressing crashers, I had to do some
refactoring to get all the tests to pass. Unfortuanately these refactorings
don't lend themselves well to being peeled off into their own commits:
- maybeAddSameTypeRequirementForNestedType() was almost identical to
concretizeNestedTypeFromConcreteParent(), except for superclasses
instead of concrete same-type constraints. I merged them together.
- We used to drop same-type constraints where the subject type was an
ErrorType, because maybeResolveEquivalenceClass() would return an
unresolved type in this case.
This violated some invariants around nested types of ArchetypeTypes,
because now it was possible for a nested type of a concrete type to
be non-concrete, if the type witness in the conformance was missing
due to an error.
Fix this by removing the ErrorType hack, and adjusting a couple of
other places to handle ErrorTypes in order to avoid regressing with
invalid code.
Fixes <rdar://problem/45216921>, <https://bugs.swift.org/browse/SR-8945>,
<https://bugs.swift.org/browse/SR-12744>.
When adding a superclass constraint, we need to find any nested
types belonging to protocols that the superclass conforms to,
and introduce implicit same-type constraints between each nested
type and the corresponding type witness in the superclass's
conformance to that protocol.
Fixes <rdar://problem/39481178>, <https://bugs.swift.org/browse/SR-11232>.
Detect situation when it's impossible to determine types for
closure parameters used in the body from the context. E.g.
when a call closure is associated with refers to a missing
member.
```swift
struct S {
}
S.foo { a, b in } // `S` doesn't have static member `foo`
let _ = { v in } // not enough context to infer type of `v`
_ = .foo { v in } // base type for `.foo` couldn't be determined
```
Resolves: [SR-12815](https://bugs.swift.org/browse/SR-12815)
Resolves: rdar://problem/63230293
doesn't conform to the associatedtype's protocol (only in diagnostic mode).
This allows the solver to find solutions for more cases involving requirement
failures for dependent member types without special cases across the solver
that check for dependent member types with no type variables.
Just like in cases where both sides are dependent member types
with resolved base that can't be simplified to a concrete type
let's ignore this mismatch and mark affected type variable as a hole
because something else has to be fixed already for this to happen.
If it's possible to build an Objective-C key path for key path
expression make sure that its implicitly generated string literal
expression has a `String` type.
Resolves: rdar://problem/57356196
When an overriding property containing willSet or didSet is not within
a type, the type checker could crash due to a missing "self"
declaration. Check this condition. Fixes rdar://problem/57040259.
The lookupDirect means that we can see type declarations nested inside of a protocol. If we do not filter these invalid declarations, we will offer a bogus fixit on top of a cycle diagnostic. Remove these types from consideration entirely so we don't crash and don't offer bogus fixits.
Resolves rdar://57003317
This commit changes how we represent caller-side
default arguments within the AST. Instead of
directly inserting them into the call-site, use
a DefaultArgumentExpr to refer to them indirectly.
The main goal of this change is to make it such
that the expression type-checker no longer cares
about the difference between caller-side and
callee-side default arguments. In particular, it
no longer cares about whether a caller-side
default argument is well-formed when type-checking
an apply. This is important because any
conversions introduced by the default argument
shouldn't affect the score of the resulting
solution.
Instead, caller-side defaults are now lazily
type-checked when we want to emit them in SILGen.
This is done through introducing a request, and
adjusting the logic in SILGen to be more lenient
with ErrorExprs. Caller-side defaults in primary
files are still also currently checked as a part
of the declaration by `checkDefaultArguments`.
Resolves SR-11085.
Resolves rdar://problem/56144412.
If a protocol requirement has a type that's a nested member
type of another member type, eg,
protocol P {
associatedtype A : Q
func f(_: A.B)
}
Then we don't actually want to use 'f()' to infer the witness
for 'A'. By avoiding doing so, we eliminate some cycles which
can allow some programs to type check that didn't before.
If a property has multiple property wrappers attached, we'll have multiple nested calls, where each call's argument is a call to construct the next wrapper in the chain. However, when we use multiple wrappers consecutively, we cannot just rely on the call's type matching the innermost wrapper's type, because it will match the first wrapper in the sequence of consective wrappers and we'll end up crashing in SILGen. So, we should check if the call's argument is another call and look into that before checking the types.