Skip to content

Commit 065eb83

Browse files
authored
[Playground] Missing playground results for init and deinit in a class wrapped in a struct (swiftlang#77498)
The problem here is when wrapping a type that has constructors and destructors inside another type. 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 was for too narrow of a type. The problem in this case was that the `dyn_cast<FuncDecl>(D)` was too narrow and didn’t include constructors/destructors. We want `dyn_cast<AbstractFunctionDecl>(D)`. We should probably resolve this duality (using an `ASTWalker` to get to the top-level decls but then using directly nested calls below) at some point, but that’s a larger change, and so the specific problem covered by this commit is worth addressing with this safer short-term fix. Changes: - change a `dyn_cast<FuncDecl>` to a `dyn_cast<AbstractFunctionDecl>` in PlaygroundTransform.cpp - add a unit test nested init and deinit (this test also tests the unnested case) rdar://137316110
1 parent 5945a89 commit 065eb83

File tree

2 files changed

+97
-1
lines changed

2 files changed

+97
-1
lines changed

lib/Sema/PlaygroundTransform.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ class Instrumenter : InstrumenterBase {
308308
Decl *transformDecl(Decl *D) {
309309
if (D->isImplicit())
310310
return D;
311-
if (auto *FD = dyn_cast<FuncDecl>(D)) {
311+
if (auto *FD = dyn_cast<AbstractFunctionDecl>(D)) {
312312
if (BraceStmt *B = FD->getTypecheckedBody()) {
313313
const ParameterList *PL = FD->getParameters();
314314
TargetKindSetter TKS(BracePairs, BracePair::TargetKinds::Return);
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
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 constructors, destructors, and regular functions for an unwrapped class.
30+
class MyClass {
31+
init() {
32+
let x = 1
33+
}
34+
func f() {
35+
let y = 2
36+
}
37+
deinit {
38+
let z = 3
39+
}
40+
}
41+
do {
42+
let c = MyClass()
43+
c.f()
44+
}
45+
46+
// CHECK: [{{.*}}] __builtin_log_scope_entry
47+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_entry
48+
// CHECK-NEXT: [{{.*}}] __builtin_log[x='1']
49+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit
50+
// CHECK-NEXT: [{{.*}}] __builtin_log[c='main{{.*}}.MyClass']
51+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_entry
52+
// CHECK-NEXT: [{{.*}}] __builtin_log[y='2']
53+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit
54+
// CHECK-NEXT: [{{.*}}] __builtin_log[c='main{{.*}}.MyClass']
55+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit
56+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_entry
57+
// CHECK-NEXT: [{{.*}}] __builtin_log[z='3']
58+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit
59+
60+
// Now make sure we get results in constructors, destructors, and regular functions for a wrapped class too.
61+
struct Playground {
62+
static func doit() {
63+
class MyClass {
64+
init() {
65+
let x = 1
66+
}
67+
func f() {
68+
let y = 2
69+
}
70+
deinit {
71+
let z = 3
72+
}
73+
}
74+
do {
75+
let c = MyClass()
76+
c.f()
77+
}
78+
}
79+
}
80+
Playground.doit()
81+
82+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_entry
83+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_entry
84+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_entry
85+
// CHECK-NEXT: [{{.*}}] __builtin_log[x='1']
86+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit
87+
// CHECK-NEXT: [{{.*}}] __builtin_log[c='main{{.*}}.MyClass']
88+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_entry
89+
// CHECK-NEXT: [{{.*}}] __builtin_log[y='2']
90+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit
91+
// CHECK-NEXT: [{{.*}}] __builtin_log[c='main{{.*}}.MyClass']
92+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit
93+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_entry
94+
// CHECK-NEXT: [{{.*}}] __builtin_log[z='3']
95+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit
96+
// CHECK-NEXT: [{{.*}}] __builtin_log_scope_exit

0 commit comments

Comments
 (0)