Skip to content

Enable SE-0341 "Opaque Parameter Declarations" by default. #41444

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 2 commits into from
Feb 18, 2022
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
30 changes: 30 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,35 @@ _**Note:** This is in reverse chronological order, so newer entries are added to

## Swift 5.7

* [SE-0341][]:

Opaque types can now be used in the parameters of functions and subscripts, wher they provide a shorthand syntax for the introduction of a generic parameter. For example, the following:

```swift
func horizontal(_ v1: some View, _ v2: some View) -> some View {
HStack {
v1
v2
}
}
```

is equivalent to

```swift
func horizontal<V1: View, V2: View>(_ v1: V1, _ v2: V2) -> some View {
HStack {
v1
v2
}
}
```

With this, `some` in a parameter type provides a generalization where the
caller chooses the parameter's type as well as its value, whereas `some` in
the result type provides a generalization where the callee chooses the
resulting type and value.

* The compiler now correctly emits warnings for more kinds of expressions where a protocol conformance is used and may be unavailable at runtime. Previously, member reference expressions and type erasing expressions that used potentially unavailable conformances were not diagnosed, leading to potential crashes at runtime.

```swift
Expand Down Expand Up @@ -8962,6 +8991,7 @@ Swift 1.0
[SE-0331]: <https://github.com/apple/swift-evolution/blob/main/proposals/0331-remove-sendable-from-unsafepointer.md>
[SE-0337]: <https://github.com/apple/swift-evolution/blob/main/proposals/0337-support-incremental-migration-to-concurrency-checking.md>
[SE-0335]: <https://github.com/apple/swift-evolution/blob/main/proposals/0335-existential-any.md>
[SE-0341]: <https://github.com/apple/swift-evolution/blob/main/proposals/0341-opaque-parameters.md>

[SR-75]: <https://bugs.swift.org/browse/SR-75>
[SR-106]: <https://bugs.swift.org/browse/SR-106>
Expand Down
8 changes: 4 additions & 4 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -4988,7 +4988,7 @@ ERROR(unable_to_parse_c_function_type,none,

// Opaque types
ERROR(unsupported_opaque_type,none,
"'some' types are only implemented for the declared type of properties and subscripts and the return type of functions", ())
"'some' types are only permitted in properties, subscripts, and functions", ())

ERROR(opaque_type_unsupported_pattern,none,
"'some' type can only be declared on a single property declaration", ())
Expand All @@ -4997,9 +4997,9 @@ ERROR(opaque_type_in_protocol_requirement,none,
"'some' type cannot be the return type of a protocol requirement; did you mean to add an associated type?",
())
ERROR(opaque_type_in_parameter,none,
"'some' cannot appear in parameter position in result "
"type %0",
(Type))
"'some' cannot appear in parameter position in %select{result|parameter}0"
" type %1",
(bool, Type))

// Function differentiability
ERROR(attr_only_on_parameters_of_differentiable,none,
Expand Down
4 changes: 0 additions & 4 deletions include/swift/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -313,10 +313,6 @@ namespace swift {
/// `func f() -> <T> T`.
bool EnableExperimentalNamedOpaqueTypes = false;

/// Enable experimental support for opaque parameter types, e.g.
/// `func f(collection: some Collection)`.
bool EnableExperimentalOpaqueParameters = false;

/// Enable support for explicit existential types via the \c any
/// keyword.
bool EnableExplicitExistentialTypes = true;
Expand Down
4 changes: 0 additions & 4 deletions include/swift/Option/FrontendOptions.td
Original file line number Diff line number Diff line change
Expand Up @@ -296,10 +296,6 @@ def enable_experimental_eager_clang_module_diagnostics :
Flag<["-"], "enable-experimental-eager-clang-module-diagnostics">,
HelpText<"Enable experimental eager diagnostics reporting on the importability of all referenced C, C++, and Objective-C libraries">;

def enable_experimental_opaque_parameters :
Flag<["-"], "enable-experimental-opaque-parameters">,
HelpText<"Enable experimental support for opaque parameters">;

def enable_experimental_pairwise_build_block :
Flag<["-"], "enable-experimental-pairwise-build-block">,
HelpText<"Enable experimental pairwise 'buildBlock' for result builders">;
Expand Down
3 changes: 0 additions & 3 deletions lib/AST/NameLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2507,9 +2507,6 @@ static SmallVector<GenericTypeParamDecl *, 2>
createOpaqueParameterGenericParams(
GenericContext *genericContext, GenericParamList *parsedGenericParams) {
ASTContext &ctx = genericContext->getASTContext();
if (!ctx.LangOpts.EnableExperimentalOpaqueParameters)
return { };

auto value = dyn_cast_or_null<ValueDecl>(genericContext->getAsDecl());
if (!value)
return { };
Expand Down
3 changes: 0 additions & 3 deletions lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -445,9 +445,6 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
Opts.EnableExperimentalNamedOpaqueTypes |=
Args.hasArg(OPT_enable_experimental_named_opaque_types);

Opts.EnableExperimentalOpaqueParameters |=
Args.hasArg(OPT_enable_experimental_opaque_parameters);

Opts.EnableExplicitExistentialTypes |=
Args.hasArg(OPT_enable_explicit_existential_types);

Expand Down
38 changes: 38 additions & 0 deletions lib/Sema/TypeCheckDeclPrimary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3251,6 +3251,44 @@ void TypeChecker::checkParameterList(ParameterList *params,
}
}

// Opaque types cannot occur in parameter position.
Type interfaceType = param->getInterfaceType();
if (interfaceType->hasTypeParameter()) {
interfaceType.findIf([&](Type type) {
if (auto fnType = type->getAs<FunctionType>()) {
for (auto innerParam : fnType->getParams()) {
auto paramType = innerParam.getPlainType();
if (!paramType->hasTypeParameter())
continue;

bool hadError = paramType.findIf([&](Type innerType) {
auto genericParam = innerType->getAs<GenericTypeParamType>();
if (!genericParam)
return false;

auto genericParamDecl = genericParam->getDecl();
if (!genericParamDecl)
return false;

if (!genericParamDecl->isOpaqueType())
return false;

param->diagnose(
diag::opaque_type_in_parameter, true, interfaceType);
return true;
});

if (hadError)
return true;
}

return false;
}

return false;
});
}

if (param->hasAttachedPropertyWrapper())
(void) param->getPropertyWrapperInitializerInfo();

Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/TypeCheckGeneric.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ OpaqueResultTypeRequest::evaluate(Evaluator &evaluator,

ctx.Diags.diagnose(repr->getLoc(),
diag::opaque_type_in_parameter,
interfaceType);
false, interfaceType);
return true;
}
}
Expand Down
12 changes: 6 additions & 6 deletions test/type/opaque.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,23 +73,23 @@ struct Test {
let inferredOpaqueStructural2 = (bar(), bas()) // expected-error{{inferred type}}
}

let zingle = {() -> some P in 1 } // expected-error{{'some' types are only implemented}}
let zingle = {() -> some P in 1 } // expected-error{{'some' types are only permitted}}


func twoOpaqueTypes() -> (some P, some P) { return (1, 2) }
func asArrayElem() -> [some P] { return [1] }

// Invalid positions

typealias Foo = some P // expected-error{{'some' types are only implemented}}
typealias Foo = some P // expected-error{{'some' types are only permitted}}

func blibble(blobble: some P) {} // expected-error{{'some' types are only implemented}}
func blibble(blobble: some P) {}
func blib() -> P & some Q { return 1 } // expected-error{{'some' should appear at the beginning}}
func blab() -> some P? { return 1 } // expected-error{{must specify only}} expected-note{{did you mean to write an optional of an 'opaque' type?}}
func blorb<T: some P>(_: T) { } // expected-error{{'some' types are only implemented}}
func blub<T>() -> T where T == some P { return 1 } // expected-error{{'some' types are only implemented}} expected-error{{cannot convert}}
func blorb<T: some P>(_: T) { } // expected-error{{'some' types are only permitted}}
func blub<T>() -> T where T == some P { return 1 } // expected-error{{'some' types are only permitted}} expected-error{{cannot convert}}

protocol OP: some P {} // expected-error{{'some' types are only implemented}}
protocol OP: some P {} // expected-error{{'some' types are only permitted}}

func foo() -> some P {
let x = (some P).self // expected-error*{{}}
Expand Down
9 changes: 8 additions & 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-experimental-opaque-parameters -enable-parameterized-protocol-types -disable-availability-checking
// RUN: %target-typecheck-verify-swift -enable-parameterized-protocol-types -disable-availability-checking

protocol P { }

Expand Down Expand Up @@ -102,3 +102,10 @@ func testPrimaries(
_ = takeMatchedPrimaryCollections(arrayOfInts, setOfInts)
_ = takeMatchedPrimaryCollections(arrayOfInts, setOfStrings) // expected-error{{type of expression is ambiguous without more context}}
}


// Prohibit use of opaque parameters in consuming positions.
typealias FnType<T> = (T) -> Void

func consumingA(fn: (some P) -> Void) { } // expected-error{{'some' cannot appear in parameter position in parameter type '(some P) -> Void'}}
func consumingB(fn: FnType<some P>) { } // expected-error{{'some' cannot appear in parameter position in parameter type '(some P) -> Void'}}