Skip to content

Commit ab6db4f

Browse files
committed
ProtocolCompositionType: Don't build compositions with a single member and no layout constraint
1 parent f64135a commit ab6db4f

File tree

3 files changed

+18
-7
lines changed

3 files changed

+18
-7
lines changed

lib/AST/ASTContext.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3210,6 +3210,8 @@ ClassType *ClassType::get(ClassDecl *D, Type Parent, const ASTContext &C) {
32103210
ProtocolCompositionType *
32113211
ProtocolCompositionType::build(const ASTContext &C, ArrayRef<Type> Members,
32123212
bool HasExplicitAnyObject) {
3213+
assert(Members.size() != 1 || HasExplicitAnyObject);
3214+
32133215
// Check to see if we've already seen this protocol composition before.
32143216
void *InsertPos = nullptr;
32153217
llvm::FoldingSetNodeID ID;

lib/AST/Type.cpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3712,6 +3712,16 @@ bool ProtocolCompositionType::requiresClass() {
37123712
Type ProtocolCompositionType::get(const ASTContext &C,
37133713
ArrayRef<Type> Members,
37143714
bool HasExplicitAnyObject) {
3715+
// Fast path for 'AnyObject' and 'Any'.
3716+
if (Members.empty()) {
3717+
return build(C, Members, HasExplicitAnyObject);
3718+
}
3719+
3720+
// If there's a single member and no layout constraint, return that type.
3721+
if (Members.size() == 1 && !HasExplicitAnyObject) {
3722+
return Members.front();
3723+
}
3724+
37153725
for (Type t : Members) {
37163726
if (!t->isCanonical())
37173727
return build(C, Members, HasExplicitAnyObject);
@@ -3730,11 +3740,6 @@ Type ProtocolCompositionType::get(const ASTContext &C,
37303740
if (Superclass)
37313741
HasExplicitAnyObject = false;
37323742

3733-
// If one protocol remains with no further constraints, its nominal
3734-
// type is the canonical type.
3735-
if (Protocols.size() == 1 && !Superclass && !HasExplicitAnyObject)
3736-
return Protocols.front()->getDeclaredInterfaceType();
3737-
37383743
// Form the set of canonical protocol types from the protocol
37393744
// declarations, and use that to build the canonical composition type.
37403745
SmallVector<Type, 4> CanTypes;
@@ -3744,6 +3749,10 @@ Type ProtocolCompositionType::get(const ASTContext &C,
37443749
Protocols, std::back_inserter(CanTypes),
37453750
[](ProtocolDecl *Proto) { return Proto->getDeclaredInterfaceType(); });
37463751

3752+
// If one member remains and no layout constraint, return that type.
3753+
if (CanTypes.size() == 1 && !HasExplicitAnyObject)
3754+
return CanTypes.front();
3755+
37473756
// TODO: Canonicalize away HasExplicitAnyObject if it is implied
37483757
// by one of our member protocols.
37493758
return build(C, CanTypes, HasExplicitAnyObject);

test/Constraints/generics.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -358,8 +358,8 @@ func testFixItClassBound() {
358358
let y1: String = y // expected-error {{cannot convert value of type 'ClassBound2<X>' to specified type 'String'}}
359359

360360
// ...but not in types.
361-
let z1: ClassBound // expected-error {{reference to generic type 'ClassBound' requires arguments in <...>}} {{21-21=<X>}}
362-
let z2: ClassBound2 // expected-error {{reference to generic type 'ClassBound2' requires arguments in <...>}} {{22-22=<X>}}
361+
let z1: ClassBound // expected-error {{reference to generic type 'ClassBound' requires arguments in <...>}} {{21-21=<<#Foo: X#>>}}
362+
let z2: ClassBound2 // expected-error {{reference to generic type 'ClassBound2' requires arguments in <...>}} {{22-22=<<#Foo: X#>>}}
363363
}
364364

365365
func testFixItCasting(x: Any) {

0 commit comments

Comments
 (0)