Skip to content

Commit 31f75c6

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`, `subscript(index:)`, 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). That issue seems to be worth resolving at some point (perhaps by using the `ASTWalker` for the whole traversal?)... but that would be a larger change requiring more though, and so the missing results being fixed here are worth addressing with a safer short-term fix. rdar://139656464
1 parent 4be3990 commit 31f75c6

File tree

2 files changed

+191
-0
lines changed

2 files changed

+191
-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<AbstractStorageDecl>(D)) {
326+
VD->visitParsedAccessors([&](AccessorDecl * ACC) {
327+
transformDecl(ACC);
328+
});
325329
}
326330

327331
return D;
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
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+
subscript(index: Int) -> Int {
51+
get {
52+
return 7
53+
}
54+
set {
55+
let y = 8
56+
}
57+
}
58+
}
59+
do {
60+
let c = MyClass()
61+
c.f()
62+
c.v1
63+
c.v2 = 7
64+
c.v2
65+
c.v3 = 8
66+
c[9]
67+
c[9] = 10
68+
}
69+
70+
// CHECK: [{{.*}}] __builtin_log_scope_entry
71+
// CHECK-NEXT: [{{.*}}] __builtin_log[c='main{{.*}}.MyClass']
72+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_entry
73+
// CHECK-NEXT: [{{.*}}] __builtin_log[x='1']
74+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit
75+
// CHECK-NEXT: [{{.*}}] __builtin_log[c='main{{.*}}.MyClass']
76+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_entry
77+
// CHECK-NEXT: [{{.*}}] __builtin_log[='2']
78+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit
79+
// CHECK-NEXT: [{{.*}}] __builtin_log[='2']
80+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_entry
81+
// CHECK-NEXT: [{{.*}}] __builtin_log[newValue='7']
82+
// CHECK-NEXT: [{{.*}}] __builtin_log[y='4']
83+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit
84+
// CHECK-NEXT: [{{.*}}] __builtin_log[c='main{{.*}}.MyClass']
85+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_entry
86+
// CHECK-NEXT: [{{.*}}] __builtin_log[='3']
87+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit
88+
// CHECK-NEXT: [{{.*}}] __builtin_log[='3']
89+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_entry
90+
// CHECK-NEXT: [{{.*}}] __builtin_log[z='6']
91+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit
92+
// CHECK-NEXT: [{{.*}}] __builtin_log[c='main{{.*}}.MyClass']
93+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_entry
94+
// CHECK-NEXT: [{{.*}}] __builtin_log[index='9']
95+
// CHECK-NEXT: [{{.*}}] __builtin_log[='7']
96+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit
97+
// CHECK-NEXT: [{{.*}}] __builtin_log[='7']
98+
// CHECK-NEXT: [{{.*}}] __builtin_log[='10']
99+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_entry
100+
// CHECK-NEXT: [{{.*}}] __builtin_log[newValue='10']
101+
// CHECK-NEXT: [{{.*}}] __builtin_log[index='9']
102+
// CHECK-NEXT: [{{.*}}] __builtin_log[y='8']
103+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit
104+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit
105+
106+
// Now make sure we get results in accessors and regular functions for a wrapped class too.
107+
struct Playground {
108+
static func doit() {
109+
class MyClass {
110+
func f() {
111+
let x = 1
112+
}
113+
var v1: Int {
114+
return 2
115+
}
116+
var v2: Int {
117+
get {
118+
return 3
119+
}
120+
set {
121+
let y = 4
122+
}
123+
}
124+
var v3: Int = 5 {
125+
didSet {
126+
let z = 6
127+
}
128+
}
129+
subscript(index: Int) -> Int {
130+
get {
131+
return 7
132+
}
133+
set {
134+
let y = 8
135+
}
136+
}
137+
}
138+
do {
139+
let c = MyClass()
140+
c.f()
141+
c.v1
142+
c.v2 = 7
143+
c.v2
144+
c.v3 = 8
145+
c[9]
146+
c[9] = 10
147+
}
148+
}
149+
}
150+
Playground.doit()
151+
152+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_entry
153+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_entry
154+
// CHECK-NEXT: [{{.*}}] __builtin_log[c='main{{.*}}.MyClass']
155+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_entry
156+
// CHECK-NEXT: [{{.*}}] __builtin_log[x='1']
157+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit
158+
// CHECK-NEXT: [{{.*}}] __builtin_log[c='main{{.*}}.MyClass']
159+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_entry
160+
// CHECK-NEXT: [{{.*}}] __builtin_log[='2']
161+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit
162+
// CHECK-NEXT: [{{.*}}] __builtin_log[='2']
163+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_entry
164+
// CHECK-NEXT: [{{.*}}] __builtin_log[newValue='7']
165+
// CHECK-NEXT: [{{.*}}] __builtin_log[y='4']
166+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit
167+
// CHECK-NEXT: [{{.*}}] __builtin_log[c='main{{.*}}.MyClass']
168+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_entry
169+
// CHECK-NEXT: [{{.*}}] __builtin_log[='3']
170+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit
171+
// CHECK-NEXT: [{{.*}}] __builtin_log[='3']
172+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_entry
173+
// CHECK-NEXT: [{{.*}}] __builtin_log[z='6']
174+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit
175+
// CHECK-NEXT: [{{.*}}] __builtin_log[c='main{{.*}}.MyClass']
176+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_entry
177+
// CHECK-NEXT: [{{.*}}] __builtin_log[index='9']
178+
// CHECK-NEXT: [{{.*}}] __builtin_log[='7']
179+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit
180+
// CHECK-NEXT: [{{.*}}] __builtin_log[='7']
181+
// CHECK-NEXT: [{{.*}}] __builtin_log[='10']
182+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_entry
183+
// CHECK-NEXT: [{{.*}}] __builtin_log[newValue='10']
184+
// CHECK-NEXT: [{{.*}}] __builtin_log[index='9']
185+
// CHECK-NEXT: [{{.*}}] __builtin_log[y='8']
186+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit
187+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit

0 commit comments

Comments
 (0)