Skip to content

Commit 8167442

Browse files
authored
Merge pull request #42225 from slavapestov/enable-se-0346-by-default
Enable parameterized protocols by default, and add new staging flag for parameterized existentials
2 parents 767f7b7 + 1bf248e commit 8167442

16 files changed

+128
-123
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -378,9 +378,6 @@ ERROR(expected_rbrace_actor,none,
378378
"expected '}' in actor", ())
379379

380380
// Protocol
381-
ERROR(generic_arguments_protocol,PointsToFirstBadToken,
382-
"protocols do not allow generic parameters; use associated types instead",
383-
())
384381
ERROR(expected_lbrace_protocol,PointsToFirstBadToken,
385382
"expected '{' in protocol type", ())
386383
ERROR(expected_rbrace_protocol,none,

include/swift/Basic/LangOptions.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -330,9 +330,9 @@ namespace swift {
330330
/// in calls to generic functions.
331331
bool EnableOpenedExistentialTypes = false;
332332

333-
/// Enable support for protocol types parameterized by primary
334-
/// associated type.
335-
bool EnableParameterizedProtocolTypes = false;
333+
/// Enable support for parameterized protocol types in existential
334+
/// position.
335+
bool EnableParameterizedExistentialTypes = false;
336336

337337
/// Enable experimental flow-sensitive concurrent captures.
338338
bool EnableExperimentalFlowSensitiveConcurrentCaptures = false;

include/swift/Option/FrontendOptions.td

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -540,9 +540,9 @@ def enable_explicit_existential_types :
540540
Flag<["-"], "enable-explicit-existential-types">,
541541
HelpText<"Enable experimental support for explicit existential types">;
542542

543-
def enable_parameterized_protocol_types :
544-
Flag<["-"], "enable-parameterized-protocol-types">,
545-
HelpText<"Enable experimental support for primary associated types and parameterized protocols">;
543+
def enable_parameterized_existential_types :
544+
Flag<["-"], "enable-parameterized-existential-types">,
545+
HelpText<"Enable experimental support for parameterized existential types">;
546546

547547
def enable_experimental_opened_existential_types :
548548
Flag<["-"], "enable-experimental-opened-existential-types">,

lib/Frontend/CompilerInvocation.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -448,8 +448,8 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
448448
Opts.EnableExperimentalNamedOpaqueTypes |=
449449
Args.hasArg(OPT_enable_experimental_named_opaque_types);
450450

451-
Opts.EnableParameterizedProtocolTypes |=
452-
Args.hasArg(OPT_enable_parameterized_protocol_types);
451+
Opts.EnableParameterizedExistentialTypes |=
452+
Args.hasArg(OPT_enable_parameterized_existential_types);
453453

454454
Opts.EnableOpenedExistentialTypes =
455455
Args.hasFlag(OPT_enable_experimental_opened_existential_types,

lib/Parse/ParseDecl.cpp

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8066,19 +8066,8 @@ parseDeclProtocol(ParseDeclOptions Flags, DeclAttributes &Attributes) {
80668066
return Status;
80678067

80688068
SmallVector<PrimaryAssociatedTypeName, 2> PrimaryAssociatedTypeNames;
8069-
8070-
if (Context.LangOpts.EnableParameterizedProtocolTypes) {
8071-
if (startsWithLess(Tok)) {
8072-
Status |= parsePrimaryAssociatedTypes(PrimaryAssociatedTypeNames);
8073-
}
8074-
} else {
8075-
// Protocols don't support generic parameters, but people often want them and
8076-
// we want to have good error recovery if they try them out. Parse them and
8077-
// produce a specific diagnostic if present.
8078-
if (startsWithLess(Tok)) {
8079-
diagnose(Tok, diag::generic_arguments_protocol);
8080-
maybeParseGenericParams();
8081-
}
8069+
if (startsWithLess(Tok)) {
8070+
Status |= parsePrimaryAssociatedTypes(PrimaryAssociatedTypeNames);
80828071
}
80838072

80848073
DebuggerContextChange DCC (*this);

lib/Sema/TypeCheckType.cpp

Lines changed: 33 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -628,50 +628,48 @@ static Type applyGenericArguments(Type type, TypeResolution resolution,
628628
auto &ctx = dc->getASTContext();
629629
auto &diags = ctx.Diags;
630630

631-
if (ctx.LangOpts.EnableParameterizedProtocolTypes) {
632-
if (auto *protoType = type->getAs<ProtocolType>()) {
633-
// Build ParameterizedProtocolType if the protocol has a primary associated
634-
// type and we're in a supported context (for now just generic requirements,
635-
// inheritance clause, extension binding).
636-
if (!resolution.getOptions().isParameterizedProtocolSupported()) {
637-
diags.diagnose(loc, diag::parameterized_protocol_not_supported);
638-
return ErrorType::get(ctx);
639-
}
631+
if (auto *protoType = type->getAs<ProtocolType>()) {
632+
// Build ParameterizedProtocolType if the protocol has a primary associated
633+
// type and we're in a supported context (for now just generic requirements,
634+
// inheritance clause, extension binding).
635+
if (!resolution.getOptions().isParameterizedProtocolSupported(ctx.LangOpts)) {
636+
diags.diagnose(loc, diag::parameterized_protocol_not_supported);
637+
return ErrorType::get(ctx);
638+
}
640639

641-
auto *protoDecl = protoType->getDecl();
642-
auto assocTypes = protoDecl->getPrimaryAssociatedTypes();
643-
if (assocTypes.empty()) {
644-
diags.diagnose(loc, diag::protocol_does_not_have_primary_assoc_type,
645-
protoType);
640+
auto *protoDecl = protoType->getDecl();
641+
auto assocTypes = protoDecl->getPrimaryAssociatedTypes();
642+
if (assocTypes.empty()) {
643+
diags.diagnose(loc, diag::protocol_does_not_have_primary_assoc_type,
644+
protoType);
646645

647-
return ErrorType::get(ctx);
648-
}
649-
650-
auto genericArgs = generic->getGenericArgs();
646+
return ErrorType::get(ctx);
647+
}
651648

652-
if (genericArgs.size() != assocTypes.size()) {
653-
diags.diagnose(loc,
654-
diag::parameterized_protocol_type_argument_count_mismatch,
655-
protoType, genericArgs.size(), assocTypes.size(),
656-
(genericArgs.size() < assocTypes.size()) ? 1 : 0);
649+
auto genericArgs = generic->getGenericArgs();
657650

658-
return ErrorType::get(ctx);
659-
}
651+
if (genericArgs.size() != assocTypes.size()) {
652+
diags.diagnose(loc,
653+
diag::parameterized_protocol_type_argument_count_mismatch,
654+
protoType, genericArgs.size(), assocTypes.size(),
655+
(genericArgs.size() < assocTypes.size()) ? 1 : 0);
660656

661-
auto genericResolution =
662-
resolution.withOptions(adjustOptionsForGenericArgs(options));
657+
return ErrorType::get(ctx);
658+
}
663659

664-
SmallVector<Type, 2> argTys;
665-
for (auto *genericArg : genericArgs) {
666-
Type argTy = genericResolution.resolveType(genericArg, silParams);
667-
if (!argTy || argTy->hasError())
668-
return ErrorType::get(ctx);
660+
auto genericResolution =
661+
resolution.withOptions(adjustOptionsForGenericArgs(options));
669662

670-
argTys.push_back(argTy);
671-
}
663+
SmallVector<Type, 2> argTys;
664+
for (auto *genericArg : genericArgs) {
665+
Type argTy = genericResolution.resolveType(genericArg, silParams);
666+
if (!argTy || argTy->hasError())
667+
return ErrorType::get(ctx);
672668

673-
return ParameterizedProtocolType::get(ctx, protoType, argTys);
669+
argTys.push_back(argTy);
674670
}
671+
672+
return ParameterizedProtocolType::get(ctx, protoType, argTys);
675673
}
676674

677675
// We must either have an unbound generic type, or a generic type alias.

lib/Sema/TypeCheckType.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "swift/AST/Type.h"
2020
#include "swift/AST/Types.h"
2121
#include "swift/AST/TypeResolutionStage.h"
22+
#include "swift/Basic/LangOptions.h"
2223
#include "llvm/ADT/None.h"
2324

2425
namespace swift {
@@ -277,13 +278,17 @@ class TypeResolutionOptions {
277278
}
278279

279280
/// Whether parameterized protocol types are supported in this context.
280-
bool isParameterizedProtocolSupported() const {
281+
///
282+
/// FIXME: Remove LangOptions parameter once EnableParameterizedExistentialTypes
283+
/// staging flag is gone.
284+
bool isParameterizedProtocolSupported(const LangOptions &opts) const {
281285
switch (context) {
282286
case Context::Inherited:
283287
case Context::ExtensionBinding:
284288
case Context::GenericRequirement:
285-
case Context::ExistentialConstraint:
286289
return true;
290+
case Context::ExistentialConstraint:
291+
return opts.EnableParameterizedExistentialTypes;
287292
case Context::None:
288293
case Context::TypeAliasDecl:
289294
case Context::GenericTypeAliasDecl:

test/Constraints/opened_existentials.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-typecheck-verify-swift -enable-experimental-opened-existential-types -enable-parameterized-protocol-types
1+
// RUN: %target-typecheck-verify-swift -enable-experimental-opened-existential-types
22

33
protocol Q { }
44

test/ModuleInterface/parameterized-protocols.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// RUN: %empty-directory(%t)
2-
// RUN: %target-swift-frontend -typecheck -module-name ParameterizedProtocols -emit-module-interface-path %t/ParameterizedProtocols.swiftinterface -enable-parameterized-protocol-types %s
2+
// RUN: %target-swift-frontend -typecheck -module-name ParameterizedProtocols -emit-module-interface-path %t/ParameterizedProtocols.swiftinterface %s
33
// RUN: %FileCheck %s < %t/ParameterizedProtocols.swiftinterface
44

55
public protocol HasPrimaryAssociatedTypes<T, U> {

test/Parse/invalid.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ func d(_ b: String -> <T>() -> T) {} // expected-error {{expected type for funct
6767

6868

6969
// <rdar://problem/22143680> QoI: terrible diagnostic when trying to form a generic protocol
70-
protocol Animal<Food> { // expected-error {{protocols do not allow generic parameters; use associated types instead}}
70+
protocol Animal<Food> { // expected-error {{an associated type named 'Food' must be declared in the protocol 'Animal' or a protocol it inherits}}
7171
func feed(_ food: Food) // expected-error {{cannot find type 'Food' in scope}}
7272
}
7373

test/SILGen/existential_parameters.swift renamed to test/SILGen/parameterized_existentials.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-emit-silgen -module-name parameterized -enable-parameterized-protocol-types %s | %FileCheck %s
1+
// RUN: %target-swift-emit-silgen -module-name parameterized -enable-parameterized-existential-types %s | %FileCheck %s
22

33
protocol P<T, U, V> {
44
associatedtype T

test/SILOptimizer/cast_folding_parameterized_protocol.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-frontend %s -emit-sil -enable-parameterized-protocol-types -O -o - | %FileCheck %s
1+
// RUN: %target-swift-frontend %s -emit-sil -enable-parameterized-existential-types -O -o - | %FileCheck %s
22

33
public protocol P<T> {
44
associatedtype T

test/type/opaque_parameters.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-typecheck-verify-swift -enable-parameterized-protocol-types -disable-availability-checking -requirement-machine-inferred-signatures=on
1+
// RUN: %target-typecheck-verify-swift -disable-availability-checking -requirement-machine-inferred-signatures=on
22

33
protocol P { }
44

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// RUN: %target-typecheck-verify-swift -requirement-machine-protocol-signatures=on -requirement-machine-inferred-signatures=on -disable-availability-checking -enable-parameterized-existential-types
2+
3+
protocol Sequence<Element> {
4+
associatedtype Element
5+
}
6+
7+
struct ConcreteSequence<Element> : Sequence {}
8+
9+
extension Sequence {
10+
func map<Other>(_ transform: (Self.Element) -> Other) -> ConcreteSequence<Other> {
11+
return ConcreteSequence<Other>()
12+
}
13+
}
14+
15+
protocol DoubleWide<X, Y> {
16+
associatedtype X
17+
associatedtype Y
18+
19+
var x: X { get }
20+
var y: Y { get }
21+
}
22+
23+
extension Int: DoubleWide {
24+
typealias X = Int
25+
typealias Y = Int
26+
27+
var x: X { 0 }
28+
var y: X { 0 }
29+
}
30+
31+
struct Collapse<T: DoubleWide>: DoubleWide {
32+
typealias X = T
33+
typealias Y = T
34+
35+
var x: X
36+
var y: X { self.x }
37+
}
38+
39+
func test() -> any DoubleWide<some DoubleWide<Int, Int>, some DoubleWide<Int, Int>> { return Collapse<Int>(x: 42) }
40+
41+
func diagonalizeAny(_ x: any Sequence<Int>) -> any Sequence<(Int, Int)> {
42+
return x.map { ($0, $0) }
43+
}
44+
45+
func erase<T>(_ x: ConcreteSequence<T>) -> any Sequence<T> {
46+
return x as any Sequence<T>
47+
}
48+
49+
protocol Sponge<A, B> {
50+
associatedtype A
51+
associatedtype B
52+
}
53+
54+
func saturation(_ dry: any Sponge, _ wet: any Sponge<Int, Int>) {
55+
_ = dry as any Sponge<Int, Int>
56+
// expected-error@-1 {{'any Sponge' is not convertible to 'any Sponge<Int, Int>'}}
57+
// expected-note@-2 {{did you mean to use 'as!' to force downcast?}}
58+
_ = dry as any Sponge
59+
60+
_ = wet as any Sponge<Int, Int> // Ok
61+
_ = wet as any Sponge // Ok
62+
_ = wet as any Sponge<String, String> // expected-error {{'any Sponge<Int, Int>' is not convertible to 'any Sponge<String, String>'}}
63+
// expected-note@-1 {{did you mean to use 'as!' to force downcast?}}
64+
}

test/type/parameterized_protocol.swift

Lines changed: 7 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
// RUN: %target-typecheck-verify-swift -requirement-machine-protocol-signatures=on -requirement-machine-inferred-signatures=on -enable-parameterized-protocol-types -disable-availability-checking
1+
// RUN: %target-typecheck-verify-swift -requirement-machine-protocol-signatures=on -requirement-machine-inferred-signatures=on -disable-availability-checking
22

3-
// RUN: not %target-swift-frontend -typecheck %s -debug-generic-signatures -requirement-machine-protocol-signatures=on -enable-parameterized-protocol-types -requirement-machine-inferred-signatures=on -disable-availability-checking 2>&1 | %FileCheck %s
3+
// RUN: not %target-swift-frontend -typecheck %s -debug-generic-signatures -requirement-machine-protocol-signatures=on -requirement-machine-inferred-signatures=on -disable-availability-checking 2>&1 | %FileCheck %s
44

55

66
/// Test some invalid syntax first
@@ -189,12 +189,17 @@ func returnsSequenceOfInt1() -> Sequence<Int> {}
189189
// expected-error@-1 {{protocol type with type arguments can only be used as a generic constraint}}
190190

191191
func takesSequenceOfInt2(_: any Sequence<Int>) {}
192+
// expected-error@-1 {{protocol type with type arguments can only be used as a generic constraint}}
192193

193194
func returnsSequenceOfInt2() -> any Sequence<Int> {}
195+
// expected-error@-1 {{protocol type with type arguments can only be used as a generic constraint}}
194196

195197
func typeExpr() {
196198
_ = Sequence<Int>.self
197199
// expected-error@-1 {{protocol type with type arguments can only be used as a generic constraint}}
200+
201+
_ = any Sequence<Int>.self
202+
// expected-error@-1 {{protocol type with type arguments can only be used as a generic constraint}}
198203
}
199204

200205
/// Not supported as a protocol composition term for now
@@ -203,56 +208,3 @@ protocol SomeProto {}
203208

204209
func protocolCompositionNotSupported(_: SomeProto & Sequence<Int>) {}
205210
// expected-error@-1 {{non-protocol, non-class type 'Sequence<Int>' cannot be used within a protocol-constrained type}}
206-
207-
/// More regression tests
208-
209-
protocol DoubleWide<X, Y> {
210-
associatedtype X
211-
associatedtype Y
212-
213-
var x: X { get }
214-
var y: Y { get }
215-
}
216-
217-
extension Int: DoubleWide {
218-
typealias X = Int
219-
typealias Y = Int
220-
221-
var x: X { 0 }
222-
var y: X { 0 }
223-
}
224-
225-
struct Collapse<T: DoubleWide>: DoubleWide {
226-
typealias X = T
227-
typealias Y = T
228-
229-
var x: X
230-
var y: X { self.x }
231-
}
232-
233-
func test() -> any DoubleWide<some DoubleWide<Int, Int>, some DoubleWide<Int, Int>> { return Collapse<Int>(x: 42) }
234-
235-
func diagonalizeAny(_ x: any Sequence<Int>) -> any Sequence<(Int, Int)> {
236-
return x.map { ($0, $0) }
237-
}
238-
239-
func erase<T>(_ x: ConcreteSequence<T>) -> any Sequence<T> {
240-
return x as any Sequence<T>
241-
}
242-
243-
protocol Sponge<A, B> {
244-
associatedtype A
245-
associatedtype B
246-
}
247-
248-
func saturation(_ dry: any Sponge, _ wet: any Sponge<Int, Int>) {
249-
_ = dry as any Sponge<Int, Int>
250-
// expected-error@-1 {{'any Sponge' is not convertible to 'any Sponge<Int, Int>'}}
251-
// expected-note@-2 {{did you mean to use 'as!' to force downcast?}}
252-
_ = dry as any Sponge
253-
254-
_ = wet as any Sponge<Int, Int> // Ok
255-
_ = wet as any Sponge // Ok
256-
_ = wet as any Sponge<String, String> // expected-error {{'any Sponge<Int, Int>' is not convertible to 'any Sponge<String, String>'}}
257-
// expected-note@-1 {{did you mean to use 'as!' to force downcast?}}
258-
}

validation-test/compiler_crashers_2_fixed/unsupported_recursive_opaque_conformance.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-frontend -disable-availability-checking -emit-ir -enable-parameterized-protocol-types %s
1+
// RUN: %target-swift-frontend -disable-availability-checking -emit-ir -enable-parameterized-existential-types %s
22

33
protocol P<X, Y> {
44
associatedtype X : P

0 commit comments

Comments
 (0)