@@ -430,17 +430,6 @@ extension LoweredFunctionSignature {
430
430
originalResult = callExpression
431
431
}
432
432
433
- // FIXME: Check whether there are multiple places in which we reference
434
- // the placeholder in resultConversion. If so, we should write it into a
435
- // local let "_resultValue" or similar so we don't call the underlying
436
- // function multiple times.
437
-
438
- // Convert the result.
439
- let convertedResult = resultConversion. asExprSyntax (
440
- isSelf: true ,
441
- placeholder: originalResult. description
442
- )
443
-
444
433
if cdecl. result. type. isVoid {
445
434
// Indirect return. This is a regular return in Swift that turns
446
435
// into an assignment via the indirect parameters. We do a cdeclToSwift
@@ -450,16 +439,23 @@ extension LoweredFunctionSignature {
450
439
let cdeclParamConversion = try ! ConversionStep (
451
440
cdeclToSwift: original. result. type
452
441
)
453
- let indirectResults = cdeclParamConversion. asExprSyntax (
454
- isSelf: true ,
455
- placeholder: " _result "
456
- )
457
- bodyItems. append ( """
458
- \( indirectResults) = \( convertedResult)
459
- """
442
+
443
+ // For each indirect result, initialize the value directly with the
444
+ // corresponding element in the converted result.
445
+ bodyItems. append (
446
+ contentsOf: cdeclParamConversion. initialize (
447
+ placeholder: " _result " ,
448
+ from: resultConversion,
449
+ otherPlaceholder: originalResult. description
450
+ )
460
451
)
461
452
} else {
462
453
// Direct return. Just convert the expression.
454
+ let convertedResult = resultConversion. asExprSyntax (
455
+ isSelf: true ,
456
+ placeholder: originalResult. description
457
+ )
458
+
463
459
bodyItems. append ( """
464
460
return \( convertedResult)
465
461
"""
@@ -475,3 +471,58 @@ extension LoweredFunctionSignature {
475
471
return loweredCDecl
476
472
}
477
473
}
474
+
475
+ extension ConversionStep {
476
+ /// Form a set of statements that initializes the placeholders within
477
+ /// the given conversion step from ones in the other step, effectively
478
+ /// exploding something like `(a, (b, c)) = (d, (e, f))` into
479
+ /// separate initializations for a, b, and c from d, e, and f, respectively.
480
+ func initialize(
481
+ placeholder: String ,
482
+ from otherStep: ConversionStep ,
483
+ otherPlaceholder: String
484
+ ) -> [ CodeBlockItemSyntax ] {
485
+ // Create separate assignments for each element in paired tuples.
486
+ if case . tuplify( let elements) = self ,
487
+ case . tuplify( let otherElements) = otherStep {
488
+ assert ( elements. count == otherElements. count)
489
+
490
+ return elements. indices. flatMap { index in
491
+ elements [ index] . initialize (
492
+ placeholder: " \( placeholder) _ \( index) " ,
493
+ from: otherElements [ index] ,
494
+ otherPlaceholder: " \( otherPlaceholder) _ \( index) "
495
+ )
496
+ }
497
+ }
498
+
499
+ // Look through "pass indirectly" steps; they do nothing here.
500
+ if case . passIndirectly( let conversionStep) = self {
501
+ return conversionStep. initialize (
502
+ placeholder: placeholder,
503
+ from: otherStep,
504
+ otherPlaceholder: otherPlaceholder
505
+ )
506
+ }
507
+
508
+ // The value we're initializing from.
509
+ let otherExpr = otherStep. asExprSyntax (
510
+ isSelf: false ,
511
+ placeholder: otherPlaceholder
512
+ )
513
+
514
+ // If we have a "pointee" on where we are performing initialization, we
515
+ // need to instead produce an initialize(to:) call.
516
+ if case . pointee( let innerSelf) = self {
517
+ let selfPointerExpr = innerSelf. asExprSyntax (
518
+ isSelf: true ,
519
+ placeholder: placeholder
520
+ )
521
+
522
+ return [ " \( selfPointerExpr) .initialize(to: \( otherExpr) ) " ]
523
+ }
524
+
525
+ let selfExpr = self . asExprSyntax ( isSelf: true , placeholder: placeholder)
526
+ return [ " \( selfExpr) = \( otherExpr) " ]
527
+ }
528
+ }
0 commit comments