Skip to content

Commit cae6746

Browse files
authored
Merge pull request #65893 from hamishknight/scoping-out
2 parents b813b0e + f75e830 commit cae6746

File tree

3 files changed

+212
-9
lines changed

3 files changed

+212
-9
lines changed

lib/AST/ASTScopeCreation.cpp

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,14 @@ class ScopeCreator final : public ASTAllocated<ScopeCreator> {
100100
ASTScopeAssert(expr,
101101
"If looking for closures, must have an expression to search.");
102102

103-
/// AST walker that finds top-level closures in an expression.
104-
class ClosureFinder : public ASTWalker {
103+
/// AST walker that finds nested scopes in expressions. This handles both
104+
/// closures and if/switch expressions.
105+
class NestedExprScopeFinder : public ASTWalker {
105106
ScopeCreator &scopeCreator;
106107
ASTScopeImpl *parent;
107108

108109
public:
109-
ClosureFinder(ScopeCreator &scopeCreator, ASTScopeImpl *parent)
110+
NestedExprScopeFinder(ScopeCreator &scopeCreator, ASTScopeImpl *parent)
110111
: scopeCreator(scopeCreator), parent(parent) {}
111112

112113
PreWalkResult<Expr *> walkToExprPre(Expr *E) override {
@@ -122,6 +123,13 @@ class ScopeCreator final : public ASTAllocated<ScopeCreator> {
122123
parent, capture);
123124
return Action::SkipChildren(E);
124125
}
126+
127+
// If we have a single value statement expression, we need to add any
128+
// scopes in the underlying statement.
129+
if (auto *SVE = dyn_cast<SingleValueStmtExpr>(E)) {
130+
scopeCreator.addToScopeTree(SVE->getStmt(), parent);
131+
return Action::SkipChildren(E);
132+
}
125133
return Action::Continue(E);
126134
}
127135
PreWalkResult<Stmt *> walkToStmtPre(Stmt *S) override {
@@ -148,7 +156,7 @@ class ScopeCreator final : public ASTAllocated<ScopeCreator> {
148156
}
149157
};
150158

151-
expr->walk(ClosureFinder(*this, parent));
159+
expr->walk(NestedExprScopeFinder(*this, parent));
152160
}
153161

154162
public:
@@ -518,11 +526,6 @@ class NodeAdder
518526
if (!expr)
519527
return p;
520528

521-
// If we have a single value statement expression, we expand scopes based
522-
// on the underlying statement.
523-
if (auto *SVE = dyn_cast<SingleValueStmtExpr>(expr))
524-
return visit(SVE->getStmt(), p, scopeCreator);
525-
526529
scopeCreator.addExprToScopeTree(expr, p);
527530
return p;
528531
}

