Skip to content

Commit fe2408c

Browse files
committed
TypeCheckType: Unconditionally warn about missing existential any until Swift 7
#72659 turned out to have some source compatibility fallout that we need to fix. Instead of introducing yet another brittle compatibility hack, stop emitting errors about a missing `any` altogether until a future language mode. Besides resolving the compatibility issue, this will encourage developers to adopt any sooner and grant us ample time to gracefully address any remaining bugs before the source compatibility burden resurfaces. A subsequent commit adds a diagnostic group that will allow users to escalate these warnings to errors with `-Werror ExistentialAny`.
1 parent 02261dc commit fe2408c

15 files changed

+163
-170
lines changed

include/swift/AST/Decl.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5580,12 +5580,6 @@ class ProtocolDecl final : public NominalTypeDecl {
55805580
/// value requirement.
55815581
bool hasSelfOrAssociatedTypeRequirements() const;
55825582

5583-
/// Determine whether an existential type constrained by this protocol must
5584-
/// be written using `any` syntax.
5585-
///
5586-
/// \Note This method takes language feature state into account.
5587-
bool existentialRequiresAny() const;
5588-
55895583
/// Returns a list of protocol requirements that must be assessed to
55905584
/// determine a concrete's conformance effect polymorphism kind.
55915585
PolymorphicEffectRequirementList getPolymorphicEffectRequirements(

lib/AST/Decl.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6958,13 +6958,6 @@ bool ProtocolDecl::hasSelfOrAssociatedTypeRequirements() const {
69586958
resultForCycle);
69596959
}
69606960

6961-
bool ProtocolDecl::existentialRequiresAny() const {
6962-
if (getASTContext().LangOpts.hasFeature(Feature::ExistentialAny))
6963-
return true;
6964-
6965-
return hasSelfOrAssociatedTypeRequirements();
6966-
}
6967-
69686961
ArrayRef<AssociatedTypeDecl *>
69696962
ProtocolDecl::getPrimaryAssociatedTypes() const {
69706963
return evaluateOrDefault(getASTContext().evaluator,

lib/Sema/TypeCheckType.cpp

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -907,11 +907,15 @@ static Type applyGenericArguments(Type type,
907907
auto parameterized =
908908
ParameterizedProtocolType::get(ctx, protoType, argTys);
909909

910+
// FIXME: Can this not be done in ExistentialTypeSyntaxChecker?
910911
if (resolution.getOptions().isConstraintImplicitExistential() &&
911912
!ctx.LangOpts.hasFeature(Feature::ImplicitSome)) {
912-
diags.diagnose(loc, diag::existential_requires_any, parameterized,
913-
ExistentialType::get(parameterized),
914-
/*isAlias=*/isa<TypeAliasType>(type.getPointer()));
913+
diags
914+
.diagnose(loc, diag::existential_requires_any, parameterized,
915+
ExistentialType::get(parameterized),
916+
/*isAlias=*/isa<TypeAliasType>(type.getPointer()))
917+
.warnUntilSwiftVersion(7);
918+
915919
return ErrorType::get(ctx);
916920
}
917921

@@ -6173,16 +6177,13 @@ class ExistentialTypeSyntaxChecker : public ASTWalker {
61736177
ASTContext &Ctx;
61746178
const bool checkStatements;
61756179
bool hitTopStmt;
6176-
bool warnUntilSwift7;
61776180

61786181
unsigned exprCount = 0;
61796182
llvm::SmallVector<TypeRepr *, 4> reprStack;
61806183

61816184
public:
6182-
ExistentialTypeSyntaxChecker(ASTContext &ctx, bool checkStatements,
6183-
bool warnUntilSwift7 = false)
6184-
: Ctx(ctx), checkStatements(checkStatements), hitTopStmt(false),
6185-
warnUntilSwift7(warnUntilSwift7) {}
6185+
ExistentialTypeSyntaxChecker(ASTContext &ctx, bool checkStatements)
6186+
: Ctx(ctx), checkStatements(checkStatements), hitTopStmt(false) {}
61866187

61876188
MacroWalking getMacroWalkingBehavior() const override {
61886189
return MacroWalking::ArgumentsAndExpansion;
@@ -6381,6 +6382,11 @@ class ExistentialTypeSyntaxChecker : public ASTWalker {
63816382
return false;
63826383
}
63836384

6385+
// A missing `any` or `some` is always diagnosed if this feature is enabled.
6386+
if (ctx.LangOpts.hasFeature(Feature::ExistentialAny)) {
6387+
return true;
6388+
}
6389+
63846390
// If the type is inverted, a missing `any` or `some` is always diagnosed.
63856391
if (isInverted) {
63866392
return true;
@@ -6398,7 +6404,7 @@ class ExistentialTypeSyntaxChecker : public ASTWalker {
63986404
// a missing `any` or `some` is always diagnosed.
63996405
auto layout = constraintTy->getExistentialLayout();
64006406
for (auto *protoDecl : layout.getProtocols()) {
6401-
if (protoDecl->existentialRequiresAny()) {
6407+
if (protoDecl->hasSelfOrAssociatedTypeRequirements()) {
64026408
return true;
64036409
}
64046410
}
@@ -6470,7 +6476,7 @@ class ExistentialTypeSyntaxChecker : public ASTWalker {
64706476
/*isAlias=*/isa<TypeAliasDecl>(decl)));
64716477
}
64726478

6473-
diag->warnUntilSwiftVersionIf(warnUntilSwift7, 7);
6479+
diag->warnUntilSwiftVersion(7);
64746480
emitInsertAnyFixit(*diag, T);
64756481
}
64766482

@@ -6545,14 +6551,7 @@ void TypeChecker::checkExistentialTypes(ASTContext &ctx, Stmt *stmt,
65456551
if (DC->isInSwiftinterface())
65466552
return;
65476553

6548-
// Previously we missed this diagnostic on 'catch' statements, downgrade
6549-
// to a warning until Swift 7.
6550-
auto downgradeUntilSwift7 = false;
6551-
if (auto *CS = dyn_cast<CaseStmt>(stmt))
6552-
downgradeUntilSwift7 = CS->getParentKind() == CaseParentKind::DoCatch;
6553-
6554-
ExistentialTypeSyntaxChecker checker(ctx, /*checkStatements=*/true,
6555-
downgradeUntilSwift7);
6554+
ExistentialTypeSyntaxChecker checker(ctx, /*checkStatements=*/true);
65566555
stmt->walk(checker);
65576556
}
65586557

test/Generics/inverse_generics.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -475,8 +475,8 @@ func checkExistentials() {
475475

476476
typealias NotCopyable = ~Copyable
477477
typealias EmptyComposition = ~Copyable & ~Escapable
478-
func test(_ t: borrowing NotCopyable) {} // expected-error {{use of 'NotCopyable' (aka '~Copyable') as a type must be written 'any NotCopyable'}}
479-
func test(_ t: borrowing EmptyComposition) {} // expected-error {{use of 'EmptyComposition' (aka '~Copyable & ~Escapable') as a type must be written 'any EmptyComposition' (aka 'any ~Copyable & ~Escapable')}}
478+
func test(_ t: borrowing NotCopyable) {} // expected-warning {{use of 'NotCopyable' (aka '~Copyable') as a type must be written 'any NotCopyable'}}
479+
func test(_ t: borrowing EmptyComposition) {} // expected-warning {{use of 'EmptyComposition' (aka '~Copyable & ~Escapable') as a type must be written 'any EmptyComposition' (aka 'any ~Copyable & ~Escapable')}}
480480

481481
typealias Copy = Copyable
482482
func test(_ z1: Copy, _ z2: Copyable) {}

test/Macros/macros_diagnostics.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,8 @@ struct MyStruct<T: MyProto> {
196196

197197
struct SomeType {
198198
#genericUnary<Equatable>(0 as Hashable)
199-
// expected-error@-1{{use of protocol 'Equatable' as a type must be written 'any Equatable'}}
200-
// expected-error@-2{{use of protocol 'Hashable' as a type must be written 'any Hashable'}}
199+
// expected-warning@-1{{use of protocol 'Equatable' as a type must be written 'any Equatable'}}
200+
// expected-warning@-2{{use of protocol 'Hashable' as a type must be written 'any Hashable'}}
201201
// expected-error@-3{{external macro implementation type}}
202202
}
203203

test/Macros/top_level_freestanding.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,12 @@ func testGlobalVariable() {
107107

108108
// expected-note @+1 6 {{in expansion of macro 'anonymousTypes' here}}
109109
#anonymousTypes(causeErrors: true) { "foo" }
110-
// DIAG_BUFFERS-DAG: @__swiftmacro_9MacroUser0033top_level_freestandingswift_DbGHjfMX108_0_33_082AE7CFEFA6960C804A9FE7366EB5A0Ll14anonymousTypesfMf0_{{.*}}: error: use of protocol 'Equatable' as a type must be written 'any Equatable'
111-
// DIAG_BUFFERS-DAG: @__swiftmacro_9MacroUser00142___swiftmacro_9MacroUser0033top_level_freestandingswift_DbGHjfMX108_0_33_082AE7CFEFA6960C804A9FE7366EB5A0Ll14anonymousTypesfMf0_swift_DAIABdjIbfMX23_2_33_082AE7CFEFA6960C804A9FE7366EB5A0Ll27introduceTypeCheckingErrorsfMf_{{.*}}: error: use of protocol 'Hashable' as a type must be written 'any Hashable'
110+
// DIAG_BUFFERS-DAG: @__swiftmacro_9MacroUser0033top_level_freestandingswift_DbGHjfMX108_0_33_082AE7CFEFA6960C804A9FE7366EB5A0Ll14anonymousTypesfMf0_{{.*}}: warning: use of protocol 'Equatable' as a type must be written 'any Equatable'
111+
// DIAG_BUFFERS-DAG: @__swiftmacro_9MacroUser00142___swiftmacro_9MacroUser0033top_level_freestandingswift_DbGHjfMX108_0_33_082AE7CFEFA6960C804A9FE7366EB5A0Ll14anonymousTypesfMf0_swift_DAIABdjIbfMX23_2_33_082AE7CFEFA6960C804A9FE7366EB5A0Ll27introduceTypeCheckingErrorsfMf_{{.*}}: warning: use of protocol 'Hashable' as a type must be written 'any Hashable'
112112

113113
// expected-note @+1 2 {{in expansion of macro 'anonymousTypes' here}}
114114
#anonymousTypes { () -> String in
115-
// expected-error @+1 {{use of protocol 'Equatable' as a type must be written 'any Equatable'}}
115+
// expected-warning @+1 {{use of protocol 'Equatable' as a type must be written 'any Equatable'}}
116116
_ = 0 as Equatable
117117
return "foo"
118118
}

test/decl/nested/protocol.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ extension OuterProtocol {
237237

238238
struct ConformsToOuterProtocol : OuterProtocol {
239239
typealias Hen = Int
240-
func f() { let _ = InnerProtocol.self } // expected-error {{use of protocol 'InnerProtocol' as a type must be written 'any InnerProtocol'}}
240+
func f() { let _ = InnerProtocol.self } // expected-warning {{use of protocol 'InnerProtocol' as a type must be written 'any InnerProtocol'}}
241241
}
242242

243243
extension OuterProtocol {

test/decl/protocol/existential_member_access/generic_fixit.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ protocol P {
1212
protocol Q {}
1313

1414
do {
15-
func test(p: P) { // expected-error {{use of protocol 'P' as a type must be written 'any P'}}
15+
func test(p: P) { // expected-warning {{use of protocol 'P' as a type must be written 'any P'}}
1616
p.method(false) // expected-error {{member 'method' cannot be used on value of type 'any P'; consider using a generic constraint instead}} {{-1:16--1:17=some P}} {{none}}
1717
}
1818
}
1919
do {
20-
func test(p: ((P))) { // expected-error {{use of protocol 'P' as a type must be written 'any P'}}
20+
func test(p: ((P))) { // expected-warning {{use of protocol 'P' as a type must be written 'any P'}}
2121
p.method(false) // expected-error {{member 'method' cannot be used on value of type 'any P'; consider using a generic constraint instead}} {{-1:18--1:19=some P}} {{none}}
2222
}
2323
}
@@ -57,12 +57,12 @@ do {
5757
}
5858
}
5959
do {
60-
func test(p: P.Type) { // expected-error {{use of protocol 'P' as a type must be written 'any P'}}
60+
func test(p: P.Type) { // expected-warning {{use of protocol 'P' as a type must be written 'any P'}}
6161
p.staticMethod(false) // expected-error {{member 'staticMethod' cannot be used on value of type 'any P.Type'; consider using a generic constraint instead}} {{-1:16--1:17=(some P)}} {{none}}
6262
}
6363
}
6464
do {
65-
func test(p: (P).Type) { // expected-error {{use of protocol 'P' as a type must be written 'any P'}}
65+
func test(p: (P).Type) { // expected-warning {{use of protocol 'P' as a type must be written 'any P'}}
6666
p.staticMethod(false) // expected-error {{member 'staticMethod' cannot be used on value of type 'any P.Type'; consider using a generic constraint instead}} {{-1:17--1:18=some P}} {{none}}
6767
}
6868
}
@@ -78,12 +78,12 @@ do {
7878
}
7979

8080
do {
81-
func test(p: P & Q) { // expected-error {{use of protocol 'P' as a type must be written 'any P'}}
81+
func test(p: P & Q) { // expected-warning {{use of protocol 'P' as a type must be written 'any P'}}
8282
p.method(false) // expected-error {{member 'method' cannot be used on value of type 'any P & Q'; consider using a generic constraint instead}} {{-1:16--1:21=some P & Q}} {{none}}
8383
}
8484
}
8585
do {
86-
func test(p: ((P & Q))) { // expected-error {{use of protocol 'P' as a type must be written 'any P'}}
86+
func test(p: ((P & Q))) { // expected-warning {{use of protocol 'P' as a type must be written 'any P'}}
8787
p.method(false) // expected-error {{member 'method' cannot be used on value of type 'any P & Q'; consider using a generic constraint instead}} {{-1:18--1:23=some P & Q}} {{none}}
8888
}
8989
}
@@ -123,12 +123,12 @@ do {
123123
}
124124
}
125125
do {
126-
func test(p: (P & Q).Type) { // expected-error {{use of protocol 'P' as a type must be written 'any P'}}
126+
func test(p: (P & Q).Type) { // expected-warning {{use of protocol 'P' as a type must be written 'any P'}}
127127
p.staticMethod(false) // expected-error {{member 'staticMethod' cannot be used on value of type 'any (P & Q).Type'; consider using a generic constraint instead}} {{-1:17--1:22=some P & Q}} {{none}}
128128
}
129129
}
130130
do {
131-
func test(p: ((P & Q)).Type) { // expected-error {{use of protocol 'P' as a type must be written 'any P'}}
131+
func test(p: ((P & Q)).Type) { // expected-warning {{use of protocol 'P' as a type must be written 'any P'}}
132132
p.staticMethod(false) // expected-error {{member 'staticMethod' cannot be used on value of type 'any (P & Q).Type'; consider using a generic constraint instead}} {{-1:18--1:23=some P & Q}} {{none}}
133133
}
134134
}

test/decl/protocol/protocols.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,7 @@ func i<T : C3>(_ x : T?) -> Bool {
475475
// expected-warning@-1 {{checking a value with optional type 'T?' against type 'any P1' succeeds whenever the value is non-nil; did you mean to use '!= nil'?}}
476476
}
477477
func j(_ x : C1) -> Bool {
478-
return x is P1 // expected-error {{use of protocol 'P1' as a type must be written 'any P1'}}
478+
return x is P1 // expected-warning {{use of protocol 'P1' as a type must be written 'any P1'}}
479479
}
480480
func k(_ x : C1?) -> Bool {
481481
return x is any P1

test/decl/protocol/recursive_requirement.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// RUN: %target-typecheck-verify-swift
2-
// RUN: not %target-swift-frontend -typecheck %s -debug-generic-signatures 2>&1 | %FileCheck %s
2+
// RUN: %target-swift-frontend -typecheck %s -debug-generic-signatures 2>&1 | %FileCheck %s
33

44
// -----
55

@@ -95,7 +95,7 @@ protocol AsExistentialB {
9595
}
9696

9797
protocol AsExistentialAssocTypeA {
98-
var delegate : AsExistentialAssocTypeB? { get } // expected-error {{use of protocol 'AsExistentialAssocTypeB' as a type must be written 'any AsExistentialAssocTypeB'}}
98+
var delegate : (any AsExistentialAssocTypeB)? { get }
9999
}
100100
protocol AsExistentialAssocTypeB {
101101
func aMethod(_ object : AsExistentialAssocTypeA)
@@ -107,7 +107,7 @@ protocol AsExistentialAssocTypeAgainA {
107107
associatedtype Bar
108108
}
109109
protocol AsExistentialAssocTypeAgainB {
110-
func aMethod(_ object : AsExistentialAssocTypeAgainA) // expected-error {{use of protocol 'AsExistentialAssocTypeAgainA' as a type must be written 'any AsExistentialAssocTypeAgainA'}}
110+
func aMethod(_ object : any AsExistentialAssocTypeAgainA)
111111
}
112112

113113
// https://github.com/apple/swift/issues/43164

0 commit comments

Comments
 (0)