Skip to content

Commit e434bdb

Browse files
authored
Merge pull request swiftlang#25129 from DougGregor/property-wrappers-minor-fixes
[SE-0258] Minor adjustments to bring implementation closer to the proposal
2 parents 46f130a + a3701cb commit e434bdb

File tree

6 files changed

+80
-44
lines changed

6 files changed

+80
-44
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4379,6 +4379,9 @@ ERROR(property_delegate_local,none,
43794379
ERROR(property_delegate_let, none,
43804380
"property delegate can only be applied to a 'var'",
43814381
())
4382+
ERROR(property_delegate_computed, none,
4383+
"property delegate cannot be applied to a computed property",
4384+
())
43824385

43834386
ERROR(property_with_delegate_conflict_attribute,none,
43844387
"property %0 with a delegate cannot also be "

lib/Sema/DerivedConformanceCodable.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,14 @@ static CodableConformanceType varConformsToCodable(TypeChecker &tc,
135135
isIUO, proto);
136136
}
137137

138+
/// Retrieve the variable name for the purposes of encoding/decoding.
139+
static Identifier getVarNameForCoding(VarDecl *var) {
140+
if (auto originalVar = var->getOriginalDelegatedProperty())
141+
return originalVar->getName();
142+
143+
return var->getName();
144+
}
145+
138146
/// Validates the given CodingKeys enum decl by ensuring its cases are a 1-to-1
139147
/// match with the stored vars of the given type.
140148
///
@@ -161,7 +169,7 @@ static bool validateCodingKeysEnum(DerivedConformance &derived,
161169
if (varDecl->getAttrs().hasAttribute<LazyAttr>())
162170
continue;
163171

164-
properties[varDecl->getName()] = varDecl;
172+
properties[getVarNameForCoding(varDecl)] = varDecl;
165173
}
166174

167175
bool propertiesAreValid = true;
@@ -364,7 +372,8 @@ static EnumDecl *synthesizeCodingKeysEnum(DerivedConformance &derived) {
364372
switch (conformance) {
365373
case Conforms:
366374
{
367-
auto *elt = new (C) EnumElementDecl(SourceLoc(), varDecl->getName(),
375+
auto *elt = new (C) EnumElementDecl(SourceLoc(),
376+
getVarNameForCoding(varDecl),
368377
nullptr, SourceLoc(), nullptr,
369378
enumDecl);
370379
elt->setImplicit();
@@ -517,6 +526,11 @@ lookupVarDeclForCodingKeysCase(DeclContext *conformanceDC,
517526
NominalTypeDecl *targetDecl) {
518527
for (auto decl : targetDecl->lookupDirect(DeclName(elt->getName()))) {
519528
if (auto *vd = dyn_cast<VarDecl>(decl)) {
529+
// If we found a property with an attached delegate, retrieve the
530+
// backing property.
531+
if (auto backingVar = vd->getPropertyDelegateBackingProperty())
532+
vd = backingVar;
533+
520534
if (!vd->isStatic()) {
521535
// This is the VarDecl we're looking for.
522536

lib/Sema/TypeCheckPropertyDelegate.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,8 @@ AttachedPropertyDelegateRequest::evaluate(Evaluator &evaluator,
265265

266266
// If the declaration came from a module file, we've already done all of
267267
// the semantic checking required.
268-
if (!dc->getParentSourceFile())
268+
auto sourceFile = dc->getParentSourceFile();
269+
if (!sourceFile)
269270
return mutableAttr;
270271

271272
// Check various restrictions on which properties can have delegates
@@ -343,6 +344,12 @@ AttachedPropertyDelegateRequest::evaluate(Evaluator &evaluator,
343344
}
344345
}
345346

347+
// Properties with delegates must not declare a getter or setter.
348+
if (!var->hasStorage() && sourceFile->Kind != SourceFileKind::Interface) {
349+
ctx.Diags.diagnose(attr->getLocation(), diag::property_delegate_computed);
350+
return nullptr;
351+
}
352+
346353
return mutableAttr;
347354
}
348355

test/SILGen/property_delegates.swift

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -142,17 +142,12 @@ struct HasDefaultInit {
142142

143143
struct DelegateWithAccessors {
144144
@Wrapper
145-
var x: Int {
146-
// CHECK-LABEL: sil hidden [ossa] @$s18property_delegates21DelegateWithAccessorsV1xSivg
147-
// CHECK-NOT: return
148-
// CHECK: integer_literal $Builtin.IntLiteral, 42
149-
return 42
150-
151-
// Synthesized setter
152-
// CHECK-LABEL: sil hidden [transparent] [ossa] @$s18property_delegates21DelegateWithAccessorsV1xSivs : $@convention(method) (Int, @inout DelegateWithAccessors) -> ()
153-
// CHECK-NOT: return
154-
// CHECK: struct_element_addr {{%.*}} : $*DelegateWithAccessors, #DelegateWithAccessors.$x
155-
}
145+
var x: Int
146+
147+
// Synthesized setter
148+
// CHECK-LABEL: sil hidden [transparent] [ossa] @$s18property_delegates21DelegateWithAccessorsV1xSivs : $@convention(method) (Int, @inout DelegateWithAccessors) -> ()
149+
// CHECK-NOT: return
150+
// CHECK: struct_element_addr {{%.*}} : $*DelegateWithAccessors, #DelegateWithAccessors.$x
156151

157152
mutating func test() {
158153
x = 17
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// RUN: %target-typecheck-verify-swift -verify-ignore-unknown
2+
3+
@_propertyDelegate
4+
struct Wrapper<T: Codable> {
5+
var value: T
6+
}
7+
8+
@_propertyDelegate
9+
struct WrapperWithInitialValue<T: Codable> {
10+
var value: T
11+
12+
init(initialValue: T) {
13+
self.value = initialValue
14+
}
15+
}
16+
17+
extension WrapperWithInitialValue: Codable { }
18+
19+
struct X: Codable {
20+
@WrapperWithInitialValue var foo = 17
21+
22+
// Make sure the generated key is named 'foo', like the original property.
23+
private func getFooKey() -> CodingKeys {
24+
return .foo
25+
}
26+
}
27+
28+
29+
30+
// expected-error@+2{{type 'Y' does not conform to protocol 'Encodable'}}
31+
// expected-error@+1{{type 'Y' does not conform to protocol 'Decodable'}}
32+
struct Y: Codable {
33+
@Wrapper var foo: Int
34+
// expected-note@-1{{cannot automatically synthesize 'Encodable' because 'Wrapper<Int>' does not conform to 'Encodable'}}
35+
// expected-note@-2{{cannot automatically synthesize 'Decodable' because 'Wrapper<Int>' does not conform to 'Decodable'}}
36+
37+
}

test/decl/var/property_delegates.swift

Lines changed: 10 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,13 @@ class Superclass {
169169
var x: Int = 0
170170
}
171171

172+
class SubclassOfClassWithDelegates: ClassWithDelegates {
173+
override var x: Int {
174+
get { return $x.value }
175+
set { $x.value = newValue }
176+
}
177+
}
178+
172179
class SubclassWithDelegate: Superclass {
173180
@Wrapper(value: 17)
174181
override var x: Int { get { return 0 } set { } } // expected-error{{property 'x' with attached delegate cannot override another property}}
@@ -315,25 +322,9 @@ func testBackingStore<T>(bs: BackingStore<T>) {
315322
// Explicitly-specified accessors
316323
// ---------------------------------------------------------------------------
317324
struct DelegateWithAccessors {
318-
@Wrapper
325+
@Wrapper // expected-error{{property delegate cannot be applied to a computed property}}
319326
var x: Int {
320-
return $x.value * 2
321-
}
322-
323-
@WrapperWithInitialValue
324-
var y: Int {
325-
get {
326-
return $y.value
327-
}
328-
329-
set {
330-
$y.value = newValue / 2
331-
}
332-
}
333-
334-
mutating func test() {
335-
x = y
336-
y = x
327+
return 17
337328
}
338329
}
339330

@@ -513,24 +504,13 @@ class Box<Value> {
513504
struct UseBox {
514505
@Box
515506
var x = 17
516-
517-
@Box
518-
var y: Int {
519-
get { return $y.value }
520-
set { }
521-
}
522507
}
523508

524509
func testBox(ub: UseBox) {
525510
_ = ub.x
526511
ub.x = 5 // expected-error{{cannot assign to property: 'x' is a get-only property}}
527512

528-
_ = ub.y
529-
ub.y = 20 // expected-error{{cannot assign to property: 'ub' is a 'let' constant}}
530-
531513
var mutableUB = ub
532-
_ = mutableUB.y
533-
mutableUB.y = 20
534514
mutableUB = ub
535515
}
536516

@@ -593,7 +573,7 @@ struct NoDefaultInitializerStruct { // expected-note{{'init(x:)' declared here}}
593573

594574
class DefaultInitializerClass {
595575
@Wrapper(value: true)
596-
final var x
576+
var x
597577

598578
@WrapperWithInitialValue
599579
final var y: Int = 10

0 commit comments

Comments
 (0)