Commit Graph

637 Commits

Author SHA1 Message Date
Slava Pestov
124b8fd546 GSB: Rename updateNestedTypeForConformance() to getOrCreateNestedType() and simplify it 2021-03-05 21:32:27 -05:00
Slava Pestov
0be55c130d GSB: Use redundant requirement graph in enumerateRequirements() 2021-03-01 17:50:26 -05:00
Slava Pestov
72bd35a344 GSB: New algorithm for identifying redundant requirements
Generic signature minimization needs to diagnose and remove any
redundant requirements, that is, requirements that can be proven
from some subset of the remaining requirements.

For each requirement on an equivalence class, we record a set of
RequirementSources; a RequirementSource is a "proof" that the
equivalence class satisfies the requirement.

A RequirementSource is either "explicit" -- meaning it
corresponds to a generic requirement written by the user -- or it
is "derived", meaning it can be proven from some other explicit
requirement.

The most naive formulation of the minimization problem is that
we say that an explicit requirement is redundant if there is a
derived source for the same requirement. However, this is not
sufficient, for example:

protocol P {
  associatedtype A : P where A.A == Self
}

In the signature <T where T : P>, the explicit requirement
T : P also has a derived source T.A.A : P. However, this source
is "self-derived", meaning that in order to obtain the
witness table for T.A.A : P, we first have to obtain the witness
table for T.A.

The GenericSignatureBuilder handled this kind of 'self-derived'
requirement correctly, by removing it from the list of sources.
This was implemented in the removeSelfDerived() function.

After removeSelfDerived() was called, any remaining derived
requirement sources were assumed to obsolete any explicit
source for the same requirement.

However, even this was not sufficient -- namely, it only handled
the case where a explicit requirement would imply a derived
source for itself, and not a cycle involving multiple explicit
sources that would imply each other.

For example, the following generic signature would be misdiagnosed
with *both* conformance requirements as redundant, resulting in
an invalid generic signature:

protocol P {
  associatedtype T : P
}

func f<T : P, U : P>(_: T, _: U) where T.X == U, U.X == T {}

In the above example, T : P has an explicit requirement source,
as well as a derived source (U : P)(U.X : P). Similarly, U : P
has an explicit requirement source, as well as a derived source
(T : P)(T.X : P). Since neither of the derived sources were
"self-derived" according to our definition, we would diagnose
*both* explicit sources as redundant. But of course, after
dropping them, we are left with the following generic signature:

func f<T, U>(_: T, _: U) where T.X == U, U.X == T {}

This is no longer valid -- since neither T nor U have a conformance
requirement, the nested types T.X and U.X referenced from our
same-type requirements are no longer valid.

The new algorithm abandons the "self-derived" concept. Instead,
we build a directed graph where the vertices are explicit
requirements, and the edges are implications where one explicit
requirement implies another. In the above example, each of the
explicit conformance requirements implies the other. This means
a correct minimization must pick exactly one of the two -- not
zero, and not both.

The set of minimized requirements is formally defined as the
minimum set of requirements whose transitive closure is the
entire graph.

We compute this set by first building the graph of strongly
connected components using Tarjan's algorithm. The graph of SCCs
is a directed acyclic graph, which means we can compute the root
set of the DAG. Finally, we pick a suitable representative
requirement from each SCC in the root set, using the lexshort
order on subject types.

This commit implements the new algorithm, runs it on each generic
signature and asserts some properties about the results, but
doesn't actually use the algorithm for computing the minimized
signature or diagnosing redundancies; that will come in the next
commit.
2021-03-01 17:19:22 -05:00
Slava Pestov
ce8549b31b GSB: Record the original type for self-derived conformances
RequirementSources with Superclass and Concrete kind would
reference a protocol conformance. However in the case where
the concrete type was an existential conforming to itself,
the SelfProtocolConformance does not store the original
type. Since self-conforming existentials don't have any
nested types, we don't really need to store this conformance
at all.

Instead of storing a protocol conformance in the case where
the original type is an existential, just the original type
itself. This allows us to recover the requirement from the
RequirementSource, which is important for the new
implementation of computing redundant requirements.
2021-02-28 23:41:56 -05:00
Slava Pestov
3a93a178e2 GSB: Remove RequirementSource::ConcreteTypeBinding 2021-02-26 22:20:32 -05:00
Slava Pestov
00ed470844 GSB: Replace RequirementSource::Derived with ::Layout
'Derived' was not a great name, since we already use the term
'derived requirement source' to mean something else.

A Derived source was only added in one place, when recording
a superclass constraint -- the idea is that this source
supercedes any explicit layout constraint, eg

    class SomeClass {}
    func foo<T>(_: T) where T : SomeClass, T : AnyObject {}

Here we have two sources for the 'T : AnyObject' layout constraint:

    Explicit: T
    Explicit: T -> Derived

