Skip to content

Commit 53cc8fc

Browse files
committed
[Playground] Missing playground results for property accessors in a class wrapped in a struct
When a decl that has properties with accessors (`get`, `set`, `willSet`, `didSet`, etc) is nested inside another type, those accessor implementations aren't playground-transformed. The reason is that the playground transform uses an `ASTWalker` to get to the top-level structure, but then once it’s inside a type, it does directly nested `transformDecl()` calls. And that inner check is missing a case for accessors. This change adds an else-clause that checks if the declaration is a `VarDecl`, and if so, calls `transformDecl()` on each accessor. It's unfortunate that the playground transform reaches decls in two different ways (using an `ASTWalker` to get to the top-level decls but then using directly nested calls below). This seems to be worth resolving at some point (perhaps by using the `ASTWalker` for the whole traversal?), but that’s a larger change, and so this is worth addressing with a safer short-term fix. rdar://139656464
1 parent 4be3990 commit 53cc8fc

File tree

2 files changed

+149
-0
lines changed

2 files changed

+149
-0
lines changed

lib/Sema/PlaygroundTransform.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,10 @@ class Instrumenter : InstrumenterBase {
322322
for (Decl *Member : NTD->getMembers()) {
323323
transformDecl(Member);
324324
}
325+
} else if (auto *VD = dyn_cast<VarDecl>(D)) {
326+
VD->visitParsedAccessors([&](AccessorDecl * ACC) {
327+
transformDecl(ACC);
328+
});
325329
}
326330

327331
return D;
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: cp %s %t/main.swift
3+
4+
// Build PlaygroundSupport module
5+
// RUN: %target-build-swift -whole-module-optimization -module-name PlaygroundSupport -emit-module-path %t/PlaygroundSupport.swiftmodule -parse-as-library -c -o %t/PlaygroundSupport.o %S/Inputs/SilentPCMacroRuntime.swift %S/Inputs/PlaygroundsRuntime.swift
6+
7+
// -playground
8+
// RUN: %target-build-swift -swift-version 5 -Xfrontend -playground -o %t/main5a -I=%t %t/PlaygroundSupport.o %t/main.swift
9+
// RUN: %target-build-swift -swift-version 6 -Xfrontend -playground -o %t/main6a -I=%t %t/PlaygroundSupport.o %t/main.swift
10+
11+
// -pc-macro -playground
12+
// RUN: %target-build-swift -swift-version 5 -Xfrontend -pc-macro -Xfrontend -playground -o %t/main5b -I=%t %t/PlaygroundSupport.o %t/main.swift
13+
// RUN: %target-build-swift -swift-version 6 -Xfrontend -pc-macro -Xfrontend -playground -o %t/main6b -I=%t %t/PlaygroundSupport.o %t/main.swift
14+
15+
// RUN: %target-codesign %t/main5a
16+
// RUN: %target-codesign %t/main5b
17+
// RUN: %target-codesign %t/main6a
18+
// RUN: %target-codesign %t/main6b
19+
20+
// RUN: %target-run %t/main5a | %FileCheck %s
21+
// RUN: %target-run %t/main5b | %FileCheck %s
22+
// RUN: %target-run %t/main6a | %FileCheck %s
23+
// RUN: %target-run %t/main6b | %FileCheck %s
24+
25+
// REQUIRES: executable_test
26+
27+
import PlaygroundSupport
28+
29+
// First make sure we get results in accessors and regular functions for an unwrapped class.
30+
class MyClass {
31+
func f() {
32+
let x = 1
33+
}
34+
var v1: Int {
35+
return 2
36+
}
37+
var v2: Int {
38+
get {
39+
return 3
40+
}
41+
set {
42+
let y = 4
43+
}
44+
}
45+
var v3: Int = 5 {
46+
didSet {
47+
let z = 6
48+
}
49+
}
50+
}
51+
do {
52+
let c = MyClass()
53+
c.f()
54+
c.v1
55+
c.v2 = 7
56+
c.v2
57+
c.v3 = 8
58+
}
59+
60+
// CHECK: [{{.*}}] __builtin_log_scope_entry
61+
// CHECK-NEXT: [{{.*}}] __builtin_log[c='main{{.*}}.MyClass']
62+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_entry
63+
// CHECK-NEXT: [{{.*}}] __builtin_log[x='1']
64+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit
65+
// CHECK-NEXT: [{{.*}}] __builtin_log[c='main{{.*}}.MyClass']
66+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_entry
67+
// CHECK-NEXT: [{{.*}}] __builtin_log[='2']
68+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit
69+
// CHECK-NEXT: [{{.*}}] __builtin_log[='2']
70+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_entry
71+
// CHECK-NEXT: [{{.*}}] __builtin_log[newValue='7']
72+
// CHECK-NEXT: [{{.*}}] __builtin_log[y='4']
73+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit
74+
// CHECK-NEXT: [{{.*}}] __builtin_log[c='main{{.*}}.MyClass']
75+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_entry
76+
// CHECK-NEXT: [{{.*}}] __builtin_log[='3']
77+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit
78+
// CHECK-NEXT: [{{.*}}] __builtin_log[='3']
79+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_entry
80+
// CHECK-NEXT: [{{.*}}] __builtin_log[z='6']
81+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit
82+
// CHECK-NEXT: [{{.*}}] __builtin_log[c='main{{.*}}.MyClass']
83+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit
84+
85+
// Now make sure we get results in accessors and regular functions for a wrapped class too.
86+
struct Playground {
87+
static func doit() {
88+
class MyClass {
89+
func f() {
90+
let x = 1
91+
}
92+
var v1: Int {
93+
return 2
94+
}
95+
var v2: Int {
96+
get {
97+
return 3
98+
}
99+
set {
100+
let y = 4
101+
}
102+
}
103+
var v3: Int = 5 {
104+
didSet {
105+
let z = 6
106+
}
107+
}
108+
}
109+
do {
110+
let c = MyClass()
111+
c.f()
112+
c.v1
113+
c.v2 = 7
114+
c.v2
115+
c.v3 = 8
116+
}
117+
}
118+
}
119+
Playground.doit()
120+
121+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_entry
122+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_entry
123+
// CHECK-NEXT: [{{.*}}] __builtin_log[c='main{{.*}}.MyClass']
124+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_entry
125+
// CHECK-NEXT: [{{.*}}] __builtin_log[x='1']
126+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit
127+
// CHECK-NEXT: [{{.*}}] __builtin_log[c='main{{.*}}.MyClass']
128+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_entry
129+
// CHECK-NEXT: [{{.*}}] __builtin_log[='2']
130+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit
131+
// CHECK-NEXT: [{{.*}}] __builtin_log[='2']
132+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_entry
133+
// CHECK-NEXT: [{{.*}}] __builtin_log[newValue='7']
134+
// CHECK-NEXT: [{{.*}}] __builtin_log[y='4']
135+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit
136+
// CHECK-NEXT: [{{.*}}] __builtin_log[c='main{{.*}}.MyClass']
137+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_entry
138+
// CHECK-NEXT: [{{.*}}] __builtin_log[='3']
139+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit
140+
// CHECK-NEXT: [{{.*}}] __builtin_log[='3']
141+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_entry
142+
// CHECK-NEXT: [{{.*}}] __builtin_log[z='6']
143+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit
144+
// CHECK-NEXT: [{{.*}}] __builtin_log[c='main{{.*}}.MyClass']
145+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit

0 commit comments

Comments
 (0)