Skip to content

Commit bf2c4d9

Browse files
committed
Prevent less-visible properties with delegates from affecting memberwise initializer
When a property with an attached delegate has less-than-internal visibility and is initialized, don’t put it into the memberwise initializer because doing so lowers the access level of the memberwise initializer, making it fairly useless. Longer term, it probably makes sense to have several memberwise initializers at different access levels, so adding an initialized `private var` make the memberwise initializer useless throughout the rest of the module. Addresses rdar://problem/50266245.
1 parent 27e7bd8 commit bf2c4d9

File tree

4 files changed

+37
-10
lines changed

4 files changed

+37
-10
lines changed

lib/AST/Decl.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5316,6 +5316,18 @@ bool VarDecl::isMemberwiseInitialized(bool preferDeclaredProperties) const {
53165316
if (isLet() && isParentInitialized())
53175317
return false;
53185318

5319+
// Properties with attached delegates that have an access level < internal
5320+
// but do have an initializer don't participate in the memberwise
5321+
// initializer, because they would arbitrarily lower the access of the
5322+
// memberwise initializer.
5323+
auto origVar = this;
5324+
if (auto origDelegate = getOriginalDelegatedProperty())
5325+
origVar = origDelegate;
5326+
if (origVar->getFormalAccess() < AccessLevel::Internal &&
5327+
origVar->getAttachedPropertyDelegate() &&
5328+
origVar->isParentInitialized())
5329+
return false;
5330+
53195331
return true;
53205332
}
53215333

lib/Sema/CodeSynthesis.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1584,6 +1584,9 @@ PropertyDelegateBackingPropertyInfoRequest::evaluate(Evaluator &evaluator,
15841584
if (parentPBD->isInitialized(patternNumber) &&
15851585
!parentPBD->isInitializerChecked(patternNumber)) {
15861586
auto &tc = *static_cast<TypeChecker *>(ctx.getLazyResolver());
1587+
if (!var->hasType())
1588+
tc.validateDecl(var);
1589+
15871590
tc.typeCheckPatternBinding(parentPBD, patternNumber);
15881591
}
15891592

test/SILGen/property_delegates.swift

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -103,15 +103,9 @@ func forceHasMemberwiseInit() {
103103

104104
// CHECK: return
105105

106-
// CHECK-LABEL: sil private [ossa] @$s18property_delegates9HasNestedV1yACyxGSayxG_tc33_
107-
// CHECK: [[STACK_SLOT:%.*]] = alloc_stack $HasNested<T>.PrivateDelegate<Array<T>>
108-
// CHECK: [[METATYPE:%.*]] = metatype $@thin HasNested<T>.PrivateDelegate<Array<T>>.Type
109-
// CHECK: [[ARRAY_STACK_SLOT:%.*]] = alloc_stack $Array<T>
110-
// CHECK: store %0 to [init] [[ARRAY_STACK_SLOT]] : $*Array<T>
111-
// CHECK: [[INIT:%.*]] = function_ref @$s18property_delegates9HasNestedV15PrivateDelegate{{.*}}initialValue
112-
// CHECK: [[DELEGATE_INSTANCE:%.*]] = apply [[INIT]]<T, [T]>([[STACK_SLOT]], [[ARRAY_STACK_SLOT]], [[METATYPE]])
113-
// CHECK: [[DELEGATE_VALUE:%.*]] = load [take] [[STACK_SLOT]] : $*HasNested<T>.PrivateDelegate<Array<T>>
114-
// CHECK: struct $HasNested<T> ([[DELEGATE_VALUE]] : $HasNested<T>.PrivateDelegate<Array<T>>)
106+
// CHECK-LABEL: sil hidden [transparent] [ossa] @$s18property_delegates9HasNestedV2$y33_4EEAE04FCFB319F460A84BF3BE29C303LLAC15PrivateDelegateAELLVyx_SayxGGvpfi : $@convention(thin) <T> () -> @owned Array<T> {
107+
// CHECK: bb0:
108+
// CHECK: function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF
115109
struct HasNested<T> {
116110
@_propertyDelegate
117111
private struct PrivateDelegate<U> {
@@ -125,7 +119,7 @@ struct HasNested<T> {
125119
private var y: [T] = []
126120

127121
static func blah(y: [T]) -> HasNested<T> {
128-
return HasNested<T>(y: y)
122+
return HasNested<T>()
129123
}
130124
}
131125

test/decl/var/property_delegates.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,24 @@ func testDefaultInitializers() {
610610
_ = NoDefaultInitializerStruct() // expected-error{{missing argument for parameter 'x' in call}}
611611
}
612612

613+
struct DefaultedPrivateMemberwiseLets {
614+
@Wrapper(value: true)
615+
private var x: Bool
616+
617+
@WrapperWithInitialValue
618+
var y: Int = 17
619+
620+
@WrapperWithInitialValue(initialValue: 17)
621+
private var z: Int
622+
}
623+
624+
func testDefaultedPrivateMemberwiseLets() {
625+
_ = DefaultedPrivateMemberwiseLets()
626+
_ = DefaultedPrivateMemberwiseLets(y: 42)
627+
_ = DefaultedPrivateMemberwiseLets(x: Wrapper(value: false)) // expected-error{{incorrect argument label in call (have 'x:', expected 'y:')}}
628+
}
629+
630+
613631
// ---------------------------------------------------------------------------
614632
// Storage references
615633
// ---------------------------------------------------------------------------

0 commit comments

Comments
 (0)