Skip to content

Commit

Permalink
Merge pull request #41996 from DougGregor/implicit-open-by-default
Browse files Browse the repository at this point in the history
[SE-0352] Implicit opening of existentials by default
  • Loading branch information
DougGregor authored Apr 21, 2022
2 parents d0950d1 + c76a99b commit 3316cf0
Show file tree
Hide file tree
Showing 11 changed files with 44 additions and 23 deletions.
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,28 @@ _**Note:** This is in reverse chronological order, so newer entries are added to

## Swift 5.7

* [SE-0352][]:

It's now possible to call a generic function with a value of protocol type
in places that would previously fail because `any` types do not conform
to their protocols. For example:

```
protocol P {
associatedtype A
func getA() -> A
}
func takeP<T: P>(_ value: T) { }
func test(p: any P) {
takeP(p) // was an error "type 'any P' cannot conform to 'P'", now accepted
}
```

This operates by "opening" the value of protocol type and passing the
underlying type directly to the generic function.

* [SE-0347][]:

It's now possible to use a default value expression with a generic parameter type
Expand Down Expand Up @@ -9162,6 +9184,7 @@ Swift 1.0
[SE-0345]: <https://github.com/apple/swift-evolution/blob/main/proposals/0345-if-let-shorthand.md>
[SE-0326]: <https://github.com/apple/swift-evolution/blob/main/proposals/0326-extending-multi-statement-closure-inference.md>
[SE-0347]: <https://github.com/apple/swift-evolution/blob/main/proposals/0347-type-inference-from-default-exprs.md>
[SE-0352]: <https://github.com/apple/swift-evolution/blob/main/proposals/0352-implicit-open-existentials.md>

[SR-75]: <https://bugs.swift.org/browse/SR-75>
[SR-106]: <https://bugs.swift.org/browse/SR-106>
Expand Down
2 changes: 1 addition & 1 deletion lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
Opts.EnableOpenedExistentialTypes =
Args.hasFlag(OPT_enable_experimental_opened_existential_types,
OPT_disable_experimental_opened_existential_types,
false);
true);

Opts.EnableExperimentalVariadicGenerics |=
Args.hasArg(OPT_enable_experimental_variadic_generics);
Expand Down
2 changes: 1 addition & 1 deletion test/Generics/existential_restrictions.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %target-typecheck-verify-swift -enable-objc-interop
// RUN: %target-typecheck-verify-swift -enable-objc-interop -disable-experimental-opened-existential-types

