Skip to content

Commit 3c51681

Browse files
committed
[NCGenerics] fix AnyObject and inverses
resolves rdar://120512544
1 parent 2fbb683 commit 3c51681

File tree

8 files changed

+78
-5
lines changed

8 files changed

+78
-5
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7583,6 +7583,10 @@ WARNING(redundant_inverse_constraint,none,
75837583
ERROR(inverse_on_class, none,
75847584
"classes cannot be '~%0'",
75857585
(StringRef))
7586+
ERROR(inverse_with_class_constraint, none,
7587+
"composition involving %select{class requirement %2|'AnyObject'}0 "
7588+
"cannot contain '~%1'",
7589+
(bool, StringRef, Type))
75867590
ERROR(inverse_extension, none,
75877591
"cannot apply inverse %0 to extension",
75887592
(Type))

lib/AST/ASTPrinter.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1472,8 +1472,8 @@ static void reconstituteInverses(GenericSignature genericSig,
14721472
for (auto tp : typeParams) {
14731473
assert(tp);
14741474

1475-
// Any generic parameter requiring a class could not have an inverse.
1476-
if (genericSig->requiresClass(tp))
1475+
// Any generic parameter with a superclass bound could not have an inverse.
1476+
if (genericSig->getSuperclassBound(tp))
14771477
continue;
14781478

14791479
auto defaults = InverseRequirement::expandDefault(tp);

lib/AST/RequirementMachine/Diagnostics.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -564,11 +564,17 @@ void RequirementMachine::computeRequirementDiagnostics(
564564
getGenericParams());
565565

566566
// Check that the generic parameters with inverses truly lack the conformance.
567-
for (auto const& inverse : inverses)
568-
if (requiresProtocol(inverse.subject, inverse.protocol))
567+
for (auto const& inverse : inverses) {
568+
// The Superclass and AnyObject checks here are based on the assumption that
569+
// a class cannot have an inverse applied to it, thus those requirements are
570+
// implied by a superclass and/or AnyObject constraint.
571+
if (requiresProtocol(inverse.subject, inverse.protocol) ||
572+
getSuperclassBound(inverse.subject, getGenericParams()) ||
573+
requiresClass(inverse.subject))
569574
errors.push_back(
570575
RequirementError::forConflictingInverseRequirement(inverse,
571576
inverse.loc));
577+
}
572578
}
573579

574580
std::string RequirementMachine::getRuleAsStringForDiagnostics(

lib/Sema/TypeCheckType.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4985,6 +4985,7 @@ TypeResolver::resolveCompositionType(CompositionTypeRepr *repr,
49854985
Type SuperclassType;
49864986
SmallVector<Type, 4> Members;
49874987
InvertibleProtocolSet Inverses;
4988+
bool HasAnyObject = false;
49884989

49894990
// Whether we saw at least one protocol. A protocol composition
49904991
// must either be empty (in which case it is Any or AnyObject),
@@ -5042,6 +5043,8 @@ TypeResolver::resolveCompositionType(CompositionTypeRepr *repr,
50425043
continue;
50435044
if (!layout.getProtocols().empty())
50445045
HasProtocol = true;
5046+
if (layout.hasExplicitAnyObject)
5047+
HasAnyObject = true;
50455048

50465049
Inverses.insertAll(pct->getInverses());
50475050
Members.push_back(ty);
@@ -5056,6 +5059,17 @@ TypeResolver::resolveCompositionType(CompositionTypeRepr *repr,
50565059
IsInvalid = true;
50575060
}
50585061

5062+
// Cannot combine inverses with Superclass or AnyObject in a composition.
5063+
if ((SuperclassType || HasAnyObject) && !Inverses.empty()) {
5064+
diagnose(repr->getStartLoc(),
5065+
diag::inverse_with_class_constraint,
5066+
HasAnyObject,
5067+
getProtocolName(getKnownProtocolKind(*Inverses.begin())),
5068+
SuperclassType);
5069+
IsInvalid = true;
5070+
}
5071+
5072+
50595073
if (IsInvalid) {
50605074
repr->setInvalid();
50615075
return ErrorType::get(getASTContext());

test/Generics/inverse_generics.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,3 +358,35 @@ func conflict15<T, C, E>(_ t: T, _ c: C, _ e: borrowing E)
358358
C: ~Escapable, // expected-error {{'C' required to be 'Escapable' but is marked with '~Escapable'}}
359359
C == T.HasE
360360
{}
361+
362+
363+
// Class bounds and AnyObject
364+
365+
class Soup {}
366+
func checkClassBound1<T>(_ t: T) where T: ~Copyable, T: Soup {}
367+
// expected-error@-1 {{'T' required to be 'Copyable' but is marked with '~Copyable'}}
368+
369+
// expected-note@+2 3{{add}}
370+
// expected-error@+1 {{parameter of noncopyable type 'T' must specify ownership}}
371+
func checkClassBound2<T>(_ t: T) where T: ~Escapable, T: AnyObject, T: ~Copyable {}
372+
// expected-error@-1 {{'T' required to be 'Escapable' but is marked with '~Escapable'}}
373+
// expected-error@-2 {{'T' required to be 'Copyable' but is marked with '~Copyable'}}
374+
375+
func checkClassBound3<T>(_ t: T) where T: Soup & ~Copyable & ~Escapable {}
376+
// expected-error@-1 {{composition involving class requirement 'Soup' cannot contain '~Copyable'}}
377+
378+
public func checkAnyObjInv1<Result: AnyObject>(_ t: borrowing Result) where Result: ~Copyable {}
379+
// expected-error@-1 {{'Result' required to be 'Copyable' but is marked with '~Copyable'}}
380+
381+
public func checkAnyObjInv2<Result: AnyObject>(_ t: borrowing Result) where Result: ~Escapable {}
382+
// expected-error@-1 {{'Result' required to be 'Escapable' but is marked with '~Escapable'}}
383+
384+
public func checkAnyObject<Result>(_ t: Result) where Result: AnyObject {
385+
checkCopyable(t)
386+
}
387+
388+
func checkExistentialAndClasses(
389+
_ a: any AnyObject & ~Copyable, // expected-error {{composition involving 'AnyObject' cannot contain '~Copyable'}}
390+
_ b: any Soup & Copyable & ~Escapable & ~Copyable, // expected-error {{composition involving class requirement 'Soup' cannot contain '~Copyable'}}
391+
_ c: some (~Escapable & Removed) & Soup // expected-error {{composition involving class requirement 'Soup' cannot contain '~Escapable'}}
392+
) {}

test/Generics/inverse_signatures.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,15 @@ func withSomeProto(_ t: some NoCopyP) {}
7070
// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : Escapable>
7171
func withInverseSome(_ t: borrowing some ~Copyable) {}
7272

73+
// CHECK-LABEL: .checkAnyObject@
74+
// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : AnyObject, τ_0_0 : Copyable, τ_0_0 : Escapable>
75+
func checkAnyObject<Result>(_ t: Result) where Result: AnyObject {}
76+
77+
// CHECK-LABEL: .checkSoup@
78+
// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : Soup>
79+
class Soup {}
80+
func checkSoup<T>(_ t: T) where T: Soup {}
81+
7382
// CHECK-LABEL: .S1@
7483
// CHECK: Generic signature: <T where T : Copyable, T : Escapable>
7584
struct S1<T> {}

test/ModuleInterface/Inputs/NoncopyableGenerics_Misc.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,5 +74,9 @@ public class C {}
7474
public func noInversesSTART() {}
7575
public func checkAny<Result>(_ t: Result) where Result: Any {}
7676
public func usingClassConstraint<Result>(arg: Result) -> Result? where Result: C { return arg }
77-
public func checkAnyObject<Result>(_ t: Result) where Result: AnyObject {}
77+
public func withAnyObject<Result>(_ t: Result) where Result: AnyObject {}
7878
public func noInversesEND() {}
79+
80+
public func checkAnyInv1<Result>(_ t: borrowing Result) where Result: Any & ~Copyable {}
81+
public func checkAnyInv2<Result: Any>(_ t: borrowing Result) where Result: ~Copyable & ~Escapable {}
82+
public func checkAnyObject<Result>(_ t: Result) where Result: AnyObject {}

test/ModuleInterface/noncopyable_generics.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ import NoncopyableGenerics_Misc
100100
// CHECK-MISC-NOT: ~
101101
// CHECK-MISC: noInversesEND
102102

103+
// CHECK-MISC: public func checkAnyInv1<Result>(_ t: borrowing Result) where Result : ~Copyable
104+
// CHECK-MISC: public func checkAnyInv2<Result>(_ t: borrowing Result) where Result : ~Copyable, Result : ~Escapable
105+
// CHECK-MISC: public func checkAnyObject<Result>(_ t: Result) where Result : AnyObject
106+
103107
///////////////////////////////////////////////////////////////////////
104108
// Synthesized conditional conformances are next
105109

0 commit comments

Comments
 (0)