SILGen: Emit default arguments as "delayed arguments".

This causes default arguments to get emitted after formal evaluation of `self`, allowing protocol methods to access the opened `Self` type of an existential receiver. Fixes rdar://problem/39524104
This commit is contained in:
Joe Groff
2018-04-30 18:07:36 -07:00
parent b8dc2d2dff
commit fce4988dd0
6 changed files with 607 additions and 479 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,39 @@
// RUN: %target-swift-frontend -emit-sil -verify %s
//
// Make sure neither rdar://problem/37031037 (default arguments on protocol extension methods
// depend on Self and normally get evaluated before an existential self value
// gets opened) nor rdar://problem/39524104 (if you open the existential self
// earlier in an attempt to fix this, then you get undesirable exclusivity
// conflicts on constructs like `existential.x = existential.y`) regress.
//
protocol MethodWithDefaultArgGenerator {
var a: Int { get set }
var b: Int { get nonmutating set }
mutating func mutate(_ x: inout Int)
}
protocol P { static var value: Self { get } }
extension Int: P { static var value: Int { return 0 } }
extension MethodWithDefaultArgGenerator {
mutating func foo(_ x: Int = 0) {}
mutating func reabstracted<T>(_ x: T.Type = T.self) -> T { fatalError() }
mutating func indirected<T: P>(_ x: T = T.value) -> T { fatalError() }
mutating func exploded(x y: (Int, String) = (0, "foo")) {}
}
func invokeMethodsWithDefaultArgs(x: inout MethodWithDefaultArgGenerator) {
x.foo()
_ = x.reabstracted() as Int
_ = x.indirected() as Int
x.exploded()
}
func checkAgainstExclusivityViolations(x: inout MethodWithDefaultArgGenerator) {
x.a = x.a
x.mutate(&x.b)
}

View File

@@ -14,9 +14,9 @@ func variadicSecond(_ x: Int, _ y: Int...) {}
var x = 0
// CHECK: [[X_ADDR:%.*]] = global_addr @$S20scalar_to_tuple_args1xSivp : $*Int
// CHECK: [[WRITE:%.*]] = begin_access [modify] [dynamic] [[X_ADDR]] : $*Int
// CHECK: [[DEFAULT_Y:%.*]] = apply {{.*}} : $@convention(thin) () -> Int
// CHECK: [[DEFAULT_Z:%.*]] = apply {{.*}} : $@convention(thin) () -> Int
// CHECK: [[WRITE:%.*]] = begin_access [modify] [dynamic] [[X_ADDR]] : $*Int
// CHECK: [[INOUT_WITH_DEFAULTS:%.*]] = function_ref @$S20scalar_to_tuple_args17inoutWithDefaults_1y1zySiz_S2itF
// CHECK: apply [[INOUT_WITH_DEFAULTS]]([[WRITE]], [[DEFAULT_Y]], [[DEFAULT_Z]])
inoutWithDefaults(&x)

View File

@@ -970,12 +970,12 @@ struct StructWithLayout {
// CHECK: [[PROJ:%.*]] = project_box %{{.*}} : ${ var StructWithLayout }, 0
// CHECK: [[PA:%.*]] = partial_apply [callee_guaranteed] %{{.*}}([[PROJ]]) : $@convention(thin) (@inout_aliasable StructWithLayout) -> Bool
// CHECK: [[CLOSURE:%.*]] = convert_escape_to_noescape [not_guaranteed] [[PA]] : $@callee_guaranteed () -> Bool to $@noescape @callee_guaranteed () -> Bool
// call default argument
// CHECK: apply %{{.*}}() : $@convention(thin) () -> StaticString
// call StaticString.init
// CHECK: apply
// call UInt.init(_builtinIntegerLiteral:)
// CHECK: apply
// call default argument
// CHECK: apply %{{.*}}() : $@convention(thin) () -> StaticString
// call _sanityCheck(_:_:file:line:)
// CHECK: apply %{{.*}}([[CLOSURE]], {{.*}})
// CHECK: load [trivial] [[PROJ]] : $*StructWithLayout

View File

@@ -2,8 +2,7 @@
// RUN: %target-swift-frontend -enforce-exclusivity=none -emit-sil -Onone %s -o %t/Onone.sil
// RUN: %target-sil-opt %t/Onone.sil -inline -assume-parsing-unqualified-ownership-sil -o %t/inlined.sil
// RUN: %FileCheck %s --check-prefix=INLINE < %t/inlined.sil
// RUN: not %target-sil-opt -enable-sil-verify-all %t/inlined.sil -enforce-exclusivity=unchecked -diagnose-static-exclusivity -assume-parsing-unqualified-ownership-sil -o /dev/null 2> %t/err.txt
// RUN: %FileCheck %s --check-prefix=DIAGNOSE < %t/err.txt
// RUN: %target-sil-opt -enable-sil-verify-all %t/inlined.sil -enforce-exclusivity=unchecked -diagnose-static-exclusivity -assume-parsing-unqualified-ownership-sil -o /dev/null
public protocol SomeP {
var someV: Int { get set }
@@ -23,15 +22,10 @@ struct Some : SomeP {
//
// INLINE-LABEL: $S5Onone16testNestedAccessyyF
// INLINE: [[OUTER:%.*]] = begin_access [modify] [static] %0 : $*SomeP
// INLINE: [[INNERREAD:%.*]] = begin_access [read] [static] [[OUTER]] : $*SomeP
// INLINE: [[INNERMOD:%.*]] = begin_access [modify] [static] [[OUTER]] : $*SomeP
// INLINE: %{{.*}} = open_existential_addr mutable_access [[INNERMOD]] : $*SomeP to $*@opened("{{.*}}") SomeP
// INLINE: [[INNERREAD:%.*]] = begin_access [read] [static] [[OUTER]] : $*SomeP
//
// DIAGNOSE: error: overlapping accesses, but modification requires exclusive access; consider copying to a local variable
// DIAGNOSE: %{{.*}} = begin_access [modify] [static] %0 : $*SomeP
// DIAGNOSE: %{{.*}} = begin_access [read] [static] %0 : $*SomeP
// DIAGNOSE: %{{.*}} = begin_access [modify] [static] %{{.*}} : $*SomeP
// DIAGNOSE: %{{.*}} = begin_access [read] [static] %{{.*}} : $*SomeP
public func testNestedAccess() {
var s: SomeP = Some()
assignNonConflict(&s)