Skip to content

Cherry-pick latest SE-0346 changes to 5.7 branch #42249

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion include/swift/AST/ASTPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ StringRef getAccessorKindString(AccessorKind value);
/// for the compiler features that it uses. Note that printBody
/// may be called multiple times if the declaration uses suppressible
/// features.
bool printWithCompatibilityFeatureChecks(ASTPrinter &printer,
void printWithCompatibilityFeatureChecks(ASTPrinter &printer,
PrintOptions &options,
Decl *decl,
llvm::function_ref<void()> printBody);
Expand Down
3 changes: 0 additions & 3 deletions include/swift/AST/DiagnosticsParse.def
Original file line number Diff line number Diff line change
Expand Up @@ -378,9 +378,6 @@ ERROR(expected_rbrace_actor,none,
"expected '}' in actor", ())

// Protocol
ERROR(generic_arguments_protocol,PointsToFirstBadToken,
"protocols do not allow generic parameters; use associated types instead",
())
ERROR(expected_lbrace_protocol,PointsToFirstBadToken,
"expected '{' in protocol type", ())
ERROR(expected_rbrace_protocol,none,
Expand Down
2 changes: 1 addition & 1 deletion include/swift/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ LANGUAGE_FEATURE(BuiltinStackAlloc, 0, "Builtin.stackAlloc", true)
SUPPRESSIBLE_LANGUAGE_FEATURE(SpecializeAttributeWithAvailability, 0, "@_specialize attribute with availability", true)
LANGUAGE_FEATURE(BuiltinAssumeAlignment, 0, "Builtin.assumeAlignment", true)
SUPPRESSIBLE_LANGUAGE_FEATURE(UnsafeInheritExecutor, 0, "@_unsafeInheritExecutor", true)
SUPPRESSIBLE_LANGUAGE_FEATURE(PrimaryAssociatedTypes, 0, "Primary associated types", true)
SUPPRESSIBLE_LANGUAGE_FEATURE(PrimaryAssociatedTypes, 346, "Primary associated types", true)
SUPPRESSIBLE_LANGUAGE_FEATURE(UnavailableFromAsync, 0, "@_unavailableFromAsync", true)
SUPPRESSIBLE_LANGUAGE_FEATURE(NoAsyncAvailability, 340, "@available(*, noasync)", true)

Expand Down
6 changes: 3 additions & 3 deletions include/swift/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -330,9 +330,9 @@ namespace swift {
/// in calls to generic functions.
bool EnableOpenedExistentialTypes = false;

/// Enable support for protocol types parameterized by primary
/// associated type.
bool EnableParameterizedProtocolTypes = false;
/// Enable support for parameterized protocol types in existential
/// position.
bool EnableParameterizedExistentialTypes = false;

/// Enable experimental flow-sensitive concurrent captures.
bool EnableExperimentalFlowSensitiveConcurrentCaptures = false;
Expand Down
6 changes: 3 additions & 3 deletions include/swift/Option/FrontendOptions.td
Original file line number Diff line number Diff line change
Expand Up @@ -536,9 +536,9 @@ def enable_explicit_existential_types :
Flag<["-"], "enable-explicit-existential-types">,
HelpText<"Enable experimental support for explicit existential types">;

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

def enable_experimental_opened_existential_types :
Flag<["-"], "enable-experimental-opened-existential-types">,
Expand Down
14 changes: 6 additions & 8 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2588,12 +2588,12 @@ void PrintAST::printSynthesizedExtensionImpl(Type ExtendedType,
// protocol Foo {}
// extension Foo where <requirments from ExtDecl> { ... }
// struct Bar {}
// extension Bar: Foo where <requirments from TransformContext> { ... }
// extension Bar: Foo where <requirements from TransformContext> { ... }
//
// should produce a synthesized extension of Bar with both sets of
// requirments:
// requirements:
//
// extension Bar where <requirments from ExtDecl+TransformContext { ... }
// extension Bar where <requirements from ExtDecl+TransformContext> { ... }
//
if (!printCombinedRequirementsIfNeeded())
printDeclGenericRequirements(ExtDecl);
Expand Down Expand Up @@ -3208,21 +3208,21 @@ static void printWithSuppressibleFeatureChecks(ASTPrinter &printer,
/// #endif
/// #endif
/// ```
bool swift::printWithCompatibilityFeatureChecks(ASTPrinter &printer,
void swift::printWithCompatibilityFeatureChecks(ASTPrinter &printer,
PrintOptions &options,
Decl *decl,
llvm::function_ref<void()> printBody) {
// A single accessor does not get a feature check,
// it should go around the whole decl.
if (isa<AccessorDecl>(decl)) {
printBody();
return false;
return;
}

FeatureSet features = getUniqueFeaturesUsed(decl);
if (features.empty()) {
printBody();
return false;
return;
}

// Enter a `#if` for the required features, if any.
Expand Down Expand Up @@ -3252,8 +3252,6 @@ bool swift::printWithCompatibilityFeatureChecks(ASTPrinter &printer,
printer.printNewline();
printer << "#endif";
}

return true;
}

void PrintAST::visitExtensionDecl(ExtensionDecl *decl) {
Expand Down
4 changes: 2 additions & 2 deletions lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -448,8 +448,8 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
Opts.EnableExperimentalNamedOpaqueTypes |=
Args.hasArg(OPT_enable_experimental_named_opaque_types);

Opts.EnableParameterizedProtocolTypes |=
Args.hasArg(OPT_enable_parameterized_protocol_types);
Opts.EnableParameterizedExistentialTypes |=
Args.hasArg(OPT_enable_parameterized_existential_types);

Opts.EnableOpenedExistentialTypes =
Args.hasFlag(OPT_enable_experimental_opened_existential_types,
Expand Down
13 changes: 2 additions & 11 deletions lib/Frontend/ModuleInterfaceSupport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -650,17 +650,8 @@ class InheritedProtocolCollector {
printer << " {}";
};

bool printedNewline = false;
if (printOptions.PrintCompatibilityFeatureChecks) {
printedNewline =
printWithCompatibilityFeatureChecks(printer, curPrintOptions,
proto, printBody);
} else {
printBody();
printedNewline = false;
}
if (!printedNewline)
printer << "\n";
printBody();
printer << "\n";
}
}

Expand Down
15 changes: 2 additions & 13 deletions lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8062,19 +8062,8 @@ parseDeclProtocol(ParseDeclOptions Flags, DeclAttributes &Attributes) {
return Status;

SmallVector<PrimaryAssociatedTypeName, 2> PrimaryAssociatedTypeNames;

if (Context.LangOpts.EnableParameterizedProtocolTypes) {
if (startsWithLess(Tok)) {
Status |= parsePrimaryAssociatedTypes(PrimaryAssociatedTypeNames);
}
} else {
// Protocols don't support generic parameters, but people often want them and
// we want to have good error recovery if they try them out. Parse them and
// produce a specific diagnostic if present.
if (startsWithLess(Tok)) {
diagnose(Tok, diag::generic_arguments_protocol);
maybeParseGenericParams();
}
if (startsWithLess(Tok)) {
Status |= parsePrimaryAssociatedTypes(PrimaryAssociatedTypeNames);
}

DebuggerContextChange DCC (*this);
Expand Down
68 changes: 33 additions & 35 deletions lib/Sema/TypeCheckType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -628,50 +628,48 @@ static Type applyGenericArguments(Type type, TypeResolution resolution,
auto &ctx = dc->getASTContext();
auto &diags = ctx.Diags;

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

auto *protoDecl = protoType->getDecl();
auto assocTypes = protoDecl->getPrimaryAssociatedTypes();
if (assocTypes.empty()) {
diags.diagnose(loc, diag::protocol_does_not_have_primary_assoc_type,
protoType);
auto *protoDecl = protoType->getDecl();
auto assocTypes = protoDecl->getPrimaryAssociatedTypes();
if (assocTypes.empty()) {
diags.diagnose(loc, diag::protocol_does_not_have_primary_assoc_type,
protoType);

return ErrorType::get(ctx);
}

auto genericArgs = generic->getGenericArgs();
return ErrorType::get(ctx);
}

if (genericArgs.size() != assocTypes.size()) {
diags.diagnose(loc,
diag::parameterized_protocol_type_argument_count_mismatch,
protoType, genericArgs.size(), assocTypes.size(),
(genericArgs.size() < assocTypes.size()) ? 1 : 0);
auto genericArgs = generic->getGenericArgs();

return ErrorType::get(ctx);
}
if (genericArgs.size() != assocTypes.size()) {
diags.diagnose(loc,
diag::parameterized_protocol_type_argument_count_mismatch,
protoType, genericArgs.size(), assocTypes.size(),
(genericArgs.size() < assocTypes.size()) ? 1 : 0);

auto genericResolution =
resolution.withOptions(adjustOptionsForGenericArgs(options));
return ErrorType::get(ctx);
}

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

argTys.push_back(argTy);
}
SmallVector<Type, 2> argTys;
for (auto *genericArg : genericArgs) {
Type argTy = genericResolution.resolveType(genericArg, silParams);
if (!argTy || argTy->hasError())
return ErrorType::get(ctx);

return ParameterizedProtocolType::get(ctx, protoType, argTys);
argTys.push_back(argTy);
}

return ParameterizedProtocolType::get(ctx, protoType, argTys);
}

// We must either have an unbound generic type, or a generic type alias.
Expand Down
9 changes: 7 additions & 2 deletions lib/Sema/TypeCheckType.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "swift/AST/Type.h"
#include "swift/AST/Types.h"
#include "swift/AST/TypeResolutionStage.h"
#include "swift/Basic/LangOptions.h"
#include "llvm/ADT/None.h"

namespace swift {
Expand Down Expand Up @@ -277,13 +278,17 @@ class TypeResolutionOptions {
}

/// Whether parameterized protocol types are supported in this context.
bool isParameterizedProtocolSupported() const {
///
/// FIXME: Remove LangOptions parameter once EnableParameterizedExistentialTypes
/// staging flag is gone.
bool isParameterizedProtocolSupported(const LangOptions &opts) const {
switch (context) {
case Context::Inherited:
case Context::ExtensionBinding:
case Context::GenericRequirement:
case Context::ExistentialConstraint:
return true;
case Context::ExistentialConstraint:
return opts.EnableParameterizedExistentialTypes;
case Context::None:
case Context::TypeAliasDecl:
case Context::GenericTypeAliasDecl:
Expand Down
2 changes: 1 addition & 1 deletion test/Constraints/opened_existentials.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %target-typecheck-verify-swift -enable-experimental-opened-existential-types -enable-parameterized-protocol-types
// RUN: %target-typecheck-verify-swift -enable-experimental-opened-existential-types

protocol Q { }

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend -typecheck -module-name ParameterizedProtocols -emit-module-interface-path %t/ParameterizedProtocols.swiftinterface %s
// RUN: %FileCheck %s < %t/ParameterizedProtocols.swiftinterface

public struct S1 : P1 {
public typealias T = Int
}

public struct S2 : Q1 {}

protocol P1 : P2 {}

public protocol P2<T> {
associatedtype T
}

protocol Q1 : Q2 {}

public protocol Q2 {}

// CHECK: extension ParameterizedProtocols.S1 : ParameterizedProtocols.P2 {}
// CHECK-NEXT: extension ParameterizedProtocols.S2 : ParameterizedProtocols.Q2 {}
2 changes: 1 addition & 1 deletion test/ModuleInterface/parameterized-protocols.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend -typecheck -module-name ParameterizedProtocols -emit-module-interface-path %t/ParameterizedProtocols.swiftinterface -enable-parameterized-protocol-types %s
// RUN: %target-swift-frontend -typecheck -module-name ParameterizedProtocols -emit-module-interface-path %t/ParameterizedProtocols.swiftinterface %s
// RUN: %FileCheck %s < %t/ParameterizedProtocols.swiftinterface

public protocol HasPrimaryAssociatedTypes<T, U> {
Expand Down
2 changes: 1 addition & 1 deletion test/Parse/invalid.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func d(_ b: String -> <T>() -> T) {} // expected-error {{expected type for funct


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

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %target-swift-emit-silgen -module-name parameterized -enable-parameterized-protocol-types %s | %FileCheck %s
// RUN: %target-swift-emit-silgen -module-name parameterized -enable-parameterized-existential-types %s | %FileCheck %s

protocol P<T, U, V> {
associatedtype T
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %target-swift-frontend %s -emit-sil -enable-parameterized-protocol-types -O -o - | %FileCheck %s
// RUN: %target-swift-frontend %s -emit-sil -enable-parameterized-existential-types -O -o - | %FileCheck %s

public protocol P<T> {
associatedtype T
Expand Down
2 changes: 1 addition & 1 deletion test/type/opaque_parameters.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %target-typecheck-verify-swift -enable-parameterized-protocol-types -disable-availability-checking -requirement-machine-inferred-signatures=on
// RUN: %target-typecheck-verify-swift -disable-availability-checking -requirement-machine-inferred-signatures=on

protocol P { }

Expand Down
64 changes: 64 additions & 0 deletions test/type/parameterized_existential.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// RUN: %target-typecheck-verify-swift -requirement-machine-protocol-signatures=on -requirement-machine-inferred-signatures=on -disable-availability-checking -enable-parameterized-existential-types

protocol Sequence<Element> {
associatedtype Element
}

struct ConcreteSequence<Element> : Sequence {}

extension Sequence {
func map<Other>(_ transform: (Self.Element) -> Other) -> ConcreteSequence<Other> {
return ConcreteSequence<Other>()
}
}

protocol DoubleWide<X, Y> {
associatedtype X
associatedtype Y

var x: X { get }
var y: Y { get }
}

extension Int: DoubleWide {
typealias X = Int
typealias Y = Int

var x: X { 0 }
var y: X { 0 }
}

struct Collapse<T: DoubleWide>: DoubleWide {
typealias X = T
typealias Y = T

var x: X
var y: X { self.x }
}

func test() -> any DoubleWide<some DoubleWide<Int, Int>, some DoubleWide<Int, Int>> { return Collapse<Int>(x: 42) }

func diagonalizeAny(_ x: any Sequence<Int>) -> any Sequence<(Int, Int)> {
return x.map { ($0, $0) }
}

func erase<T>(_ x: ConcreteSequence<T>) -> any Sequence<T> {
return x as any Sequence<T>
}

protocol Sponge<A, B> {
associatedtype A
associatedtype B
}

func saturation(_ dry: any Sponge, _ wet: any Sponge<Int, Int>) {
_ = dry as any Sponge<Int, Int>
// expected-error@-1 {{'any Sponge' is not convertible to 'any Sponge<Int, Int>'}}
// expected-note@-2 {{did you mean to use 'as!' to force downcast?}}
_ = dry as any Sponge

_ = wet as any Sponge<Int, Int> // Ok
_ = wet as any Sponge // Ok
_ = wet as any Sponge<String, String> // expected-error {{'any Sponge<Int, Int>' is not convertible to 'any Sponge<String, String>'}}
// expected-note@-1 {{did you mean to use 'as!' to force downcast?}}
}
Loading