Although I don't plan to bring over new assertions wholesale
into the current qualification branch, it's entirely possible
that various minor changes in main will use the new assertions;
having this basic support in the release branch will simplify that.
(This is why I'm adding the includes as a separate pass from
rewriting the individual assertions)
Previously getReducedType() would dump debug info if we had an invalid
dependent member type, but an invalid root type parameter would cause
a segfault. Fix this.
This basically undoes 3da6fe9c0d, which in hindsight was wrong.
There were no other usages of TypeArrayView anywhere else except for
GenericSignature::getGenericParams(), and it was almost never what
you want, so callers had to convert back and forth to an ArrayRef.
Remove it.
This is phase-1 of switching from llvm::Optional to std::optional in the
next rebranch. llvm::Optional was removed from upstream LLVM, so we need
to migrate off rather soon. On Darwin, std::optional, and llvm::Optional
have the same layout, so we don't need to be as concerned about ABI
beyond the name mangling. `llvm::Optional` is only returned from one
function in
```
getStandardTypeSubst(StringRef TypeName,
bool allowConcurrencyManglings);
```
It's the return value, so it should not impact the mangling of the
function, and the layout is the same as `std::optional`, so it should be
mostly okay. This function doesn't appear to have users, and the ABI was
already broken 2 years ago for concurrency and no one seemed to notice
so this should be "okay".
I'm doing the migration incrementally so that folks working on main can
cherry-pick back to the release/5.9 branch. Once 5.9 is done and locked
away, then we can go through and finish the replacement. Since `None`
and `Optional` show up in contexts where they are not `llvm::None` and
`llvm::Optional`, I'm preparing the work now by going through and
removing the namespace unwrapping and making the `llvm` namespace
explicit. This should make it fairly mechanical to go through and
replace llvm::Optional with std::optional, and llvm::None with
std::nullopt. It's also a change that can be brought onto the
release/5.9 with minimal impact. This should be an NFC change.
We had two notions of canonical types, one is the structural property
where it doesn't contain sugared types, the other one where it does
not contain reducible type parameters with respect to a generic
signature.
Rename the second one to a 'reduced type'.
The RequirementSignature generalizes the old ArrayRef<Requirement>
which stores the minimal requirements that a conforming type's
witnesses must satisfy, to also record the protocol typealiases
defined in the protocol.
We would bail out early if there was no property map entry for this key.
But this means if a term without properties was non-canonical, this
method would still return false.
On the other hand, it is possible for a DependentMemberType to be
canonical, even if its parent is not, in the case where the parent
is fixed to a concrete type.
To handle this properly, change the type walk to use a TypeWalker
directly instead of findIf(); this allows us to return
Action::SkipChildren upon encountering a DependentMemberType.
The primary use of isCanonicalTypeInContext() was from inside
GenericSignature::verify(). So the assertion there will become
stricter.
We would skip recording a conformance access path if the subject
type canonicalized to a concrete type, but this was incorrect.
The correct formulation is to use the _canonical anchor_ and not
the canonical type as the caching key; that is, we always want it
to be a type parameter, even if it is fixed to a concrete type,
because type parameters fixed to concrete types can appear in
the middle of conformance access paths, as the example in the
radar demonstrates.
Fixes rdar://problem/83687967.
This was manifesting as module interfaces printing generic parameters
as `τ_0_0` in some cases.
Note that the GSB has the same bug, so this test case will fail with
-requirement-machine=off. I don't plan on fixing the bug in the GSB
unless we need to.
Fixes rdar://problem/78977127.
The property map stores the concrete type or superclass bound for all
terms whose suffix is equal to some key, so eg if you have
protocol P {
associatedtype T where T == U?
associatedtype U
}
Then you have this rewrite system
[P].T => [P:T]
[P].U => [P:U]
[P:T].[concrete: Optional<τ_0_0> with <[P:U]>] => [P:T]
Which creates this property map
[P:T] => { [concrete: Optional<τ_0_0> with <[P:U]>] }
Now if I start with a generic signature like
<T, U where U : P>
This produces the following rewrite system:
τ_0_1.[U] => τ_0_1
τ_0_1.T => τ_0_1.[P:T]
τ_0_1.U => τ_0_1.[P:U]
Consider the computation of the canonical type of τ_0_1.T. This term
reduces to τ_0_1.[P:T]. The suffix [P:T] has a concrete type symbol in
the property map, [concrete: Optional<τ_0_0> with <[P:U]>].
However it would not be correct to canonicalize τ_0_1.[P:T] to
Optional<τ_0_0>.subst { τ_0_0 => getTypeForTerm([P:T]) }; this
produces the type Optional<τ_0_0.T>, and not Optional<τ_0_1.T> as
expected.
The reason is that the substitution τ_0_0 => getTypeForTerm([P:T])
is "relative" to the protocol Self type of P, since domain([P:T]) = {P}.
Indeed, the right solution here is to note that τ_0_1.[P:T] has a suffix
equal to the key of the property map entry, [P:T]. If we strip off the
suffix, we get τ_0_1. If we then prepend τ_0_1 to the substitution term,
we get the term τ_0_1.[P:U], whose canonical type is τ_0_1.U.
Now, applying the substitution τ_0_0 => τ_0_1.U to Optional<τ_0_0>
produces the desired result, Optional<τ_0_1.U>.
Note that this is the same "prepend a prefix to each substitution of
a concrete type symbol" operation that is performed in checkForOverlap()
and PropertyBag::copyPropertiesFrom(), however we can simplify things
slightly by open-coding it instead of calling the utility method
prependPrefixToConcreteSubstitutions(), since the latter creates a
new symbol, which we don't actually need.
If you have
protocol P {
associatedtype T
}
class C<T> : P {}
Then substituting the type parameter T.T from the generic signature
<T where T : P> into the generic signature <T, U where T : C<U>>
is the identity operation, and also returns T.T, because subst()
isn't smart enough to replace T.T with U.
So getCanonicalTypeInContext() has to do the concrete conformance
lookup here, just like it does for the analogous situation where
you have a concrete type requirement.
This could be solved in a more principled way by better book-keeping
elsewhere, but the GSB supported the old behavior, so we can
simulate it easily enough in the RequirementMachine also.