Note that the 'Derived' requirement source does not store
a 'proof' -- we can't figure out _how_ we determined that
the explicit 'T : AnyObject' constraint is redundant here.

In the case where a superclass requirement makes a protocol
conformance redundant, we do have a 'proof', because the
'Superclass' requirement source stores a conformance:

    class SomeClass : SomeProto {}
    func foo<T>(_: T) where T : SomeClass, T : SomeProto {}

    Explicit: T
    Explicit: T -> Superclass: [SomeClass : P]

From looking at the second requirement source, we can
determine that the requirement was imposed by the explicit
constraint 'T : SomeClass'.

For the 'Layout' requirement source, there's not really a
"conformance", so we can just store the superclass type:

    Explicit: T
    Explicit: T -> Layout: SomeClass
2021-02-26 14:55:40 -05:00
Slava Pestov
f8b293e8c9 GSB: RequirementRHS can now store a ProtocolDecl * 2021-02-26 14:53:52 -05:00
Slava Pestov
24de1913ac GSB: Merge collectRequirements() with enumerateRequirements() 2021-02-25 17:19:23 -05:00
Slava Pestov
e0c7627598 GSB: getBestConstraintSource() never returns nullptr 2021-02-25 17:19:23 -05:00
Slava Pestov
b9f5267ac1 GSB: Stop printing enumerated requirements in dump()
The call to enumerateRequirements() here actually makes debugging
more difficult, since it has a lot of side effects, for example
calling maybeResolveEquivalenceClass() and removeSelfDerived().

Also, this is the only usage of enumerateRequirements() other than
collectRequirements(), which allows the two to be merged together
and simplified.
2021-02-25 17:19:23 -05:00
Slava Pestov
34d3236316 GSB: Avoid re-resolving FloatingRequirementSources 2021-02-24 16:33:38 -05:00
Slava Pestov
39397d76a1 GSB: Remove HadAnyRedundantConstraints
Redundant requirements no longer pose a problem for the new
getConformanceAccessPath() implementation.
2021-02-23 16:26:04 -05:00
Slava Pestov
d492a53bf1 GSB: Remove unused SourceLoc parameter from computeGenericSignature() 2021-02-22 23:06:27 -05:00
Slava Pestov
3d5ca29993 GSB: Dump conformance and same-type requirement sources in EquivalenceClass::dump() 2021-02-18 22:35:00 -05:00
Slava Pestov
44dac01d99 GSB: Fix getMinimalConformanceSource() for top-level requirements in a requirement signature
Consider the following program:

protocol P1 {
  associatedtype A : P2
}

protocol P2 {
  associatedtype A
}

func f<T>(_: T) where T : P2, T.A : P1, T.A.A == T {}

There are two proofs of T : P2:

- The explicit requirement in f()'s generic signature.

- Since T.A.A == T, we can also prove T : P2 via T.A.A : P2:
  - First, we prove that T.A : P1 via the explicit requirement
    in f()'s generic signature.
  - Second, we prove that T.A.A : P1 via Self.A : P2 in P1's
    requirement signature.

However, the second proof does not render the explicit requirement
T : P2 redundant, because it relies on the existence of the
nested type T.A, which only exists if T : P2.

This is captured in getMinimalConformanceSource(), which returns
nullptr for the requirement source corresponding to the second proof
above. It does this by looking at the root type of the requirement
source, T.A.

Now consider the analogous situation but with protocols -- let's
replace f() with a protocol P3:

protocol P3 : P2 where Self.A : P1, Self.A.A == Self {}

Here, we also have two proofs of Self : P2:

- The explicit requirement in P3's requirement signature.
  - First, we prove that Self.A : P1 via the explicit requirement
    in P3's requirement siganture.
  - Second, we prove that Self.A.A : P1 via Self.A : P2 in P1's
    requirement signature.

Once again, the second proof implicitly depends on the explicit
requirement, so we cannot use it to mark the explicit requirement
as redundant. However, since the requirement source root type here
is just 'Self', we were unable to recognize this, and we would
diagnose the requirement as redundant and drop it, resulting in
computing an invalid requirement signature for protocol P3.

To fix this, handle requirements at the top level of a protocol
requirement signature just like they are explicit requirements.

Fixes https://bugs.swift.org/browse/SR-13850 / rdar://problem/71377571.
2021-02-18 22:35:00 -05:00
Slava Pestov
034c2be004 GSB: An unresolved DependentMemberType might resolve to a concrete TypeAliasDecl with a dependent underlying type
Fixes https://bugs.swift.org/browse/SR-11639 / rdar://problem/56466696
2021-02-12 17:47:31 -05:00
Slava Pestov
8edf4264ae GSB: Better handling of unresolved DependentMemberTypes in maybeResolveEquivalenceClass()
A DependentMemberType can either have a bound AssociatedTypeDecl,
or it might be 'unresolved' and only store an identifier.

