AST: Fix TypeBase::hasSimpleTypeRepr() for ProtocolCompositionType

Prior to the introduction of noncopyable generics, a ProtocolCompositionType
was 'simple' if it was exactly 'Any' or 'AnyObject'. Now, there is a new
simple case, where we have a single inverse requirement '~Copyable' or
'~Escapable', and the old logic was never updated to account for this
possibility. Instead, it would ignore inverses, so it would claim that
a composition like `P & ~Copyable` was simple when it shouldn't be.

Fixes rdar://139465298.
This commit is contained in:
Slava Pestov
2025-02-26 16:54:50 -05:00
parent 874c62513c
commit c4e804a7d1
2 changed files with 38 additions and 2 deletions

View File

@@ -4561,11 +4561,28 @@ bool TypeBase::hasSimpleTypeRepr() const {
}
case TypeKind::ProtocolComposition: {
// 'Any', 'AnyObject' and single protocol compositions are simple
auto composition = cast<const ProtocolCompositionType>(this);
// A protocol composition is simple if its syntactic representation does not
// involve `&`. This is true if we have 'Any', 'AnyObject', or a single
// inverse requirement like `~Copyable`.
// All other protocol compositions contain at least two `&`-separated terms.
// Add each logical member Foo.
auto memberCount = composition->getMembers().size();
// And each inverse requirement ~Foo.
for (auto ip : composition->getInverses()) {
(void) ip;
++memberCount;
}
// And finally, AnyObject.
if (composition->hasExplicitAnyObject())
return memberCount == 0;
++memberCount;
// Almost always, this will be > 1.
return memberCount <= 1;
}

View File

@@ -46,3 +46,22 @@ public protocol ProtocolTypealias {
// CHECK: public func dependentExistential<T>(value: (T) -> any main.P) where T : main.ProtocolTypealias
public func dependentExistential<T: ProtocolTypealias>(value: (T) -> T.A) {}
public protocol Yescopyable {}
public protocol Noncopyable: ~Copyable {}
// CHECK: public func existentialMetatype1(_: any (main.Noncopyable & ~Copyable).Type)
// CHECK: public func existentialMetatype2(_: any (main.Noncopyable & main.Yescopyable).Type)
// CHECK: public func existentialMetatype3(_: any ~Copyable.Type)
public func existentialMetatype1(_: any (Noncopyable & ~Copyable).Type) {}
public func existentialMetatype2(_: any (Yescopyable & Noncopyable).Type) {}
public func existentialMetatype3(_: any ~Copyable.Type) {}
// CHECK: public func metatypeExistential1(_: (any main.Noncopyable & ~Copyable).Type)
// CHECK: public func metatypeExistential2(_: (any main.Noncopyable & main.Yescopyable).Type)
// CHECK: public func metatypeExistential3(_: (any ~Copyable).Type)
public func metatypeExistential1(_: (any Noncopyable & ~Copyable).Type) {}
public func metatypeExistential2(_: (any Yescopyable & Noncopyable).Type) {}
public func metatypeExistential3(_: (any ~Copyable).Type) {}