Skip to content

Commit 512a159

Browse files
committed
Sema: Fix handling of inverse requirements in checkProtocolRefinementRequirements()
1 parent bd06653 commit 512a159

File tree

4 files changed

+36
-38
lines changed

4 files changed

+36
-38
lines changed

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2047,36 +2047,41 @@ static void diagnoseWrittenPlaceholderTypes(ASTContext &Ctx,
20472047
/// want 'Other' to appear in the inheritance clause of 'Bar', so that
20482048
/// name lookup on Bar can find members of Other.
20492049
static void checkProtocolRefinementRequirements(ProtocolDecl *proto) {
2050-
auto requiredProtos = proto->getGenericSignature()->getRequiredProtocols(
2051-
proto->getSelfInterfaceType());
2050+
auto &ctx = proto->getASTContext();
2051+
auto selfTy = proto->getSelfInterfaceType();
2052+
auto genericSig = proto->getGenericSignature();
2053+
20522054
const bool EnabledNoncopyableGenerics =
2053-
proto->getASTContext().LangOpts.hasFeature(Feature::NoncopyableGenerics);
2055+
ctx.LangOpts.hasFeature(Feature::NoncopyableGenerics);
2056+
2057+
// If we make a ~P marking but our protocol Self type still conforms to P,
2058+
// diagnose an error.
2059+
//
2060+
// FIXME: This duplicates logic from computeRequirementDiagnostics().
2061+
if (EnabledNoncopyableGenerics) {
2062+
// Get the list of written inverses.
2063+
InvertibleProtocolSet inverses;
2064+
bool anyObject = false;
2065+
(void) getDirectlyInheritedNominalTypeDecls(proto, inverses, anyObject);
2066+
2067+
for (auto ip : inverses) {
2068+
auto kp = getKnownProtocolKind(ip);
2069+
auto *otherProto = ctx.getProtocol(kp);
2070+
if (!genericSig->requiresProtocol(selfTy, otherProto))
2071+
continue;
2072+
2073+
ctx.Diags.diagnose(proto,
2074+
diag::inverse_generic_but_also_conforms,
2075+
selfTy, getProtocolName(kp));
2076+
}
2077+
}
20542078

2079+
auto requiredProtos = genericSig->getRequiredProtocols(selfTy);
20552080
for (auto *otherProto : requiredProtos) {
20562081
// Every protocol 'P' has an implied requirement 'Self : P'; skip it.
20572082
if (otherProto == proto)
20582083
continue;
20592084

2060-
// For every invertible protocol IP and any protocol 'P', there is an
2061-
// implied requirement 'Self: IP', unless it was suppressed via
2062-
// `Self: ~IP`. So if this suppression annotation exists yet IP was
2063-
// implied anyway, emit a diagnostic.
2064-
if (EnabledNoncopyableGenerics) {
2065-
if (auto kp = otherProto->getKnownProtocolKind()) {
2066-
if (auto ip = getInvertibleProtocolKind(*kp)) {
2067-
auto inverse = proto->hasInverseMarking(*ip);
2068-
if (!inverse)
2069-
continue; // no ~IP annotation
2070-
2071-
auto &Diags = proto->getASTContext().Diags;
2072-
Diags.diagnose(inverse.getLoc(),
2073-
diag::inverse_generic_but_also_conforms,
2074-
proto->getSelfInterfaceType(), getProtocolName(*kp));
2075-
continue;
2076-
}
2077-
}
2078-
}
2079-
20802085
// SIMDScalar in the standard library currently emits this warning for:
20812086
// 'Hashable', 'Encodable', and 'Decodable'. This is unfortunate, but we
20822087
// cannot fix it as it would alter the ABI of the protocol. Silence these

test/Generics/inverse_generics.swift

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,11 @@ func checkAliases<C, NC: ~Copyable>(_ a: AlwaysCopyable<C>, _ b: AlwaysCopyable<
2929
checkCopyable(b)
3030
}
3131

32+
protocol NeedsCopyable {}
33+
// expected-note@-1 {{type 'TryInferCopyable' does not conform to inherited protocol 'Copyable'}}
34+
3235
struct TryInferCopyable: ~Copyable, NeedsCopyable {}
33-
// expected-error@-1 {{type 'TryInferCopyable' does not conform to protocol 'NeedsCopyable'}}
34-
// expected-error@-2 {{type 'TryInferCopyable' does not conform to protocol 'Copyable'}}
36+
// expected-error@-1 {{type 'TryInferCopyable' does not conform to protocol 'Copyable'}}
3537

3638
protocol Removed: ~Copyable {
3739
func requiresCopyableSelf(_ t: AlwaysCopyable<Self>)
@@ -165,8 +167,6 @@ func chk(_ t: CornerCase<NC>) {}
165167

166168
/// MARK: tests that we diagnose ~Copyable that became invalid because it's required to be copyable
167169

168-
protocol NeedsCopyable {}
169-
170170
struct Silly: ~Copyable, Copyable {} // expected-error {{struct 'Silly' required to be 'Copyable' but is marked with '~Copyable'}}
171171
enum Sally: Copyable, ~Copyable, NeedsCopyable {} // expected-error {{enum 'Sally' required to be 'Copyable' but is marked with '~Copyable'}}
172172

@@ -176,10 +176,6 @@ class NiceTry: ~Copyable, Copyable {} // expected-error {{classes cannot be '~Co
176176
@_moveOnly class NiceTry2: Copyable {} // expected-error {{'@_moveOnly' attribute is only valid on structs or enums}}
177177
// expected-error@-1 {{class 'NiceTry2' required to be 'Copyable' but is marked with '~Copyable'}}
178178

179-
struct OopsConformance1: ~Copyable, NeedsCopyable {}
180-
// expected-error@-1 {{type 'OopsConformance1' does not conform to protocol 'NeedsCopyable'}}
181-
// expected-error@-2 {{type 'OopsConformance1' does not conform to protocol 'Copyable'}}
182-
183179

184180
struct Extendo: ~Copyable {}
185181
extension Extendo: Copyable, ~Copyable {} // expected-error {{cannot apply inverse '~Copyable' to extension}}
@@ -344,8 +340,8 @@ func conflict10<T>(_ t: T, _ u: some ~Copyable & Copyable)
344340
T: ~Copyable {}
345341
// expected-error@-1 {{'T' required to be 'Copyable' but is marked with '~Copyable'}}
346342

347-
// FIXME: this is bogus (rdar://119345796)
348343
protocol Conflict11: ~Copyable, Copyable {}
344+
// expected-error@-1 {{'Self' required to be 'Copyable' but is marked with '~Copyable'}}
349345

350346
struct Conflict12: ~Copyable, Copyable {}
351347
// expected-error@-1 {{struct 'Conflict12' required to be 'Copyable' but is marked with '~Copyable'}}

test/Generics/inverse_protocols_errors.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33

44

55
protocol RegularProto {}
6-
protocol NCProto: RegularProto
7-
where Self: ~Copyable { // expected-error{{'Self' required to be 'Copyable' but is marked with '~Copyable'}}
6+
protocol NCProto: RegularProto // expected-error{{'Self' required to be 'Copyable' but is marked with '~Copyable'}}
7+
where Self: ~Copyable {
88
func checkIfCopyableSelf(_ s: Self)
99
}
1010

test/Parse/inverses.swift

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
// RUN: %target-typecheck-verify-swift -enable-experimental-feature NoncopyableGenerics
22

3-
4-
53
protocol U {}
64

75
enum Maybe<Thing: ~Copyable> : ~Copyable {}
@@ -50,8 +48,7 @@ public struct MoveOnlyS1<T> : ~Copyable { /*deinit {}*/ }
5048
public struct MoveOnlyS2<T: Equatable> : ~Copyable { /*deinit {}*/ }
5149
public struct MoveOnlyS3<T: ~Copyable> : ~Copyable { /*deinit {}*/ }
5250

53-
protocol Rope<Element>: Hashable, ~ Copyable {
54-
51+
protocol Rope<Element>: Hashable, ~Copyable { // expected-error {{'Self' required to be 'Copyable' but is marked with '~Copyable'}}
5552
associatedtype Element: ~Copyable
5653
}
5754

0 commit comments

Comments
 (0)