In maybeResolveEquivalenceClass(), we did not handle the unresolved
case when the base type of the DependentMemberType had itself been
resolved to a concrete type.

Fixes <rdar://problem/71162777>.
2021-02-11 16:33:35 -05:00
Richard Wei
18fe723543 Merge pull request #35811 from rxwei/69980056-differentiable-reverse
[AutoDiff] Add '@differentiable(reverse)'.
2021-02-08 04:32:27 -08:00
Richard Wei
af8942d940 [AutoDiff] Rename '@differentiable' to '@differentiable(reverse)'.
Compiler:
- Add `Forward` and `Reverse` to `DifferentiabilityKind`.
- Expand `DifferentiabilityMask` in `ExtInfo` to 3 bits so that it now holds all 4 cases of `DifferentiabilityKind`.
- Parse `@differentiable(reverse)` and `@differentiable(_forward)` declaration attributes and type attributes.
- Emit a warning for `@differentiable` without `reverse`.
- Emit an error for `@differentiable(_forward)`.
- Rename `@differentiable(linear)` to `@differentiable(_linear)`.
- Make `@differentiable(reverse)` type lowering go through today's `@differentiable` code path. We will specialize it to reverse-mode in a follow-up patch.

ABI:
- Add `Forward` and `Reverse` to `FunctionMetadataDifferentiabilityKind`.
- Extend `TargetFunctionTypeFlags` by 1 bit to store the highest bit of differentiability kind (linear). Note that there is a 2-bit gap in `DifferentiabilityMask` which is reserved for `AsyncMask` and `ConcurrentMask`; `AsyncMask` is ABI-stable so we cannot change that.

_Differentiation module:
- Replace all occurrences of `@differentiable` with `@differentiable(reverse)`.
- Delete `_transpose(of:)`.

Resolves rdar://69980056.
2021-02-07 14:09:46 -08:00
Slava Pestov
fd809ca0c9 GSB: Instead of sorting connected components, sort the final requirements
There are fewer of them, since it is possible for the vast
majority of connected components to generate no requirements.
2021-02-07 01:14:52 -05:00
Slava Pestov
65620d75f3 GSB: FloatingRequirementSource::getSource() now takes a ResolvedType 2021-02-07 01:14:52 -05:00
Slava Pestov
df3c87911c GSB: PotentialArchetypes now store their canonical type
Instead of recomputing it on every call to getDependentType(),
we can just store it in there instead of the GenericParamKey
or AssociatedTypeDecl.

We still need to 're-sugar' user-visible dependent types to
get the right generic parameter name; a new getSugaredDependentType()
utility method is called in the right places for that.
2021-02-05 17:23:31 -05:00
Slava Pestov
143b3c18e9 GSB: Remove some dead code 2021-02-05 15:56:29 -05:00
Slava Pestov
5cec731355 GSB: DerivedSameTypeComponent can store a Type instead of a PotentialArchetype * 2021-02-05 15:56:29 -05:00
Anthony Latsis
afcb1665f8 GSB: Handle concrete ResolvedTypes in ArchetypeType::resolveNestedType()
A nested type of an archetype type might be concrete, for example, via a
same-type constraint:

extension SomeProtocol where SomeAssoc == Int {
  ... Self.SomeAssoc ...
}

This can happen in one of two ways; either the EquivalenceClass of the
nested type has a concrete type, or it is "fully concrete" because
there is no equivalence class and maybeResolveEquivalenceClass() returns
a ResolvedType storing the concrete type.

For some reason we didn't handle the second case here.

Fixes https://bugs.swift.org/browse/SR-13519 / rdar://problem/68531679
2021-01-12 23:52:44 -05:00
Slava Pestov
445d747622 AST: Move GenericParamList and friends to GenericParamList.{h,cpp} 2020-09-29 19:51:03 -04:00
Slava Pestov
ce550f2464 AST: Try harder to preserve type sugar in AbstractGenericSignatureRequest
AbstractGenericSignatureRequest tries to minimize the number of GSBs that we
spin up by only creating a GSB if the generic parameter and requirement types
are canonical. If they're not canonical, it first canonicalizes them, then
kicks off a request to compute the canonical signature, and finally, re-applies
type sugar.

We would do this by building a mapping for re-sugaring generic parameters,
however this mapping was only populated for the newly-added generic parameters.

If some of the newly-added generic requirements mention the base signature's
generic parameters, they would remain canonicalized.

