Skip to content

Commit 9f8ccd4

Browse files
committed
SILGen: Fix for tuple conversions in function argument position
Swift admits implicit conversions between tuple types to introduce and eliminate argument labels, and re-order argument labels. These are expressed as TupleShuffleExpr in the AST. SILGen has two different code paths for lowering TupleShuffleExpr, which is also used for varargs and default arguments in call argument emission. These two code paths support different subsets of TupleShuffleExpr; neither one supports the full generality of the other, but there is some overlap. Work around the damage by routing the two different "kinds" of TupleShuffleExprs to the correct place in argument emission. The next incremental step here would be to refactor ArgEmitter to make it usable when lowering SubscriptExpr; then the RValueEmitter's support for varargs in TupleShuffleExpr can go away. Once that's done we can split off an ArgumentExpr from TupleShuffleExpr, and in the fullness of time, fold ArgumentExpr into ApplyExpr. At that point this dark corner of the AST will start to be sane... Fixes <https://bugs.swift.org/browse/SR-2887>.
1 parent 2517701 commit 9f8ccd4

File tree

3 files changed

+86
-8
lines changed

3 files changed

+86
-8
lines changed

lib/SILGen/ArgumentSource.cpp

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,35 @@ bool ArgumentSource::requiresCalleeToEvaluate() {
5555
case Kind::LValue:
5656
return false;
5757
case Kind::Expr:
58-
return isa<TupleShuffleExpr>(asKnownExpr());
58+
// FIXME: TupleShuffleExprs come in two flavors:
59+
//
60+
// 1) as apply arguments, where they're used to insert default
61+
// argument value and collect varargs
62+
//
63+
// 2) as tuple conversions, where they can introduce, eliminate
64+
// and re-order fields
65+
//
66+
// Case 1) must be emitted by ArgEmitter, and Case 2) must be
67+
// emitted by RValueEmitter.
68+
//
69+
// It would be good to split up TupleShuffleExpr into these two
70+
// cases, and simplify ArgEmitter since it no longer has to deal
71+
// with re-ordering. However for now, SubscriptExpr emits the
72+
// index argument via the RValueEmitter, so the RValueEmitter has
73+
// to know about varargs, duplicating some of the logic in
74+
// ArgEmitter.
75+
//
76+
// Once this is fixed, we can also consider allowing subscripts
77+
// to have default arguments.
78+
if (auto *shuffleExpr = dyn_cast<TupleShuffleExpr>(asKnownExpr())) {
79+
for (auto index : shuffleExpr->getElementMapping()) {
80+
if (index == TupleShuffleExpr::DefaultInitialize ||
81+
index == TupleShuffleExpr::CallerDefaultInitialize ||
82+
index == TupleShuffleExpr::Variadic)
83+
return true;
84+
}
85+
}
86+
return false;
5987
}
6088

6189
llvm_unreachable("Unhandled Kind in switch.");

test/SILGen/argument_shuffle.swift

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// RUN: %target-swift-frontend -emit-silgen %s
2+
3+
struct Horse<T> {
4+
func walk(_: (String, Int), reverse: Bool) {}
5+
func trot(_: (x: String, y: Int), halfhalt: Bool) {}
6+
func canter(_: T, counter: Bool) {}
7+
}
8+
9+
var kevin = Horse<(x: String, y: Int)>()
10+
var loki = Horse<(String, Int)>()
11+
12+
//
13+
14+
// No conversion
15+
let noLabelsTuple = ("x", 1)
16+
kevin.walk(("x", 1), reverse: false)
17+
kevin.walk(noLabelsTuple, reverse: false)
18+
19+
loki.canter(("x", 1), counter: false)
20+
loki.canter(noLabelsTuple, counter: false)
21+
22+
// Introducing labels
23+
kevin.trot(("x", 1), halfhalt: false)
24+
kevin.trot(noLabelsTuple, halfhalt: false)
25+
26+
kevin.canter(("x", 1), counter: false)
27+
kevin.canter(noLabelsTuple, counter: false)
28+
29+
// Eliminating labels
30+
let labelsTuple = (x: "x", y: 1)
31+
kevin.walk((x: "x", y: 1), reverse: false)
32+
kevin.walk(labelsTuple, reverse: false)
33+
34+
loki.canter((x: "x", y: 1), counter: false)
35+
loki.canter(labelsTuple, counter: false)
36+
37+
// No conversion
38+
kevin.trot((x: "x", y: 1), halfhalt: false)
39+
kevin.trot(labelsTuple, halfhalt: false)
40+
41+
kevin.canter((x: "x", y: 1), counter: false)
42+
kevin.canter(labelsTuple, counter: false)
43+
44+
// Shuffling labels
45+
let shuffledLabelsTuple = (y: 1, x: "x")
46+
kevin.trot((y: 1, x: "x"), halfhalt: false)
47+
kevin.trot(shuffledLabelsTuple, halfhalt: false)
48+
49+
kevin.canter((y: 1, x: "x"), counter: false)
50+
kevin.canter(shuffledLabelsTuple, counter: false)

test/SILGen/arguments.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,25 +18,25 @@ func _deallocateUninitializedArray<T>(_: Array<T>) {}
1818

1919
var i:Int, f:Float, c:UnicodeScalar
2020

21-
func arg_tuple(x x: Int, y: Float) {}
21+
func arg_tuple(x: Int, y: Float) {}
2222
// CHECK-LABEL: sil hidden @_TFs9arg_tupleFT1xSi1ySf_T_
2323
// CHECK: bb0([[X:%[0-9]+]] : $Int, [[Y:%[0-9]+]] : $Float):
2424

2525
arg_tuple(x: i, y: f)
2626

27-
func arg_deep_tuples(x x: Int, y: (Float, UnicodeScalar)) {}
27+
func arg_deep_tuples(x: Int, y: (Float, UnicodeScalar)) {}
2828
// CHECK-LABEL: sil hidden @_TFs15arg_deep_tuplesFT1xSi1yTSfSc__T_
2929
// CHECK: bb0([[X:%[0-9]+]] : $Int, [[Y_0:%[0-9]+]] : $Float, [[Y_1:%[0-9]+]] : $UnicodeScalar):
3030

3131
arg_deep_tuples(x:i, y:(f, c))
3232
var unnamed_subtuple = (f, c)
33-
arg_deep_tuples(x: i, y: unnamed_subtuple)
34-
// FIXME rdar://problem/12985801 -- tuple conversion confuses named fields
33+
arg_deep_tuples(x:i, y: unnamed_subtuple)
34+
// rdar://problem/12985801 -- tuple conversion confuses named fields
3535
// of a subtuple with those of outer tuple
36-
//var named_subtuple = (x:f, y:c)
37-
//arg_deep_tuples(i, named_subtuple)
36+
var named_subtuple = (x:f, y:c)
37+
arg_deep_tuples(x:i, y: named_subtuple)
3838

39-
func arg_deep_tuples_2(x x: Int, _: (y: Float, z: UnicodeScalar)) {}
39+
func arg_deep_tuples_2(x: Int, _: (y: Float, z: UnicodeScalar)) {}
4040
// CHECK-LABEL: sil hidden @_TFs17arg_deep_tuples_2FT1xSiT1ySf1zSc__T_
4141
// CHECK: bb0([[X:%[0-9]+]] : $Int, [[Y:%[0-9]+]] : $Float, [[Z:%[0-9]+]] : $UnicodeScalar):
4242

0 commit comments

Comments
 (0)