Skip to content

Commit c3877c8

Browse files
Merge pull request #65112 from AnthonyLatsis/existential-any-multimodule
TypeCheckType: Fix existential 'any' migration diagnostics for extra-modular protocols
2 parents 66641c7 + 8d1d526 commit c3877c8

8 files changed

+88
-27
lines changed

include/swift/AST/Decl.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4889,8 +4889,14 @@ class ProtocolDecl final : public NominalTypeDecl {
48894889
bool requiresSelfConformanceWitnessTable() const;
48904890

48914891
/// Determine whether an existential type must be explicitly prefixed
4892-
/// with \c any. \c any is required if any of the members contain
4893-
/// an associated type, or if \c Self appears in non-covariant position.
4892+
/// with \c any. \c any is required if one of the following conditions is met
4893+
/// for this protocol or an inherited protocol:
4894+
/// - The protocol has an associated type requirement.
4895+
/// - `Self` appears in non-covariant position in the type signature of a
4896+
/// value requirement.
4897+
///
4898+
/// @Note This method does not take the state of language features into
4899+
/// account.
48944900
bool existentialRequiresAny() const;
48954901

48964902
/// Returns a list of protocol requirements that must be assessed to

lib/Sema/TypeCheckDecl.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -714,10 +714,6 @@ ExistentialConformsToSelfRequest::evaluate(Evaluator &evaluator,
714714
bool
715715
ExistentialRequiresAnyRequest::evaluate(Evaluator &evaluator,
716716
ProtocolDecl *decl) const {
717-
auto &ctx = decl->getASTContext();
718-
if (ctx.LangOpts.hasFeature(Feature::ExistentialAny))
719-
return true;
720-
721717
// ObjC protocols do not require `any`.
722718
if (decl->isObjC())
723719
return false;

lib/Sema/TypeCheckType.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5166,6 +5166,10 @@ class ExistentialTypeVisitor
51665166
if (T->isInvalid())
51675167
return;
51685168

5169+
if (Ctx.LangOpts.hasFeature(Feature::ImplicitSome)) {
5170+
return;
5171+
}
5172+
51695173
// Compute the type repr to attach 'any' to.
51705174
TypeRepr *replaceRepr = T;
51715175
// Insert parens in expression context for '(any P).self'
@@ -5198,7 +5202,8 @@ class ExistentialTypeVisitor
51985202
OS << ")";
51995203

52005204
if (auto *proto = dyn_cast_or_null<ProtocolDecl>(T->getBoundDecl())) {
5201-
if (proto->existentialRequiresAny() && !Ctx.LangOpts.hasFeature(Feature::ImplicitSome)) {
5205+
if (Ctx.LangOpts.hasFeature(Feature::ExistentialAny) ||
5206+
proto->existentialRequiresAny()) {
52025207
Ctx.Diags.diagnose(T->getNameLoc(),
52035208
diag::existential_requires_any,
52045209
proto->getDeclaredInterfaceType(),
@@ -5216,7 +5221,8 @@ class ExistentialTypeVisitor
52165221
if (type->isConstraintType()) {
52175222
auto layout = type->getExistentialLayout();
52185223
for (auto *protoDecl : layout.getProtocols()) {
5219-
if (!protoDecl->existentialRequiresAny() || Ctx.LangOpts.hasFeature(Feature::ImplicitSome))
5224+
if (!Ctx.LangOpts.hasFeature(Feature::ExistentialAny) &&
5225+
!protoDecl->existentialRequiresAny())
52205226
continue;
52215227

52225228
Ctx.Diags.diagnose(T->getNameLoc(),

test/expr/postfix/call/forward_trailing_closure_errors.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ func testUnlabeledParamMatching(i: Int, fn: ((Int) -> Int) -> Void) {
2020

2121
// When "fuzzy matching is disabled, this will fail.
2222
func forwardMatchFailure( // expected-note{{declared here}}
23-
onError: ((Error) -> Void)? = nil,
23+
onError: ((any Error) -> Void)? = nil,
2424
onCompletion: (Int) -> Void
2525
) { }
2626

test/type/explicit_existential.swift

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -207,17 +207,9 @@ extension MyError {
207207
}
208208
}
209209

210-
struct Wrapper {
211-
typealias E = Error
212-
}
213-
214-
func typealiasMemberReferences(metatype: Wrapper.Type) {
215-
let _: Wrapper.E.Protocol = metatype.E.self
216-
let _: (any Wrapper.E).Type = metatype.E.self
217-
}
218-
219210
func testAnyTypeExpr() {
220211
let _: (any P).Type = (any P).self
212+
let _: (any P1 & P2).Type = (any P1 & P2).self
221213

222214
func test(_: (any P).Type) {}
223215
test((any P).self)
@@ -281,6 +273,12 @@ enum EE : Equatable, any Empty { // expected-error {{raw type 'any Empty' is not
281273
case hack
282274
}
283275

276+
// Protocols from a serialized module (the standard library).
277+
do {
278+
let _: Decodable
279+
let _: Codable
280+
}
281+
284282
func testAnyFixIt() {
285283
struct ConformingType : HasAssoc {
286284
typealias Assoc = Int
@@ -302,6 +300,19 @@ func testAnyFixIt() {
302300
// expected-error@+2 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-18=(any HasAssoc)}}
303301
// expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{30-38=(any HasAssoc)}}
304302
let _: HasAssoc.Protocol = HasAssoc.self
303+
do {
304+
struct Wrapper {
305+
typealias HasAssocAlias = HasAssoc
306+
}
307+
let wrapperMeta: Wrapper.Type
308+
// FIXME: Both of these fix-its are wrong.
309+
// 1. 'any' is attached to 'HasAssocAlias' instead of 'Wrapper.HasAssocAlias'
310+
// 2. What is the correct fix-it for the initializer?
311+
//
312+
// expected-error@+2:20 {{use of 'Wrapper.HasAssocAlias' (aka 'HasAssoc') as a type must be written 'any Wrapper.HasAssocAlias' (aka 'any HasAssoc')}}{{20-33=(any HasAssocAlias)}}
313+
// expected-error@+1:57 {{use of 'Wrapper.HasAssocAlias' (aka 'HasAssoc') as a type must be written 'any Wrapper.HasAssocAlias' (aka 'any HasAssoc')}}{{57-70=(any HasAssocAlias)}}
314+
let _: Wrapper.HasAssocAlias.Protocol = wrapperMeta.HasAssocAlias.self
315+
}
305316
// expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{11-19=any HasAssoc}}
306317
let _: (HasAssoc).Protocol = (any HasAssoc).self
307318
// expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-18=(any HasAssoc)}}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend %s -swift-version 5 -emit-module -DM -module-name M -emit-module-path %t/M.swiftmodule -enable-upcoming-feature ExistentialAny
3+
// RUN: %target-swift-frontend %s -verify -swift-version 5 -typecheck -I %t
4+
5+
// Test that the feature state used to compile a module is not reflected in
6+
// the module file. The feature must not be enforced on protocols originating in
7+
// a different module just because that module was compiled with the feature
8+
// enabled.
9+
10+
#if M
11+
public protocol P {}
12+
#else
13+
import M
14+
func test(_: P) {}
15+
#endif
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend %s -swift-version 5 -emit-module -DM -module-name M -emit-module-path %t/M.swiftmodule
3+
// RUN: %target-swift-frontend %s -verify -swift-version 5 -typecheck -I %t -enable-upcoming-feature ExistentialAny
4+
5+
// Test that a protocol that requires 'any' *only* when the feature is enabled
6+
// is diagnosed as expected when said protocol originates in a different module.
7+
// In other words, test that deserialization does not affect 'any' migration
8+
// diagnostics.
9+
10+
#if M
11+
public protocol P {}
12+
#else
13+
import M
14+
func test(_: P) {} // expected-error {{use of protocol 'P' as a type must be written 'any P'}}
15+
#endif

test/type/explicit_existential_swift6.swift

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -229,17 +229,9 @@ extension MyError {
229229
}
230230
}
231231

232-
struct Wrapper {
233-
typealias E = Error
234-
}
235-
236-
func typealiasMemberReferences(metatype: Wrapper.Type) {
237-
let _: Wrapper.E.Protocol = metatype.E.self
238-
let _: (any Wrapper.E).Type = metatype.E.self
239-
}
240-
241232
func testAnyTypeExpr() {
242233
let _: (any P).Type = (any P).self
234+
let _: (any P1 & P2).Type = (any P1 & P2).self
243235

244236
func test(_: (any P).Type) {}
245237
test((any P).self)
@@ -311,6 +303,13 @@ enum EE : Equatable, any Empty { // expected-error {{raw type 'any Empty' is not
311303
case hack
312304
}
313305

306+
// Protocols from a serialized module (the standard library).
307+
do {
308+
// expected-error@+1 {{use of protocol 'Decodable' as a type must be written 'any Decodable'}}
309+
let _: Decodable
310+
// expected-error@+1 2 {{use of 'Codable' (aka 'Decodable & Encodable') as a type must be written 'any Codable' (aka 'any Decodable & Encodable')}}
311+
let _: Codable
312+
}
314313

315314
func testAnyFixIt() {
316315
struct ConformingType : HasAssoc {
@@ -333,6 +332,19 @@ func testAnyFixIt() {
333332
// expected-error@+2 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-18=(any HasAssoc)}}
334333
// expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{30-38=(any HasAssoc)}}
335334
let _: HasAssoc.Protocol = HasAssoc.self
335+
do {
336+
struct Wrapper {
337+
typealias HasAssocAlias = HasAssoc
338+
}
339+
let wrapperMeta: Wrapper.Type
340+
// FIXME: Both of these fix-its are wrong.
341+
// 1. 'any' is attached to 'HasAssocAlias' instead of 'Wrapper.HasAssocAlias'
342+
// 2. What is the correct fix-it for the initializer?
343+
//
344+
// expected-error@+2:20 {{use of 'Wrapper.HasAssocAlias' (aka 'HasAssoc') as a type must be written 'any Wrapper.HasAssocAlias' (aka 'any HasAssoc')}}{{20-33=(any HasAssocAlias)}}
345+
// expected-error@+1:57 {{use of 'Wrapper.HasAssocAlias' (aka 'HasAssoc') as a type must be written 'any Wrapper.HasAssocAlias' (aka 'any HasAssoc')}}{{57-70=(any HasAssocAlias)}}
346+
let _: Wrapper.HasAssocAlias.Protocol = wrapperMeta.HasAssocAlias.self
347+
}
336348
// expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{11-19=any HasAssoc}}
337349
let _: (HasAssoc).Protocol = (any HasAssoc).self
338350
// expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-18=(any HasAssoc)}}

0 commit comments

Comments
 (0)