Skip to content

Commit 05bfc28

Browse files
committed
Mark lazy properties as having mutating getters immediately.
We were trying to do this when synthesizing the getter prototype, but we don't do that immediately when we're just type-checking a reference to the storage, which could lead to the reference thinking that the getter was non-mutating. Fixes rdar://45712204.
1 parent 252a204 commit 05bfc28

File tree

4 files changed

+18
-6
lines changed

4 files changed

+18
-6
lines changed

lib/Sema/CodeSynthesis.cpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -189,12 +189,6 @@ static AccessorDecl *createGetterPrototype(TypeChecker &TC,
189189
ParamDecl *selfDecl = nullptr;
190190
if (storage->getDeclContext()->isTypeContext()) {
191191
if (storage->getAttrs().hasAttribute<LazyAttr>()) {
192-
// The getter is considered mutating if it's on a value type.
193-
if (!storage->getDeclContext()->getSelfClassDecl() &&
194-
!storage->isStatic()) {
195-
storage->setIsGetterMutating(true);
196-
}
197-
198192
// For lazy properties, steal the 'self' from the initializer context.
199193
auto *varDecl = cast<VarDecl>(storage);
200194
auto *bindingDecl = varDecl->getParentPatternBinding();

lib/Sema/TypeCheckDecl.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2280,6 +2280,15 @@ static bool validateAccessorIsMutating(TypeChecker &TC, FuncDecl *accessor) {
22802280

22812281
static bool computeIsGetterMutating(TypeChecker &TC,
22822282
AbstractStorageDecl *storage) {
2283+
// 'lazy' overrides the normal accessor-based rules and heavily
2284+
// restricts what accessors can be used. The getter is considered
2285+
// mutating if this is instance storage on a value type.
2286+
if (storage->getAttrs().hasAttribute<LazyAttr>()) {
2287+
return storage->getDeclContext()->isTypeContext() &&
2288+
!storage->getDeclContext()->getSelfClassDecl() &&
2289+
!storage->isStatic();
2290+
}
2291+
22832292
switch (storage->getReadImpl()) {
22842293
case ReadImplKind::Stored:
22852294
return false;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
public struct Test1 {
2+
lazy var property: String = "help"
3+
}

test/multifile/lazy.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// RUN: %target-swift-frontend -emit-sil -verify -primary-file %s %S/Inputs/external_lazy_property.swift
2+
3+
// rdar://45712204
4+
func test1(s: Test1) {
5+
s.property // expected-error {{cannot use mutating getter on immutable value: 's' is a 'let' constant}}
6+
}

0 commit comments

Comments
 (0)