test/SILGen/if_expr.swift

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,3 +263,98 @@ func nestedType() throws -> Int {
263263
0
264264
}
265265
}
266+
267+
// MARK: Bindings
268+
269+
enum E {
270+
case e(Int)
271+
}
272+
273+
struct S {
274+
var i: Int
275+
276+
mutating func testAssign1(_ x: E) {
277+
i = if case .e(let y) = x { y } else { 0 }
278+
}
279+
280+
281+
mutating func testAssign2(_ x: E) {
282+
i = if case .e(let y) = x { Int(y) } else { 0 }
283+
}
284+
285+
func testAssign3(_ x: E) {
286+
var i = 0
287+
i = if case .e(let y) = x { y } else { 0 }
288+
_ = i
289+
}
290+
291+
func testAssign4(_ x: E) {
292+
var i = 0
293+
let _ = {
294+
i = if case .e(let y) = x { y } else { 0 }
295+
}
296+
_ = i
297+
}
298+
299+
mutating func testAssign5(_ x: E) {
300+
i = switch Bool.random() {
301+
case true:
302+
if case .e(let y) = x { y } else { 0 }
303+
case let z:
304+
z ? 0 : 1
305+
}
306+
}
307+
308+
mutating func testAssign6(_ x: E) {
309+
i = if case .e(let y) = x {
310+
switch Bool.random() {
311+
case true: y
312+
case false: y
313+
}
314+
} else {
315+
0
316+
}
317+
}
318+
319+
mutating func testAssign7(_ x: E?) {
320+
i = if let x = x {
321+
switch x {
322+
case .e(let y): y
323+
}
324+
} else {
325+
0
326+
}
327+
}
328+
329+
func testReturn1(_ x: E) -> Int {
330+
if case .e(let y) = x { y } else { 0 }
331+
}
332+
333+
func testReturn2(_ x: E) -> Int {
334+
return if case .e(let y) = x { y } else { 0 }
335+
}
336+
337+
func testReturn3(_ x: E) -> Int {
338+
{
339+
if case .e(let y) = x { y } else { 0 }
340+
}()
341+
}
342+
343+
func testReturn4(_ x: E) -> Int {
344+
return {
345+
if case .e(let y) = x { y } else { 0 }
346+
}()
347+
}
348+
349+
func testBinding1(_ x: E) -> Int {
350+
let i = if case .e(let y) = x { y } else { 0 }
351+
return i
352+
}
353+
354+
func testBinding2(_ x: E) -> Int {
355+
let i = {
356+
if case .e(let y) = x { y } else { 0 }
357+
}()
358+
return i
359+
}
360+
}

test/SILGen/switch_expr.swift

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,3 +358,108 @@ func nestedType() throws -> Int {
358358
0
359359
}
360360
}
361+
362+
// MARK: Bindings
363+
364+
enum F {
365+
case e(Int)
366+
}
367+
368+
struct S {
369+
var i: Int
370+
371+
mutating func testAssign1(_ x: F) {
372+
i = switch x {
373+
case .e(let y): y
374+
}
375+
}
376+
377+
mutating func testAssign2(_ x: F) {
378+
i = switch x {
379+
case .e(let y): Int(y)
380+
}
381+
}
382+
383+
func testAssign3(_ x: F) {
384+
var i = 0
385+
i = switch x {
386+
case .e(let y): y
387+
}
388+
_ = i
389+
}
390+
391+
func testAssign4(_ x: F) {
392+
var i = 0
393+
let _ = {
394+
i = switch x {
395+
case .e(let y): y
396+
}
397+
}
398+
_ = i
399+
}
400+
401+
mutating func testAssign5(_ x: F) {
402+
i = switch Bool.random() {
403+
case true:
404+
switch x {
405+
case .e(let y): y
406+
}
407+
case let z:
408+
z ? 0 : 1
409+
}
410+
}
411+
412+
mutating func testAssign6(_ x: F) {
413+
i = switch x {
414+
case .e(let y):
415+
switch Bool.random() {
416+
case true: y
417+
case false: y
418+
}
419+
}
420+
}
421+
422+
func testReturn1(_ x: F) -> Int {
423+
switch x {
424+
case .e(let y): y
425+
}
426+
}
427+
428+
func testReturn2(_ x: F) -> Int {
429+
return switch x {
430+
case .e(let y): y
431+
}
432+
}
433+
434+
func testReturn3(_ x: F) -> Int {
435+
{
436+
switch x {
437+
case .e(let y): y
438+
}
439+
}()
440+
}
441+
442+
func testReturn4(_ x: F) -> Int {
443+
return {
444+
switch x {
445+
case .e(let y): y
446+
}
447+
}()
448+
}
449+
450+
func testBinding1(_ x: F) -> Int {
451+
let i = switch x {
452+
case .e(let y): y
453+
}
454+
return i
455+
}
456+
457+
func testBinding2(_ x: F) -> Int {
458+
let i = {
459+
switch x {
460+
case .e(let y): y
461+
}
462+
}()
463+
return i
464+
}
465+
}

0 commit comments

Comments
 (0)