Skip to content

Commit 0347ba7

Browse files
committed
Sema: Allow protocols to inherit from subclass existentials
This was a regression from 7566f98. Fixes <rdar://problem/50022955>.
1 parent e0f1994 commit 0347ba7

File tree

3 files changed

+46
-23
lines changed

3 files changed

+46
-23
lines changed

lib/Sema/TypeCheckDecl.cpp

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,8 @@ static void checkInheritanceClause(
248248
inheritedClause = typeDecl->getInherited();
249249
}
250250

251+
// Can this declaration's inheritance clause contain a class or
252+
// subclass existential?
251253
bool canHaveSuperclass = (isa<ClassDecl>(decl) ||
252254
(isa<ProtocolDecl>(decl) &&
253255
!cast<ProtocolDecl>(decl)->isObjC()));
@@ -351,34 +353,38 @@ static void checkInheritanceClause(
351353
if (inheritedTy->isExistentialType()) {
352354
auto layout = inheritedTy->getExistentialLayout();
353355

354-
// Inheritance from protocol compositions that do not contain classes
355-
// or AnyObject is always OK.
356-
if (!layout.hasExplicitAnyObject &&
357-
!layout.explicitSuperclass)
356+
// Subclass existentials are not allowed except on classes and
357+
// non-@objc protocols.
358+
if (layout.explicitSuperclass &&
359+
!canHaveSuperclass) {
360+
decl->diagnose(diag::inheritance_from_protocol_with_superclass,
361+
inheritedTy);
358362
continue;
363+
}
359364

360-
// Protocols can inherit from AnyObject.
365+
// AnyObject is not allowed except on protocols.
361366
if (layout.hasExplicitAnyObject &&
362-
isa<ProtocolDecl>(decl))
367+
!isa<ProtocolDecl>(decl)) {
368+
decl->diagnose(canHaveSuperclass
369+
? diag::inheritance_from_non_protocol_or_class
370+
: diag::inheritance_from_non_protocol,
371+
inheritedTy);
363372
continue;
373+
}
364374

365-
// Class-constrained protocol compositions are not allowed except in
366-
// special cases.
367-
if (layout.explicitSuperclass) {
368-
if (!canHaveSuperclass) {
369-
decl->diagnose(diag::inheritance_from_protocol_with_superclass,
370-
inheritedTy);
371-
continue;
372-
}
375+
// If the existential did not have a class constraint, we're done.
376+
if (!layout.explicitSuperclass)
377+
continue;
373378

374-
// Classes can inherit from protocol compositions that contain a
375-
// superclass, but not AnyObject.
376-
if (isa<ClassDecl>(decl) &&
377-
!layout.hasExplicitAnyObject) {
378-
// Superclass inheritance is handled below.
379-
inheritedTy = layout.explicitSuperclass;
380-
}
381-
}
379+
// Classes and protocols can inherit from subclass existentials.
380+
// For classes, we check for a duplicate superclass below.
381+
// For protocols, the GSB emits its own warning instead.
382+
if (isa<ProtocolDecl>(decl))
383+
continue;
384+
385+
assert(isa<ClassDecl>(decl));
386+
assert(canHaveSuperclass);
387+
inheritedTy = layout.explicitSuperclass;
382388
}
383389

384390
// If this is an enum inheritance clause, check for a raw type.
@@ -418,7 +424,9 @@ static void checkInheritanceClause(
418424
continue;
419425
}
420426

421-
// If this is a class type, it may be the superclass.
427+
// If this is a class type, it may be the superclass. We end up here when
428+
// the inherited type is either itself a class, or when it is a subclass
429+
// existential via the existential type path above.
422430
if (inheritedTy->getClassOrBoundGenericClass()) {
423431
// First, check if we already had a superclass.
424432
if (superclassTy) {

test/decl/protocol/protocol_with_superclass.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,3 +340,15 @@ extension Amb { // expected-error {{'Amb' is ambiguous for type lookup in this c
340340
_ = ConcreteAlias.self
341341
}
342342
}
343+
344+
protocol ProtoRefinesClassComposition : Generic<Int> & BaseProto {}
345+
346+
func usesProtoRefinesClass1(_ t: ProtoRefinesClassComposition) {
347+
t.genericMethod((1, 2))
348+
let _: BaseProto = t
349+
}
350+
351+
func usesProtoRefinesClass2<T : ProtoRefinesClassComposition>(_ t: T) {
352+
t.genericMethod((1, 2))
353+
let _: BaseProto = t
354+
}

test/decl/protocol/protocol_with_superclass_objc.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,6 @@ typealias Composition = OtherProtocol & Base
1111

1212
@objc protocol Protocol2 : Composition {}
1313
// expected-error@-1 {{inheritance from class-constrained protocol composition type 'Composition' (aka 'Base & OtherProtocol')}}
14+
15+
@objc protocol Protocol3 : OtherProtocol & Base {}
16+
// expected-error@-1 {{inheritance from class-constrained protocol composition type 'Base & OtherProtocol'}}

0 commit comments

Comments
 (0)