Skip to content

Commit 830eebb

Browse files
authored
Merge pull request #24390 from DougGregor/property-delegates-private-memberwise-inits
Prevent less-visible properties with delegates from affecting memberwise initializer
2 parents 26dc092 + bf2c4d9 commit 830eebb

File tree

5 files changed

+55
-29
lines changed

5 files changed

+55
-29
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/SILGen/SILGenConstructor.cpp

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -177,32 +177,31 @@ static void emitImplicitValueConstructor(SILGenFunction &SGF,
177177
fieldTy.getAddressType());
178178
InitializationPtr init(new KnownAddressInitialization(slot));
179179

180-
// An initialized 'let' property has a single value specified by the
181-
// initializer - it doesn't come from an argument.
182-
if (!field->isStatic() && field->isLet() &&
183-
field->getParentInitializer()) {
180+
// If it's memberwise initialized, do so now.
181+
if (field->isMemberwiseInitialized(/*preferDeclaredProperties=*/false)) {
182+
assert(elti != eltEnd &&
183+
"number of args does not match number of fields");
184+
(void)eltEnd;
185+
FullExpr scope(SGF.Cleanups, field->getParentPatternBinding());
186+
if (!maybeEmitPropertyDelegateInitFromValue(
187+
SGF, Loc, field, std::move(*elti),
188+
[&](Expr *expr) {
189+
SGF.emitExprInto(expr, init.get());
190+
})) {
191+
std::move(*elti).forwardInto(SGF, Loc, init.get());
192+
}
193+
++elti;
194+
} else {
184195
#ifndef NDEBUG
185-
assert(field->getType()->isEqual(field->getParentInitializer()->getType())
186-
&& "Checked by sema");
196+
assert(
197+
field->getType()->isEqual(field->getParentInitializer()->getType())
198+
&& "Checked by sema");
187199
#endif
188200

189201
// Cleanup after this initialization.
190202
FullExpr scope(SGF.Cleanups, field->getParentPatternBinding());
191203
SGF.emitExprInto(field->getParentInitializer(), init.get());
192-
continue;
193204
}
194-
195-
assert(elti != eltEnd && "number of args does not match number of fields");
196-
(void)eltEnd;
197-
FullExpr scope(SGF.Cleanups, field->getParentPatternBinding());
198-
if (!maybeEmitPropertyDelegateInitFromValue(
199-
SGF, Loc, field, std::move(*elti),
200-
[&](Expr *expr) {
201-
SGF.emitExprInto(expr, init.get());
202-
})) {
203-
std::move(*elti).forwardInto(SGF, Loc, init.get());
204-
}
205-
++elti;
206205
}
207206
SGF.B.createReturn(ImplicitReturnLocation::getImplicitReturnLoc(Loc),
208207
SGF.emitEmptyTuple(Loc));

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)