Fixes <rdar://problem/67579220>.
2020-08-24 19:16:36 -04:00
Slava Pestov
92bc89b78f GSB: Add an inferred AnyObject constraint to @objc protocol requirement signatures
This simplifies GenericSignatureImpl::requiresClass(), which no longer
has to look through the conformances of the equivalence class.
2020-08-13 00:23:47 -04:00
Slava Pestov
34650e8f3a Merge pull request #32799 from AnthonyLatsis/sself-is-fixed
AssociatedTypeInference: Allow Self as a fixed type witness
2020-08-06 19:43:56 -04:00
Slava Pestov
94c6bff65d AST: Replace some calls to getDeclaredType() with getDeclaredInterfaceType() 2020-07-31 13:39:01 -04:00
Slava Pestov
c46eb22fcd AST: Don't attach trailing where clause requirements to the GenericParamList
Previously we had two representations for the 'where' clause of a
parsed declaration; if the declaration had generic parameters of
its own, we would store them in the GenericParamList, otherwise
we would store them separately in a TrailingWhereClause instance.

Since the latter is more general and also used for protocols and
extensions, let's just use it for everything and simplify
GenericParamList in the process.
2020-07-28 02:07:16 -04:00
Robert Widmann
ec885b027b [NFC] const-qualify Inheritance-Clause-Bearing PointerUnion 2020-07-23 20:45:24 -07:00
Slava Pestov
7e5d566180 GSB: An anchor cannot have a concrete parent type
EquivalenceClass::getAnchor() always returns a canonical type and
the parent of a canonical type is itself be canonical.

This means that EquivalenceClass::getTypeInContext() can safely
assume that the parent type of a DependentMemberType maps to an
ArchetypeType in the GenericEnvironment.

Instead of trying to handle the case where the parent is concrete,
let's just crash by changing the conditional cast to an
unconditional one.
2020-07-21 21:29:12 -04:00
Slava Pestov
b76733b614 GSB: Simplify ResolvedType implementation
We don't need to store the EquivalenceClass anymore.
2020-07-16 23:31:34 -04:00
Slava Pestov
c0d981ad61 GSB: Simplify maybeResolveEquivalenceClass()
When passing in wantExactPotentialArchetype=false, we don't actually ever
call getDependentType() on the result. So the Type + EquivalenceClass form
of ResolvedType can be removed.
2020-07-16 23:31:34 -04:00
Anthony Latsis
28531141d2 AssociatedTypeInference: Self is a valid fixed type witness 2020-07-15 22:34:24 +03:00
Slava Pestov
71e267d5b1 GSB: Teach 'derived via concrete' computation about superclass constraints
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>..
2020-06-21 23:42:10 -04:00
Anthony Latsis
267e32dcd8 Merge pull request #32118 from AnthonyLatsis/post-increment-cleanup
[NFC] Pre- increment and decrement where possible
2020-06-02 20:10:29 +03:00
Anthony Latsis
9fd1aa5d59 [NFC] Pre- increment and decrement where possible 2020-06-01 15:39:29 +03:00
Varun Gandhi
c14e934563 [NFC] Remove redundant includes for llvm/ADT/SmallSet.h. 2020-05-31 13:07:45 -07:00
Owen Voorhees
45bc578ae5 [SourceManager] Rename line and column APIs for clarity 2020-05-21 12:54:07 -05:00
Slava Pestov
653fa07260 GSB: Fix maybeResolveEquivalenceClass() with member type of superclass-constrained type
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>.
2020-05-19 20:28:51 -04:00
Slava Pestov
514a0423b6 GSB: Concretize nested types when adding a superclass constraint
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>.
2020-05-15 21:58:58 -04:00
Arnold Schwaighofer
5c4bbf3de9 Merge pull request #31736 from aschwaighofer/fix_protocol_conformance_subst
Existentials don't always conform to a protocol via an abstract confo…
2020-05-13 11:27:25 -07:00
Anthony Latsis
df9103e9d7 [NFC] AST: Const-qualify GenericSignatureImpl 2020-05-13 01:03:08 +03:00
Arnold Schwaighofer
b40b1be41d Existentials don't always conform to a protocol via an abstract conformance
So it is not always correct to use the current conformance when substituting.

rdar://62894495
2020-05-12 12:20:01 -07:00
Anthony Latsis
724c76041d Merge pull request #31555 from AnthonyLatsis/arch-resolution-kind
GSB: Propagate ArchetypeResolutionKind to resolveDependentMemberTypes
2020-05-07 04:24:24 +03:00
Anthony Latsis
dfcc656501 GSB: Propagate ArchetypeResolutionKind to resolveDependentMemberTypes when resolving equivalence classes 2020-05-06 23:43:53 +03:00
Anthony Latsis
bc49a8e232 [Diags] NFC: Audit diags using DeclName for names of nominals and vars 2020-05-02 16:08:24 +03:00
Varun Gandhi
65577940d0 [NFC] Get rid of -Wrange-loop-analysis warnings. (#31324) 2020-04-27 09:47:52 -07:00