Skip to content

Commit 2a187f2

Browse files
committed
SILGen: Support mutable consuming parameters.
Emit a box like we would for a local variable, and move the parameter value into the box, as part of the prolog.
1 parent 704a436 commit 2a187f2

File tree

4 files changed

+45
-14
lines changed

4 files changed

+45
-14
lines changed

lib/AST/Decl.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6387,9 +6387,9 @@ Type VarDecl::getType() const {
63876387
/// is a let member in an initializer.
63886388
bool VarDecl::isSettable(const DeclContext *UseDC,
63896389
const DeclRefExpr *base) const {
6390-
// Only inout parameters are settable.
6390+
// Parameters are settable or not depending on their ownership convention.
63916391
if (auto *PD = dyn_cast<ParamDecl>(this))
6392-
return PD->isInOut();
6392+
return !PD->isImmutableInFunctionBody();
63936393

63946394
// If this is a 'var' decl, then we're settable if we have storage or a
63956395
// setter.

lib/SILGen/SILGenProlog.cpp

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -429,18 +429,20 @@ struct ArgumentInitHelper {
429429
ManagedValue argrv = makeArgument(ty, pd->isInOut(), isNoImplicitCopy,
430430
lifetimeAnnotation, parent, loc);
431431

432+
SILValue value = argrv.getValue();
432433
if (pd->isInOut()) {
433434
assert(argrv.getType().isAddress() && "expected inout to be address");
434-
} else {
435-
#warning "todo"
436-
assert(pd->isImmutableInFunctionBody()
437-
&& "consuming mutable params not implemented yet");
438-
// If the variable is immutable, we can bind the value as is.
439-
// Leave the cleanup on the argument, if any, in place to consume the
440-
// argument if we're responsible for it.
435+
} else if (!pd->isImmutableInFunctionBody()) {
436+
// If it's a locally mutable parameter, then we need to move the argument
437+
// value into a local box to hold the mutated value.
438+
auto mutableBox = SGF.emitLocalVariableWithCleanup(pd,
439+
MarkUninitializedInst::Var);
440+
argrv.ensurePlusOne(SGF, loc).forwardInto(SGF, loc, mutableBox.get());
441+
return;
441442
}
442-
SILValue value = argrv.getValue();
443-
#warning "todo"
443+
// If the variable is immutable, we can bind the value as is.
444+
// Leave the cleanup on the argument, if any, in place to consume the
445+
// argument if we're responsible for it.
444446
SILDebugVariable varinfo(pd->isImmutableInFunctionBody(), ArgNo);
445447
if (!argrv.getType().isAddress()) {
446448
// NOTE: We setup SGF.VarLocs[pd] in updateArgumentValueForBinding.

lib/Sema/TypeCheckStorage.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3358,9 +3358,9 @@ StorageImplInfoRequest::evaluate(Evaluator &evaluator,
33583358
AbstractStorageDecl *storage) const {
33593359
if (auto *param = dyn_cast<ParamDecl>(storage)) {
33603360
return StorageImplInfo::getSimpleStored(
3361-
param->isInOut()
3362-
? StorageIsMutable
3363-
: StorageIsNotMutable);
3361+
param->isImmutableInFunctionBody()
3362+
? StorageIsNotMutable
3363+
: StorageIsMutable);
33643364
}
33653365

33663366
if (auto *var = dyn_cast<VarDecl>(storage)) {

test/SILGen/consuming_parameter.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: %target-swift-emit-silgen %s | %FileCheck %s
2+
3+
func bar(_: String) {}
4+
5+
// CHECK-LABEL: sil {{.*}} @${{.*}}3foo
6+
func foo(y: consuming String, z: String) -> () -> String {
7+
// CHECK: bb0(%0 : @owned $String, %1 : @guaranteed $String):
8+
// CHECK: [[BOX:%.*]] = alloc_box ${ var String }
9+
// CHECK: [[BOX0:%.*]] = mark_uninitialized [var] [[BOX]]
10+
// CHECK: [[BOX1:%.*]] = begin_borrow [lexical] [[BOX0]]
11+
// CHECK: [[Y:%.*]] = project_box [[BOX1]]
12+
// CHECK: store %0 to [init] [[Y]]
13+
14+
// CHECK: [[YCAPTURE:%.*]] = copy_value [[BOX1]]
15+
// CHECK: partial_apply {{.*}} {{%.*}}([[YCAPTURE]])
16+
let r = { y }
17+
18+
// CHECK: [[ZCOPY:%.*]] = copy_value %1
19+
// CHECK: [[YACCESS:%.*]] = begin_access [modify] [unknown] [[Y]]
20+
// CHECK: assign [[ZCOPY]] to [[YACCESS]]
21+
y = z
22+
23+
// CHECK: [[YACCESS:%.*]] = begin_access [read] [unknown] [[Y]]
24+
// CHECK: [[YVAL:%.*]] = load [copy] [[YACCESS]]
25+
// CHECK: apply {{%.*}}([[YVAL]]
26+
bar(y)
27+
28+
return r
29+
}

0 commit comments

Comments
 (0)