Skip to content

Commit 4242ac8

Browse files
committed
[CSApply] Teach adjustSelfTypeForMember about init accessors
`adjustSelfTypeForMember` shouldn't load base if member reference is a potential init accessor use, the proper use of `self` would be determined during lowering of the `assign_or_init` instruction and defensive load for `nonmutating` sets is unnecessary in this case.
1 parent 0cc5297 commit 4242ac8

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
@@ -7578,6 +7578,12 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
75787578
abort();
75797579
}
75807580

7581+
static bool isSelfRefInInitializer(Expr *baseExpr,
7582+
DeclContext *useDC) {
7583+
auto *CD = dyn_cast<ConstructorDecl>(useDC);
7584+
return CD && baseExpr->isSelfExprOf(CD);
7585+
}
7586+
75817587
/// Detect whether an assignment to \c baseExpr.member in the given
75827588
/// decl context can potentially be initialization of a property wrapper.
75837589
static bool isPotentialPropertyWrapperInit(Expr *baseExpr,
@@ -7590,15 +7596,19 @@ static bool isPotentialPropertyWrapperInit(Expr *baseExpr,
75907596

75917597
// Assignment to a wrapped property can only be re-written to
75927598
// initialization in an init.
7593-
auto *CD = dyn_cast<ConstructorDecl>(UseDC);
7594-
if (!CD)
7595-
return false;
7599+
return isSelfRefInInitializer(baseExpr, UseDC);
7600+
}
75967601

7597-
// This is not an assignment on self
7598-
if (!baseExpr->isSelfExprOf(CD))
7602+
/// Detect whether an assignment to \c baseExpr.member in the given
7603+
/// decl context can potentially be initialization via an init accessor.
7604+
static bool isPotentialInitViaInitAccessor(Expr *baseExpr,
7605+
ValueDecl *member,
7606+
DeclContext *useDC) {
7607+
auto *VD = dyn_cast<VarDecl>(member);
7608+
if (!(VD && VD->hasInitAccessor()))
75997609
return false;
76007610

7601-
return true;
7611+
return isSelfRefInInitializer(baseExpr, useDC);
76027612
}
76037613

76047614
/// Adjust the given type to become the self type when referring to
@@ -7635,12 +7645,13 @@ static Type adjustSelfTypeForMember(Expr *baseExpr,
76357645

76367646
// If neither the property's getter nor its setter are mutating,
76377647
// the base can be an rvalue unless the assignment is potentially
7638-
// initializing a property wrapper. If the assignment can be re-
7639-
// written to property wrapper initialization, the base type should
7640-
// be an lvalue.
7648+
// initializing a property wrapper or using init accessor. If the
7649+
// assignment can be re-written to property wrapper or init accessor
7650+
// initialization, the base type should be an lvalue.
76417651
if (!SD->isGetterMutating() &&
76427652
(!isSettableFromHere || !SD->isSetterMutating()) &&
7643-
!isPotentialPropertyWrapperInit(baseExpr, member, UseDC))
7653+
!isPotentialPropertyWrapperInit(baseExpr, member, UseDC) &&
7654+
!isPotentialInitViaInitAccessor(baseExpr, member, UseDC))
76447655
return baseObjectTy;
76457656

76467657
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)