Skip to content

Commit 7cee7e9

Browse files
authored
Merge pull request #72164 from slavapestov/ncgenerics-fixes-10
Non-copyable generics fixes, part 10
2 parents 27702fa + 3a4d831 commit 7cee7e9

9 files changed

+82
-53
lines changed

Diff for: include/swift/AST/DiagnosticsSema.def

+4-5
Original file line numberDiff line numberDiff line change
@@ -2496,7 +2496,7 @@ ERROR(inferred_opaque_type,none,
24962496

24972497
// Inverse Constraints
24982498
ERROR(inverse_type_not_invertible,none,
2499-
"type %0 is not invertible", (Type))
2499+
"type %0 cannot be suppressed", (Type))
25002500

25012501
// Extensions
25022502
ERROR(non_nominal_extension,none,
@@ -3168,12 +3168,11 @@ ERROR(requires_not_suitable_archetype,none,
31683168
(Type))
31693169

31703170
ERROR(requires_not_suitable_inverse_subject,none,
3171-
"cannot apply inverse '~%1' to type %0 in conformance requirement",
3171+
"cannot suppress '~%1' on type %0",
31723172
(Type, StringRef))
31733173

31743174
ERROR(requires_not_suitable_inverse_outer_subject,none,
3175-
"cannot add inverse constraint '%0: ~%1' "
3176-
"on generic parameter '%0' defined in outer scope",
3175+
"cannot suppress '~%1' on generic parameter '%0' defined in outer scope",
31773176
(StringRef, StringRef))
31783177

31793178
ERROR(invalid_shape_requirement,none,
@@ -7613,7 +7612,7 @@ ERROR(inverse_conflicts_explicit_composition, none,
76137612
"composition cannot contain '~%0' when another member requires '%0'",
76147613
(StringRef))
76157614
ERROR(inverse_extension, none,
7616-
"cannot apply inverse %0 to extension",
7615+
"cannot suppress %0 in extension",
76177616
(Type))
76187617
ERROR(copyable_illegal_deinit, none,
76197618
"deinitializer cannot be declared in %kind0 that conforms to 'Copyable'",

Diff for: lib/AST/NameLookup.cpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -3060,9 +3060,10 @@ directReferencesForTypeRepr(Evaluator &evaluator,
30603060
inverseRepr->getConstraint(), dc,
30613061
allowUsableFromInline);
30623062
if (innerResult.first.size() == 1) {
3063-
auto *proto = dyn_cast<ProtocolDecl>(innerResult.first[0]);
3064-
if (auto ip = proto->getInvertibleProtocolKind()) {
3065-
result.second.insert(*ip);
3063+
if (auto *proto = dyn_cast<ProtocolDecl>(innerResult.first[0])) {
3064+
if (auto ip = proto->getInvertibleProtocolKind()) {
3065+
result.second.insert(*ip);
3066+
}
30663067
}
30673068
}
30683069

Diff for: lib/Sema/TypeCheckDeclPrimary.cpp

+5-10
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141
#include "swift/AST/ForeignErrorConvention.h"
4242
#include "swift/AST/GenericEnvironment.h"
4343
#include "swift/AST/Initializer.h"
44-
#include "swift/AST/InverseMarking.h"
4544
#include "swift/AST/MacroDefinition.h"
4645
#include "swift/AST/NameLookup.h"
4746
#include "swift/AST/NameLookupRequests.h"
@@ -3224,21 +3223,17 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
32243223
static void diagnoseInverseOnClass(ClassDecl *decl) {
32253224
auto &ctx = decl->getASTContext();
32263225

3227-
for (auto ip : InvertibleProtocolSet::full()) {
3228-
auto inverseMarking = decl->hasInverseMarking(ip);
3229-
3230-
// Inferred inverses are already ignored for classes.
3231-
// FIXME: we can also diagnose @_moveOnly here if we use `isAnyExplicit`
3232-
if (!inverseMarking.is(InverseMarking::Kind::Explicit))
3233-
continue;
3226+
InvertibleProtocolSet inverses;
3227+
bool anyObject = false;
3228+
(void) getDirectlyInheritedNominalTypeDecls(decl, inverses, anyObject);
32343229

3230+
for (auto ip : inverses) {
32353231
// Allow ~Copyable when MoveOnlyClasses is enabled
32363232
if (ip == InvertibleProtocolKind::Copyable
32373233
&& ctx.LangOpts.hasFeature(Feature::MoveOnlyClasses))
32383234
continue;
32393235

3240-
3241-
ctx.Diags.diagnose(inverseMarking.getLoc(),
3236+
ctx.Diags.diagnose(decl->getLoc(),
32423237
diag::inverse_on_class,
32433238
getProtocolName(getKnownProtocolKind(ip)));
32443239
}

Diff for: lib/Sema/TypeCheckProtocol.cpp

+9-1
Original file line numberDiff line numberDiff line change
@@ -2418,8 +2418,16 @@ checkIndividualConformance(NormalProtocolConformance *conformance) {
24182418
implyingConf = implyingConf->getImplyingConformance();
24192419
}
24202420

2421+
// If the conditional requirements all have the form `T : Copyable`, then
2422+
// we accept the implied conformance with the same conditional requirements.
24212423
auto implyingCondReqs = implyingConf->getConditionalRequirements();
2422-
if (!implyingCondReqs.empty()) {
2424+
bool allCondReqsInvertible = llvm::all_of(implyingCondReqs,
2425+
[&](Requirement req) {
2426+
return (req.getKind() == RequirementKind::Conformance &&
2427+
req.getProtocolDecl()->getInvertibleProtocolKind());
2428+
});
2429+
2430+
if (!allCondReqsInvertible) {
24232431
// FIXME:
24242432
// We shouldn't suggest including witnesses for the conformance, because
24252433
// those suggestions will go in the current DeclContext, but really they

Diff for: test/Generics/inverse_extensions.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ protocol HasAssoc {
1515
associatedtype A
1616
}
1717
extension HasAssoc where Self.A: ~Copyable {}
18-
// expected-error@-1 {{cannot add inverse constraint 'Self.A: ~Copyable' on generic parameter 'Self.A' defined in outer scope}}
18+
// expected-error@-1 {{cannot suppress '~Copyable' on generic parameter 'Self.A' defined in outer scope}}
1919
// expected-error@-2 {{'Self.A' required to be 'Copyable' but is marked with '~Copyable'}}
2020

2121
class Box<T: ~Copyable> {}

Diff for: test/Generics/inverse_generics.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -171,11 +171,11 @@ class NiceTry: ~Copyable, Copyable {} // expected-error {{classes cannot be '~Co
171171

172172

173173
struct Extendo: ~Copyable {}
174-
extension Extendo: Copyable, ~Copyable {} // expected-error {{cannot apply inverse '~Copyable' to extension}}
174+
extension Extendo: Copyable, ~Copyable {} // expected-error {{cannot suppress '~Copyable' in extension}}
175175
// expected-error@-1 {{struct 'Extendo' required to be 'Copyable' but is marked with '~Copyable'}}
176176

177177
enum EnumExtendo {}
178-
extension EnumExtendo: ~Copyable {} // expected-error {{cannot apply inverse '~Copyable' to extension}}
178+
extension EnumExtendo: ~Copyable {} // expected-error {{cannot suppress '~Copyable' in extension}}
179179

180180
extension NeedsCopyable where Self: ~Copyable {}
181181
// expected-error@-1 {{'Self' required to be 'Copyable' but is marked with '~Copyable'}}

Diff for: test/Generics/inverse_scoping.swift

+10-10
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,16 @@
55
protocol NoCopyReq: ~Copyable {}
66

77
protocol P {
8-
func f() where Self: ~Copyable // expected-error {{cannot add inverse constraint 'Self: ~Copyable' on generic parameter 'Self' defined in outer scope}}
8+
func f() where Self: ~Copyable // expected-error {{cannot suppress '~Copyable' on generic parameter 'Self' defined in outer scope}}
99

10-
func g<T>(_: T) where Self: ~Copyable // expected-error {{cannot add inverse constraint 'Self: ~Copyable' on generic parameter 'Self' defined in outer scope}}
10+
func g<T>(_: T) where Self: ~Copyable // expected-error {{cannot suppress '~Copyable' on generic parameter 'Self' defined in outer scope}}
1111

1212
associatedtype AT where Self: ~Copyable // expected-error {{constraint with subject type of 'Self' is not supported; consider adding requirement to protocol inheritance clause instead}}
1313

14-
// expected-error@+1 {{cannot add inverse constraint 'Self.Alice: ~Copyable' on generic parameter 'Self.Alice' defined in outer scope}}
14+
// expected-error@+1 {{cannot suppress '~Copyable' on generic parameter 'Self.Alice' defined in outer scope}}
1515
associatedtype Bob where Alice: NoCopyReq & ~Copyable
1616
associatedtype Alice where Bob: ~Copyable
17-
// expected-error@-1 {{cannot add inverse constraint 'Self.Bob: ~Copyable' on generic parameter 'Self.Bob' defined in outer scope}}
17+
// expected-error@-1 {{cannot suppress '~Copyable' on generic parameter 'Self.Bob' defined in outer scope}}
1818
}
1919

2020
protocol U {}
@@ -23,13 +23,13 @@ extension U where Self: ~Copyable {}
2323
// expected-error@-1 {{'Self' required to be 'Copyable' but is marked with '~Copyable'}}
2424

2525
extension P where Self: ~Copyable {
26-
func g() where Self: ~Copyable, // expected-error {{cannot add inverse constraint 'Self: ~Copyable' on generic parameter 'Self' defined in outer scope}}
26+
func g() where Self: ~Copyable, // expected-error {{cannot suppress '~Copyable' on generic parameter 'Self' defined in outer scope}}
2727
// FIXME: why no similar 2nd error as Escapable here on Self?
2828

29-
Self: ~Escapable {} // expected-error {{cannot add inverse constraint 'Self: ~Escapable' on generic parameter 'Self' defined in outer scope}}
29+
Self: ~Escapable {} // expected-error {{cannot suppress '~Escapable' on generic parameter 'Self' defined in outer scope}}
3030
// expected-error@-1 {{'Self' required to be 'Escapable' but is marked with '~Escapable'}}
3131

32-
typealias Me = Self where Self: ~Copyable // expected-error {{cannot add inverse constraint 'Self: ~Copyable' on generic parameter 'Self' defined in outer scope}}
32+
typealias Me = Self where Self: ~Copyable // expected-error {{cannot suppress '~Copyable' on generic parameter 'Self' defined in outer scope}}
3333

3434
typealias MeAndU = Self where Self: U
3535
}
@@ -39,15 +39,15 @@ struct S<T> {
3939
// expected-note@+2 3{{add}}
4040
// expected-error@+1 {{parameter of noncopyable type 'U' must specify ownership}}
4141
func fn<U>(_ u: U)
42-
where T: ~Copyable, // expected-error {{cannot add inverse constraint 'T: ~Copyable' on generic parameter 'T' defined in outer scope}}
42+
where T: ~Copyable, // expected-error {{cannot suppress '~Copyable' on generic parameter 'T' defined in outer scope}}
4343
// expected-error@-1 {{'T' required to be 'Copyable' but is marked with '~Copyable'}}
4444
U: ~Copyable
4545
{}
4646

4747
func onlyCopyable() where T: Copyable {}
4848

4949
func fn<U>(_ u: U)
50-
where T: ~Escapable, // expected-error {{cannot add inverse constraint 'T: ~Escapable' on generic parameter 'T' defined in outer scope}}
50+
where T: ~Escapable, // expected-error {{cannot suppress '~Escapable' on generic parameter 'T' defined in outer scope}}
5151
// expected-error@-1 {{'T' required to be 'Escapable' but is marked with '~Escapable'}}
5252
U: ~Escapable
5353
{}
@@ -57,5 +57,5 @@ extension S where T: NoCopyReq & ~Copyable {}
5757
// expected-error@-1 {{'T' required to be 'Copyable' but is marked with '~Copyable'}}
5858

5959
struct ExtraInverse<T: ~Copyable> {
60-
func check() where T: ~Copyable {} // expected-error {{cannot add inverse constraint 'T: ~Copyable' on generic parameter 'T' defined in outer scope}}
60+
func check() where T: ~Copyable {} // expected-error {{cannot suppress '~Copyable' on generic parameter 'T' defined in outer scope}}
6161
}

Diff for: test/Parse/inverses.swift

+25-21
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,18 @@ enum Maybe<Thing: ~Copyable> : ~Copyable {}
77
func more() {
88
let _: any ~Copyable = 19
99

10-
let _: any ~Equatable = 19 // expected-error@:14 {{type 'Equatable' is not invertible}}
10+
let _: any ~Equatable = 19 // expected-error@:14 {{type 'Equatable' cannot be suppressed}}
1111

12-
let _: any (~Copyable & ~Equatable) // expected-error{{type 'Equatable' is not invertible}}
12+
let _: any (~Copyable & ~Equatable) // expected-error{{type 'Equatable' cannot be suppressed}}
1313

14-
let _: ~Any // expected-error {{type 'Any' is not invertible}}
15-
let _: ~AnyObject // expected-error {{type 'AnyObject' is not invertible}}
14+
let _: ~Any // expected-error {{type 'Any' cannot be suppressed}}
15+
let _: ~AnyObject // expected-error {{type 'AnyObject' cannot be suppressed}}
1616
}
1717

18-
struct S4: ~(Copyable & Equatable) {} // expected-error {{type 'Equatable' is not invertible}}
18+
struct S4: ~(Copyable & Equatable) {} // expected-error {{type 'Equatable' cannot be suppressed}}
1919

2020
func blah<T>(_ t: borrowing T) where T: ~Copyable,
21-
T: ~Hashable {} // expected-error@:41 {{type 'Hashable' is not invertible}}
21+
T: ~Hashable {} // expected-error@:41 {{type 'Hashable' cannot be suppressed}}
2222

2323
func foo<T: ~Copyable>(x: borrowing T) {}
2424

@@ -35,13 +35,13 @@ protocol Foo: ~Copyable
3535
associatedtype Touch : ~Copyable,
3636
~Copyable
3737

38-
func test<T>(_ t: T) where T: ~Self // expected-error {{type 'Self' is not invertible}}
38+
func test<T>(_ t: T) where T: ~Self // expected-error {{type 'Self' cannot be suppressed}}
3939
}
4040

4141
protocol Sando { func make() }
4242

4343
class C: ~Copyable, // expected-error {{classes cannot be '~Copyable'}}
44-
~Sando // expected-error {{type 'Sando' is not invertible}}
44+
~Sando // expected-error {{type 'Sando' cannot be suppressed}}
4545
{}
4646

4747
public struct MoveOnlyS1<T> : ~Copyable { /*deinit {}*/ }
@@ -52,12 +52,12 @@ protocol Rope<Element>: Hashable, ~Copyable { // expected-error {{'Self' requir
5252
associatedtype Element: ~Copyable
5353
}
5454

55-
extension S: ~Copyable {} // expected-error {{cannot apply inverse '~Copyable' to extension}}
55+
extension S: ~Copyable {} // expected-error {{cannot suppress '~Copyable' in extension}}
5656

57-
struct S: ~U, // expected-error {{type 'U' is not invertible}}
57+
struct S: ~U, // expected-error {{type 'U' cannot be suppressed}}
5858
~Copyable {}
5959

60-
func greenBay<each T: ~Copyable>(_ r: repeat each T) {} // expected-error{{cannot apply inverse '~Copyable' to type 'each T' in conformance requirement}}
60+
func greenBay<each T: ~Copyable>(_ r: repeat each T) {} // expected-error{{cannot suppress '~Copyable' on type 'each T'}}
6161

6262
typealias Clone = Copyable
6363
func dup<D: ~Clone>(_ d: D) {}
@@ -73,28 +73,32 @@ func superb(_ thing: some ~Copyable, thing2: some ~Clone) {}
7373
// expected-note@-2 2{{add 'inout'}}
7474
// expected-note@-3 2{{add 'consuming'}}
7575

76-
func ownership1(_ t: borrowing any ~Equatable) {} // expected-error {{type 'Equatable' is not invertible}}
76+
func ownership1(_ t: borrowing any ~Equatable) {} // expected-error {{type 'Equatable' cannot be suppressed}}
7777

7878
func ownership2(_ t: ~ borrowing Int) {} // expected-error {{cannot find type 'borrowing' in scope}}
7979
// expected-error@-1 {{unnamed parameters must be written with the empty name '_'}}
8080
// expected-error@-2 {{expected ',' separator}}
8181

8282
func ownership3(_ t: consuming some ~Clone) {}
8383

84-
func what(one: ~Copyable..., // expected-error {{type 'any Copyable' is not invertible}}
84+
func what(one: ~Copyable..., // expected-error {{type 'any Copyable' cannot be suppressed}}
8585
two: ~(Copyable...) // expected-error {{variadic parameter cannot appear outside of a function parameter list}}
86-
// expected-error@-1 {{type 'any Copyable' is not invertible}}
86+
// expected-error@-1 {{type 'any Copyable' cannot be suppressed}}
8787
) {}
8888

8989
struct A { struct B { struct C {} } }
9090

9191
typealias Z1 = (~Copyable).Type // FIXME: should be an error
92-
typealias Z1 = ~Copyable.Type // expected-error {{type 'any Copyable.Type' is not invertible}}
93-
typealias Z2 = ~A.B.C // expected-error {{type 'A.B.C' is not invertible}}
94-
typealias Z3 = ~A? // expected-error {{type 'A?' is not invertible}}
95-
typealias Z4 = ~Rope<Int> // expected-error {{type 'Rope<Int>' is not invertible}}
96-
typealias Z5 = (~Int) -> Void // expected-error {{type 'Int' is not invertible}}
92+
typealias Z1 = ~Copyable.Type // expected-error {{type 'any Copyable.Type' cannot be suppressed}}
93+
typealias Z2 = ~A.B.C // expected-error {{type 'A.B.C' cannot be suppressed}}
94+
typealias Z3 = ~A? // expected-error {{type 'A?' cannot be suppressed}}
95+
typealias Z4 = ~Rope<Int> // expected-error {{type 'Rope<Int>' cannot be suppressed}}
96+
typealias Z5 = (~Int) -> Void // expected-error {{type 'Int' cannot be suppressed}}
9797
typealias Z6 = ~() -> () // expected-error {{single argument function types require parentheses}}
98-
// expected-error@-1 {{type '()' is not invertible}}
99-
typealias Z7 = ~(Copyable & Hashable) // expected-error {{type 'Hashable' is not invertible}}
98+
// expected-error@-1 {{type '()' cannot be suppressed}}
99+
typealias Z7 = ~(Copyable & Hashable) // expected-error {{type 'Hashable' cannot be suppressed}}
100100
typealias Z8 = ~Copyable & Hashable // expected-error {{composition cannot contain '~Copyable' when another member requires 'Copyable'}}
101+
102+
struct NotAProtocol {}
103+
104+
struct Bad: ~NotAProtocol {} // expected-error {{type 'NotAProtocol' cannot be suppressed}}

Diff for: test/Sema/conditionally_copyable.swift

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %target-typecheck-verify-swift -enable-experimental-feature NoncopyableGenerics
2+
3+
struct G<T: ~Copyable>: ~Copyable {}
4+
5+
extension G: Copyable {}
6+
7+
protocol Base {}
8+
protocol Derived: Base {}
9+
10+
// Normally we would require the conditional conformance 'G: Base' to be
11+
// explicitly declared, but that would break source compatibility if G
12+
// used to be unconditionally Copyable.
13+
14+
extension G: Derived {} // expected-note {{requirement from conditional conformance of 'G<NotCopyable>' to 'Base'}}
15+
16+
struct NotCopyable: ~Copyable {}
17+
struct IsCopyable {}
18+
19+
func f<T: Base>(_: T.Type) {}
20+
21+
f(G<NotCopyable>.self) // expected-error {{global function 'f' requires that 'NotCopyable' conform to 'Copyable'}}
22+
f(G<IsCopyable>.self) // accepted

0 commit comments

Comments
 (0)