Skip to content

Commit 69656b0

Browse files
xedinhborla
authored andcommitted
[TypeCheckMacros] Never associate MacroExpansionExpr with a closure
The closures are type-checked after macros are expanded which means that macro cannot reference any declarations from inner or outer closures as its arguments. For example: `_: (Int) -> Void = { x in { @macro(x) in ... }() }` `x` is not going to be type-checked at macro expansion time and cannot be referenced by `@Macro`. Let's walk up declaration contexts until we find first non-closure one. This means that we can support a local declaration that is defined inside of a closure because they are separately checked after outer ones are already processed.
1 parent 1b111f4 commit 69656b0

File tree

2 files changed

+116
-1
lines changed

2 files changed

+116
-1
lines changed

lib/Sema/TypeCheckMacros.cpp

+22
Original file line numberDiff line numberDiff line change
@@ -2257,6 +2257,28 @@ ConcreteDeclRef ResolveMacroRequest::evaluate(Evaluator &evaluator,
22572257
dc, expansion->getExpansionInfo(), roles);
22582258
}
22592259
} else {
2260+
if (isa<ClosureExpr>(dc) && roles.contains(MacroRole::Body)) {
2261+
// The closures are type-checked after macros are expanded
2262+
// which means that macro cannot reference any declarations
2263+
// from inner or outer closures as its arguments.
2264+
//
2265+
// For example:
2266+
// `_: (Int) -> Void = { x in { @Macro(x) in ... }() }`
2267+
//
2268+
// `x` is not going to be type-checked at macro expansion
2269+
// time and cannot be referenced by `@Macro`.
2270+
//
2271+
// Let's walk up declaration contexts until we find first
2272+
// non-closure one. This means that we can support a local
2273+
// declaration that is defined inside of a closure because
2274+
// they are separately checked after outer ones are already
2275+
// processed.
2276+
while ((dc = dc->getParent())) {
2277+
if (!isa<AbstractClosureExpr>(dc))
2278+
break;
2279+
}
2280+
}
2281+
22602282
SourceRange genericArgsRange = macroRef.getGenericArgsRange();
22612283
macroExpansion = MacroExpansionExpr::create(
22622284
dc, macroRef.getSigilLoc(),

test/Macros/start_task.swift

+94-1
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,107 @@ func sync() {
1515
}
1616

1717
func takeClosure(
18-
_ closure: @escaping @Sendable () -> Void
18+
_ closure: @escaping @Sendable () -> Void,
19+
v: Int = 42
1920
) {
2021
closure()
2122
}
2223

24+
func multipleClosures(
25+
a: @escaping @Sendable () -> Void,
26+
b: @escaping @Sendable () -> Void) {
27+
}
2328

2429
func onClosure() {
30+
// CHECK-LABEL: @__swiftmacro_10start_task0021start_taskswift_IfFDefMX35_16_33_EEC79532ED9A2723128F952F754D3F84Ll9StartTaskfMb_.swift
31+
// CHECK: {
32+
// CHECK: Task {
33+
// CHECK: await f()
34+
// CHECK: }
35+
// CHECK: }
2536
takeClosure { @StartTask in
2637
await f()
2738
}
39+
40+
// CHECK-LABEL: @__swiftmacro_10start_task0021start_taskswift_IfFDefMX45_16_33_EEC79532ED9A2723128F952F754D3F84Ll9StartTaskfMb_.swift
41+
// CHECK: {
42+
// CHECK: Task {
43+
// CHECK: await f()
44+
// CHECK: }
45+
// CHECK: }
46+
takeClosure({ @StartTask in
47+
await f()
48+
}, v: 0)
49+
50+
// CHECK-LABEL: @__swiftmacro_10start_task0021start_taskswift_IfFDefMX55_21_33_EEC79532ED9A2723128F952F754D3F84Ll9StartTaskfMb_.swift
51+
// CHECK: {
52+
// CHECK: Task {
53+
// CHECK: await f()
54+
// CHECK: }
55+
// CHECK: }
56+
multipleClosures { @StartTask in
57+
await f()
58+
} b: {
59+
}
60+
61+
// CHECK-LABEL: @__swiftmacro_10start_task0021start_taskswift_IfFDefMX68_9_33_EEC79532ED9A2723128F952F754D3F84Ll9StartTaskfMb_.swift
62+
// CHECK: {
63+
// CHECK: Task {
64+
// CHECK: await f()
65+
// CHECK: }
66+
// CHECK: }
67+
multipleClosures {
68+
_ = 42
69+
} b: { @StartTask in
70+
await f()
71+
}
72+
73+
// CHECK-LABEL: @__swiftmacro_10start_task0021start_taskswift_IfFDefMX86_4_33_EEC79532ED9A2723128F952F754D3F84Ll9StartTaskfMb_.swift
74+
// CHECK: {
75+
// CHECK: Task {
76+
// CHECK: _ = 42
77+
// CHECK: }
78+
// CHECK: }
79+
80+
// CHECK-LABEL: @__swiftmacro_10start_task0021start_taskswift_IfFDefMX88_9_33_EEC79532ED9A2723128F952F754D3F84Ll9StartTaskfMb_.swift
81+
// CHECK: {
82+
// CHECK: Task {
83+
// CHECK: await f()
84+
// CHECK: }
85+
// CHECK: }
86+
multipleClosures {
87+
@StartTask in
88+
_ = 42
89+
} b: { @StartTask in
90+
await f()
91+
}
92+
93+
// CHECK-LABEL: @__swiftmacro_10start_task0021start_taskswift_IfFDefMX100_12_33_EEC79532ED9A2723128F952F754D3F84Ll9StartTaskfMb_.swift
94+
// CHECK: {
95+
// CHECK: Task {
96+
// CHECK: await f()
97+
// CHECK: }
98+
// CHECK: }
99+
let _ = {
100+
func test() {
101+
_ = { @StartTask in await f() }
102+
}
103+
}
104+
105+
// CHECK-LABEL: @__swiftmacro_10start_task0021start_taskswift_IfFDefMX114_54_33_EEC79532ED9A2723128F952F754D3F84Ll9StartTaskfMb_.swift
106+
// CHECK: {
107+
// CHECK: Task {
108+
// CHECK: await test()
109+
// CHECK: }
110+
// CHECK: }
111+
let _ = {
112+
let y = 42
113+
func test() async { print(y) }
114+
115+
if case let (_, closure) = (otherValue: 42, fn: { @StartTask in
116+
await test()
117+
}) {
118+
let _: Task<(), Never> = closure()
119+
}
120+
}
28121
}

0 commit comments

Comments
 (0)