protocol P { }
@objc protocol OP { }
Expand Down
4 changes: 2 additions & 2 deletions test/RemoteAST/existentials.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,6 @@ printDynamicTypeAndAddressForExistential(q)
// Case five: existential metatypes.
// CHECK-NEXT: Any.Type
let metatype : Any.Type = Any.self
printDynamicTypeAndAddressForExistential(metatype)
printDynamicTypeAndAddressForExistential(metatype as Any.Type)
stopRemoteAST()
stopRemoteAST()
6 changes: 3 additions & 3 deletions test/SILGen/builtins.swift
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ func class_archetype_to_native_object<T : C>(_ t: T) -> Builtin.NativeObject {
// CHECK-NEXT: [[PTR:%[0-9]+]] = unchecked_ref_cast [[REF]] : $@opened({{.*}}) ClassProto to $Builtin.NativeObject
// CHECK-NEXT: return [[PTR]]
func class_existential_to_native_object(_ t:ClassProto) -> Builtin.NativeObject {
return Builtin.unsafeCastToNativeObject(t)
return Builtin.unsafeCastToNativeObject(t as ClassProto)
}

// CHECK-LABEL: sil hidden [ossa] @$s8builtins24class_from_native_object{{[_0-9a-zA-Z]*}}F
Expand Down Expand Up @@ -718,7 +718,7 @@ func refcast_class_any(_ o: A) -> AnyObject {
// CHECK-LABEL: sil hidden [ossa] @$s8builtins20refcast_punknown_any{{[_0-9a-zA-Z]*}}F
// CHECK: unchecked_ref_cast_addr PUnknown in %{{.*}} : $*PUnknown to AnyObject in %{{.*}} : $*AnyObject
func refcast_punknown_any(_ o: PUnknown) -> AnyObject {
return Builtin.castReference(o)
return Builtin.castReference(o as PUnknown)
}

// CHECK-LABEL: sil hidden [ossa] @$s8builtins18refcast_pclass_anyyyXlAA6PClass_pF :
Expand All @@ -728,7 +728,7 @@ func refcast_punknown_any(_ o: PUnknown) -> AnyObject {
// CHECK: return [[ARG_CAST]]
// CHECK: } // end sil function '$s8builtins18refcast_pclass_anyyyXlAA6PClass_pF'
func refcast_pclass_any(_ o: PClass) -> AnyObject {
return Builtin.castReference(o)
return Builtin.castReference(o as PClass)
}

// CHECK-LABEL: sil hidden [ossa] @$s8builtins20refcast_any_punknown{{[_0-9a-zA-Z]*}}F
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ protocol Q: P { }

@inline(never) func sink<T>(_ x: T) {}

func p<T: Q>(_ x: T) { sink(x.p()) }
func p<T: Q>(_ x: T) { sink(x.p() as Any.Type) }

class Foo<T>: Q { func p() -> Any.Type { return T.self } }
class Bar<T>: Foo<T> {}
Expand Down
18 changes: 10 additions & 8 deletions test/decl/protocol/conforms/error_self_conformance.swift
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
// RUN: %target-typecheck-verify-swift

func wantsError<T: Error>(_: T) {}
// expected-note@-1 {{required by global function 'wantsError' where 'T' = 'any ErrorRefinement'}}
// expected-note@-2 {{required by global function 'wantsError' where 'T' = 'any Error & OtherProtocol'}}
// expected-note@-3 {{required by global function 'wantsError' where 'T' = 'any C & Error'}}
func opensError<T: Error>(_: T) {}
func wantsError<T: Error>(_: T, _: T) {}
// expected-note@-1 3{{required by global function 'wantsError' where 'T' = 'any}}

func testSimple(error: Error) {
wantsError(error)
opensError(error)
}

protocol ErrorRefinement : Error {}
func testErrorRefinment(error: ErrorRefinement) {
wantsError(error) // expected-error {{type 'any ErrorRefinement' cannot conform to 'Error'}} expected-note {{only concrete types such as structs, enums and classes can conform to protocols}}
opensError(error) // okay
wantsError(error, error) // expected-error {{type 'any ErrorRefinement' cannot conform to 'Error'}} expected-note {{only concrete types such as structs, enums and classes can conform to protocols}}
}

protocol OtherProtocol {}
func testErrorComposition(error: Error & OtherProtocol) {
wantsError(error) // expected-error {{type 'any Error & OtherProtocol' cannot conform to 'Error'}} expected-note {{only concrete types such as structs, enums and classes can conform to protocols}}
opensError(error) // okay
wantsError(error, error) // expected-error {{type 'any Error & OtherProtocol' cannot conform to 'Error'}} expected-note {{only concrete types such as structs, enums and classes can conform to protocols}}
}

class C {}
func testErrorCompositionWithClass(error: Error & C) {
wantsError(error) // expected-error {{type 'any C & Error' cannot conform to 'Error'}} expected-note {{only concrete types such as structs, enums and classes can conform to protocols}}
opensError(error) // okay
wantsError(error, error) // expected-error {{type 'any C & Error' cannot conform to 'Error'}} expected-note {{only concrete types such as structs, enums and classes can conform to protocols}}
}
2 changes: 1 addition & 1 deletion test/stdlib/Runtime.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,7 @@ Runtime.test("abstraction barrier on casting generic param bound to existential"
dynamicWithErasedType,
dynamicExistentialWithErasedType,
dynamicDoubleWrappedExistentialWithErasedType)
= castWithAbstractionBarrier(x)
= castWithAbstractionBarrier(x as SomeProtocol)

expectTrue(staticWithConcreteType == SomeProtocol.self)
expectTrue(dynamicWithConcreteType == SomeProtocol.self)
Expand Down
3 changes: 0 additions & 3 deletions test/type/subclass_composition.swift
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,6 @@ func dependentMemberTypes<T : BaseIntAndP2>(
func conformsToAnyObject<T : AnyObject>(_: T) {}
// expected-note@-1 {{where 'T' = 'any P1'}}
func conformsToP1<T : P1>(_: T) {}
// expected-note@-1 {{required by global function 'conformsToP1' where 'T' = 'any P1'}}
func conformsToP2<T : P2>(_: T) {}
func conformsToBaseIntAndP2<T : Base<Int> & P2>(_: T) {}
// expected-note@-1 {{where 'T' = 'FakeDerived'}}
Expand Down Expand Up @@ -428,8 +427,6 @@ func conformsTo<T1 : P2, T2 : Base<Int> & P2>(
// expected-error@-1 {{global function 'conformsToAnyObject' requires that 'any P1' be a class type}}

conformsToP1(p1)
// expected-error@-1 {{type 'any P1' cannot conform to 'P1'}}
// expected-note@-2 {{only concrete types such as structs, enums and classes can conform to protocols}}

// FIXME: Following diagnostics are not great because when
// `conformsTo*` methods are re-typechecked, they loose information
Expand Down
3 changes: 1 addition & 2 deletions test/type/subclass_composition_objc.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,7 @@ func testSelfConformance(c: ObjCClass, p: ObjCProtocol, cp: ObjCClass & ObjCProt
func takesStaticObjCProtocol<T : StaticObjCProtocol>(_: T) {}

func testSelfConformance(cp: ObjCClass & StaticObjCProtocol) {
takesStaticObjCProtocol(cp)
// expected-error@-1 {{'any ObjCClass & StaticObjCProtocol' cannot be used as a type conforming to protocol 'StaticObjCProtocol' because 'StaticObjCProtocol' has static requirements}}
takesStaticObjCProtocol(cp) // okay because the type is opened
}

func testMetatypeSelfConformance(m1: (ObjCClass & ObjCProtocol).Protocol,
Expand Down
2 changes: 1 addition & 1 deletion validation-test/Reflection/existentials.swift
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,7 @@ protocol Q {}
protocol Composition : P, Q {}
struct S : Composition {}
func getComposition() -> P & Q { return S() }
reflect(any: getComposition())
reflect(any: getComposition() as P & Q)
// CHECK-64: Mangled name: $s12existentials1P_AA1Qp
// CHECK-64: Demangled name: existentials.P & existentials.Q
// CHECK-32: Mangled name: $s12existentials1P_AA1Qp
Expand Down

0 comments on commit 3316cf0

Please sign in to comment.