Skip to content

Commit 9d0797a

Browse files
authored
Merge pull request #71248 from xedin/init_accessors-nonmutating-big-struct
[CSApply] Teach `adjustSelfTypeForMember` about init accessors
2 parents 4c7822c + 4242ac8 commit 9d0797a

File tree

3 files changed

+76
-20
lines changed

3 files changed

+76
-20
lines changed

lib/Sema/CSApply.cpp

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7637,6 +7637,12 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
76377637
abort();
76387638
}
76397639

7640+
static bool isSelfRefInInitializer(Expr *baseExpr,
7641+
DeclContext *useDC) {
7642+
auto *CD = dyn_cast<ConstructorDecl>(useDC);
7643+
return CD && baseExpr->isSelfExprOf(CD);
7644+
}
7645+
76407646
/// Detect whether an assignment to \c baseExpr.member in the given
76417647
/// decl context can potentially be initialization of a property wrapper.
76427648
static bool isPotentialPropertyWrapperInit(Expr *baseExpr,
@@ -7649,15 +7655,19 @@ static bool isPotentialPropertyWrapperInit(Expr *baseExpr,
76497655

76507656
// Assignment to a wrapped property can only be re-written to
76517657
// initialization in an init.
7652-
auto *CD = dyn_cast<ConstructorDecl>(UseDC);
7653-
if (!CD)
7654-
return false;
7658+
return isSelfRefInInitializer(baseExpr, UseDC);
7659+
}
76557660

7656-
// This is not an assignment on self
7657-
if (!baseExpr->isSelfExprOf(CD))
7661+
/// Detect whether an assignment to \c baseExpr.member in the given
7662+
/// decl context can potentially be initialization via an init accessor.
7663+
static bool isPotentialInitViaInitAccessor(Expr *baseExpr,
7664+
ValueDecl *member,
7665+
DeclContext *useDC) {
7666+
auto *VD = dyn_cast<VarDecl>(member);
7667+
if (!(VD && VD->hasInitAccessor()))
76587668
return false;
76597669

7660-
return true;
7670+
return isSelfRefInInitializer(baseExpr, useDC);
76617671
}
76627672

76637673
/// Adjust the given type to become the self type when referring to
@@ -7694,12 +7704,13 @@ static Type adjustSelfTypeForMember(Expr *baseExpr,
76947704

76957705
// If neither the property's getter nor its setter are mutating,
76967706
// the base can be an rvalue unless the assignment is potentially
7697-
// initializing a property wrapper. If the assignment can be re-
7698-
// written to property wrapper initialization, the base type should
7699-
// be an lvalue.
7707+
// initializing a property wrapper or using init accessor. If the
7708+
// assignment can be re-written to property wrapper or init accessor
7709+
// initialization, the base type should be an lvalue.
77007710
if (!SD->isGetterMutating() &&
77017711
(!isSettableFromHere || !SD->isSetterMutating()) &&
7702-
!isPotentialPropertyWrapperInit(baseExpr, member, UseDC))
7712+
!isPotentialPropertyWrapperInit(baseExpr, member, UseDC) &&
7713+
!isPotentialInitViaInitAccessor(baseExpr, member, UseDC))
77037714
return baseObjectTy;
77047715

77057716
if (isa<SubscriptDecl>(member))

test/SILOptimizer/init_accessor_raw_sil_lowering.swift

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -429,11 +429,14 @@ func test_handling_of_nonmutating_set() {
429429
}
430430

431431
// CHECK-LABEL: sil private [ossa] @$s23assign_or_init_lowering32test_handling_of_nonmutating_setyyF4TestL_V5countADSi_tcfC : $@convention(method) (Int, @thin Test.Type) -> Test
432+
// CHECK: [[SELF:%.*]] = mark_uninitialized [rootself] %2 : $*Test
432433
// CHECK: [[INIT_VALUE:%.*]] = function_ref @$s23assign_or_init_lowering32test_handling_of_nonmutating_setyyF4TestL_V5countSivpfi : $@convention(thin) () -> Int
433434
// CHECK-NEXT: [[VALUE:%.*]] = apply [[INIT_VALUE]]() : $@convention(thin) () -> Int
434-
// CHECK: assign_or_init [init] #<abstract function>Test.count, self %3 : $*Test, value [[VALUE]] : $Int, init {{.*}} : $@noescape @callee_guaranteed (Int) -> @out Int, set {{.*}} : $@noescape @callee_guaranteed (Int) -> ()
435-
// CHECK: assign_or_init [set] #<abstract function>Test.count, self %3 : $*Test, value %0 : $Int, init {{.*}} : $@noescape @callee_guaranteed (Int) -> @out Int, set {{.*}} : $@noescape @callee_guaranteed (Int) -> ()
436-
// CHECK: assign_or_init [set] #<abstract function>Test.count, self %3 : $*Test, value [[ZERO:%.*]] : $Int, init {{.*}} : $@noescape @callee_guaranteed (Int) -> @out Int, set {{.*}} : $@noescape @callee_guaranteed (Int) -> ()
435+
// CHECK: assign_or_init [init] #<abstract function>Test.count, self [[SELF]] : $*Test, value [[VALUE]] : $Int, init {{.*}} : $@noescape @callee_guaranteed (Int) -> @out Int, set {{.*}} : $@noescape @callee_guaranteed (Int) -> ()
436+
// CHECK: [[SELF_REF:%.*]] = begin_access [read] [static] [[SELF]] : $*Test
437+
// CHECK: assign_or_init [set] #<abstract function>Test.count, self [[SELF_REF]] : $*Test, value %0 : $Int, init {{.*}} : $@noescape @callee_guaranteed (Int) -> @out Int, set {{.*}} : $@noescape @callee_guaranteed (Int) -> ()
438+
// CHECK: [[SELF_REF:%.*]] = begin_access [read] [static] [[SELF]] : $*Test
439+
// CHECK: assign_or_init [set] #<abstract function>Test.count, self [[SELF_REF]] : $*Test, value [[ZERO:%.*]] : $Int, init {{.*}} : $@noescape @callee_guaranteed (Int) -> @out Int, set {{.*}} : $@noescape @callee_guaranteed (Int) -> ()
437440
init(count: Int) {
438441
self.count = count
439442
self.count = 0
@@ -453,25 +456,28 @@ func test_handling_of_nonmutating_set() {
453456

454457
// CHECK-LABEL: sil private [ossa] @$s23assign_or_init_lowering32test_handling_of_nonmutating_setyyF14TestWithStoredL_V5countADSi_tcfC
455458
// CHECK: [[SELF_REF:%.*]] = mark_uninitialized [rootself] %2
456-
// CHECK: [[SELF:%.*]] = load [copy] {{.*}} : $*TestWithStored
459+
// CHECK: [[SELF_ACCESS:%.*]] = begin_access [read] [static] [[SELF_REF]] : $*TestWithStored
457460
// CHECK: [[SETTER_REF:%.*]] = function_ref @$s23assign_or_init_lowering32test_handling_of_nonmutating_setyyF14TestWithStoredL_V5countSivs : $@convention(method) (Int, @guaranteed TestWithStored) -> ()
461+
// CHECK: [[SELF:%.*]] = load [copy] {{.*}} : $*TestWithStored
458462
// CHECK-NEXT: [[SETTER_CLOSURE:%.*]] = partial_apply [callee_guaranteed] [on_stack] [[SETTER_REF]]([[SELF]]) : $@convention(method) (Int, @guaranteed TestWithStored) -> ()
459-
// CHECK-NEXT: assign_or_init [init] #<abstract function>TestWithStored.count, self [[SELF_REF]] : $*TestWithStored, value %0 : $Int, init {{.*}} : $@noescape @callee_guaranteed (Int) -> @out Int, set [[SETTER_CLOSURE]] : $@noescape @callee_guaranteed (Int) -> ()
463+
// CHECK-NEXT: assign_or_init [init] #<abstract function>TestWithStored.count, self [[SELF_ACCESS]] : $*TestWithStored, value %0 : $Int, init {{.*}} : $@noescape @callee_guaranteed (Int) -> @out Int, set [[SETTER_CLOSURE]] : $@noescape @callee_guaranteed (Int) -> ()
460464
init(count: Int) {
461465
self.count = count
462466
}
463467

464468
// CHECK-LABEL: sil private [ossa] @$s23assign_or_init_lowering32test_handling_of_nonmutating_setyyF14TestWithStoredL_V5valueADSi_tcfC
465-
// CHECK: [[SELF_REF:%.*]] = mark_uninitialized [rootself] %2
466-
// CHECK: [[SELF:%.*]] = load [copy] {{.*}} : $*TestWithStored
469+
// CHECK: [[SELF:%.*]] = mark_uninitialized [rootself] %2
467470
//
471+
// CHECK: [[SELF_REF:%.*]] = begin_access [read] [static] [[SELF]] : $*TestWithStored
468472
// CHECK: [[SETTER_REF:%.*]] = function_ref @$s23assign_or_init_lowering32test_handling_of_nonmutating_setyyF14TestWithStoredL_V5countSivs : $@convention(method) (Int, @guaranteed TestWithStored) -> ()
469-
// CHECK-NEXT: [[SETTER_CLOSURE:%.*]] = partial_apply [callee_guaranteed] [on_stack] [[SETTER_REF]]([[SELF]]) : $@convention(method) (Int, @guaranteed TestWithStored) -> ()
473+
// CHECK: [[SELF_COPY:%.*]] = load [copy] {{.*}} : $*TestWithStored
474+
// CHECK-NEXT: [[SETTER_CLOSURE:%.*]] = partial_apply [callee_guaranteed] [on_stack] [[SETTER_REF]]([[SELF_COPY]]) : $@convention(method) (Int, @guaranteed TestWithStored) -> ()
470475
// CHECK-NEXT: assign_or_init [init] #<abstract function>TestWithStored.count, self [[SELF_REF]] : $*TestWithStored, value {{.*}} : $Int, init {{.*}} : $@noescape @callee_guaranteed (Int) -> @out Int, set [[SETTER_CLOSURE]] : $@noescape @callee_guaranteed (Int) -> ()
471476
//
472-
// CHECK: [[SELF:%.*]] = load [copy] {{.*}} : $*TestWithStored
477+
// CHECK: [[SELF_REF:%.*]] = begin_access [read] [static] [[SELF]] : $*TestWithStored
473478
// CHECK: [[SETTER_REF:%.*]] = function_ref @$s23assign_or_init_lowering32test_handling_of_nonmutating_setyyF14TestWithStoredL_V5countSivs : $@convention(method) (Int, @guaranteed TestWithStored) -> ()
474-
// CHECK-NEXT: [[SETTER_CLOSURE:%.*]] = partial_apply [callee_guaranteed] [on_stack] [[SETTER_REF]]([[SELF]]) : $@convention(method) (Int, @guaranteed TestWithStored) -> ()
479+
// CHECK: [[SELF_COPY:%.*]] = load [copy] {{.*}} : $*TestWithStored
480+
// CHECK-NEXT: [[SETTER_CLOSURE:%.*]] = partial_apply [callee_guaranteed] [on_stack] [[SETTER_REF]]([[SELF_COPY]]) : $@convention(method) (Int, @guaranteed TestWithStored) -> ()
475481
// CHECK-NEXT: assign_or_init [set] #<abstract function>TestWithStored.count, self [[SELF_REF]] : $*TestWithStored, value %0 : $Int, init {{.*}} : $@noescape @callee_guaranteed (Int) -> @out Int, set [[SETTER_CLOSURE]] : $@noescape @callee_guaranteed (Int) -> ()
476482
init(value: Int) {
477483
self.count = 0

test/SILOptimizer/issue-68875.swift

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// RUN: %target-swift-frontend %s -emit-silgen | %FileCheck %s
2+
3+
public struct ID {
4+
var a: Int = 0
5+
var b: Int = 1
6+
var c: Int = 2
7+
var d: Int = 3
8+
var e: Int = 4
9+
var description: String = ""
10+
var mirror: Mirror
11+
}
12+
13+
struct Test {
14+
let id: ID
15+
private var _name: String
16+
17+
var name: String {
18+
@storageRestrictions(initializes: _name)
19+
init { _name = newValue }
20+
21+
get { _name }
22+
23+
nonmutating set {}
24+
}
25+
26+
// CHECK-LABEL: sil hidden [ossa] @$s4main4TestV2id4nameAcA2IDV_SStcfC : $@convention(method) (@in ID, @owned String, @thin Test.Type) -> @out Test
27+
// CHECK: [[SELF:%.*]] = project_box {{.*}} : ${ var Test }, 0
28+
// CHECK: [[SELF_REF:%.*]] = begin_access [read] [unknown] [[SELF]] : $*Test
29+
// CHECK: [[INIT_REF:%.*]] = function_ref @$s4main4TestV4nameSSvi : $@convention(thin) (@owned String, @thin Test.Type) -> @out String
30+
// CHECK-NEXT: [[METATYPE:%.*]] = metatype $@thin Test.Type
31+
// CHECK-NEXT: [[INIT:%.*]] = partial_apply [callee_guaranteed] [on_stack] [[INIT_REF]]([[METATYPE]]) : $@convention(thin) (@owned String, @thin Test.Type) -> @out String
32+
// CHECK: [[SETTER_REF:%.*]] = function_ref @$s4main4TestV4nameSSvs : $@convention(method) (@owned String, @in_guaranteed Test) -> ()
33+
// CHECK-NEXT: [[SETTER:%.*]] = partial_apply [callee_guaranteed] [on_stack] [[SETTER_REF]]([[SELF_REF]]) : $@convention(method) (@owned String, @in_guaranteed Test) -> ()
34+
// CHECK-NEXT: assign_or_init #Test.name, self [[SELF_REF]] : $*Test, value {{.*}} : $String, init [[INIT]] : $@noescape @callee_guaranteed (@owned String) -> @out String, set [[SETTER]] : $@noescape @callee_guaranteed (@owned String) -> ()
35+
init(id: ID, name: String) {
36+
self.id = id
37+
self.name = name
38+
}
39+
}

0 commit comments

Comments
 (0)