diff --git a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyKeyPath.swift b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyKeyPath.swift index 2e3cd1da7b888..fdef7e2f28349 100644 --- a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyKeyPath.swift +++ b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyKeyPath.swift @@ -31,10 +31,19 @@ extension KeyPathInst : OnoneSimplifyable { fileprivate func allUsesRemovable(instruction: Instruction) -> Bool { for result in instruction.results { for use in result.uses { - if !(use.instruction is UpcastInst || use.instruction is DestroyValueInst || use.instruction is BeginBorrowInst || use.instruction is EndBorrowInst) { - return false - } - if !allUsesRemovable(instruction: use.instruction) { + switch use.instruction { + case is UpcastInst, + is DestroyValueInst, + is BeginBorrowInst, + is EndBorrowInst, + is MoveValueInst, + is CopyValueInst: + // This is a removable instruction type, continue descending into uses + if !allUsesRemovable(instruction: use.instruction) { + return false + } + + default: return false } } diff --git a/test/embedded/keypaths2.swift b/test/embedded/keypaths2.swift new file mode 100644 index 0000000000000..7211adafb96e2 --- /dev/null +++ b/test/embedded/keypaths2.swift @@ -0,0 +1,43 @@ +// RUN: %target-run-simple-swift( -enable-experimental-feature Embedded -wmo -runtime-compatibility-version none) | %FileCheck %s +// RUN: %target-run-simple-swift(-O -enable-experimental-feature Embedded -wmo -runtime-compatibility-version none) | %FileCheck %s + +// REQUIRES: swift_in_compiler +// REQUIRES: executable_test +// REQUIRES: optimized_stdlib +// REQUIRES: OS=macosx || OS=linux-gnu + +@dynamicMemberLookup +public struct Box: ~Copyable { + init() { + self.value = UnsafeMutablePointer.allocate(capacity: 1) + } + + subscript(dynamicMember member: WritableKeyPath) -> U { + @_transparent + get { return self.value.pointer(to: member)!.pointee } + + @_transparent + set { self.value.pointer(to: member)!.pointee = newValue } + } + + var value: UnsafeMutablePointer +} + +public struct Foo { + var a: Int + var b: Int +} + +public func test_read(x: inout Box) -> Int { + return x.b +} + +public func test_write(x: inout Box) { + x.b = 42 +} + +var box = Box() +_ = test_read(x: &box) +test_write(x: &box) +print(box.b) +// CHECK: 42 diff --git a/test/embedded/keypaths3.swift b/test/embedded/keypaths3.swift new file mode 100644 index 0000000000000..addac00e930e5 --- /dev/null +++ b/test/embedded/keypaths3.swift @@ -0,0 +1,64 @@ +// RUN: %target-run-simple-swift( -enable-experimental-feature Embedded -wmo -Xfrontend -disable-access-control -runtime-compatibility-version none) | %FileCheck %s +// RUN: %target-run-simple-swift(-O -enable-experimental-feature Embedded -wmo -Xfrontend -disable-access-control -runtime-compatibility-version none) | %FileCheck %s + +// REQUIRES: swift_in_compiler +// REQUIRES: executable_test +// REQUIRES: optimized_stdlib +// REQUIRES: OS=macosx || OS=linux-gnu + +@dynamicMemberLookup +public struct Box: ~Copyable { + internal init(from t: T) { + self.value = UnsafeMutablePointer>.allocate(capacity: 1) + self.value.pointee = .init(t) + } + + public subscript(dynamicMember member: WritableKeyPath, Value>) -> Value + { + @_transparent + @inline(__always) + get { return self.value.pointer(to: member)!.pointee } + + @_transparent + @inline(__always) + set { self.value.pointer(to: member)!.pointee = newValue } + } + + public struct InnerBox { + public init(_ value: V) { self.innerValue = value } + public var innerValue: V + } + + @usableFromInline + internal var value: UnsafeMutablePointer> +} + +struct Foo { + var a: Int + var b: Int +} + +@inline(never) +public func test() -> Int { + var x = Box(from: Foo(a: 0, b: 0)) + x.innerValue.b = 42 + return x.innerValue.b +} + +precondition(test() == 42) +print("OK!") +// CHECK: OK! + +public func test_read(x: inout Box) -> Int { + return x.innerValue.b +} + +public func test_write(x: inout Box) { + x.innerValue.b = 42 +} + +var box = Box(from: Foo(a: 0, b: 0)) +_ = test_read(x: &box) +test_write(x: &box) +print(box.innerValue.b) +// CHECK: 42