Skip to content

Commit cb91bfa

Browse files
authored
Merge pull request #21399 from slavapestov/lazy-capture-order-5.0
Sema: Fix order dependency between lazy getter body synthesis and capture computation [5.0]
2 parents 2a216c9 + 5c11c10 commit cb91bfa

File tree

4 files changed

+28
-14
lines changed

4 files changed

+28
-14
lines changed

lib/Sema/CodeSynthesis.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -226,10 +226,10 @@ static AccessorDecl *createGetterPrototype(TypeChecker &TC,
226226
getter->setImplicit();
227227

228228
// If we're stealing the 'self' from a lazy initializer, set it now.
229-
if (selfDecl) {
229+
// Note that we don't re-parent the 'self' declaration to be part of
230+
// the getter until we synthesize the body of the getter later.
231+
if (selfDecl)
230232
*getter->getImplicitSelfDeclStorage() = selfDecl;
231-
selfDecl->setDeclContext(getter);
232-
}
233233

234234
// We need to install the generic environment here because:
235235
// 1) validating the getter will change the implicit self decl's DC to it,
@@ -1315,6 +1315,7 @@ static void synthesizeLazyGetterBody(TypeChecker &TC, AccessorDecl *Get,
13151315

13161316
// Recontextualize any closure declcontexts nested in the initializer to
13171317
// realize that they are in the getter function.
1318+
Get->getImplicitSelfDecl()->setDeclContext(Get);
13181319
InitValue->walk(RecontextualizeClosures(Get));
13191320

13201321
// Wrap the initializer in a LazyInitializerExpr to avoid problems with

lib/Sema/TypeCheckCaptures.cpp

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -283,15 +283,14 @@ class FindCapturedVars : public ASTWalker {
283283
// recontextualized into it, so treat it as if it's already there.
284284
if (auto init = dyn_cast<PatternBindingInitializer>(TmpDC)) {
285285
if (auto lazyVar = init->getInitializedLazyVar()) {
286-
// Referring to the 'self' parameter is fine.
287-
if (D == init->getImplicitSelfDecl())
288-
return { false, DRE };
289-
290-
// Otherwise, act as if we're in the getter.
291-
auto getter = lazyVar->getGetter();
292-
assert(getter && "lazy variable without getter");
293-
TmpDC = getter;
294-
continue;
286+
// If we have a getter with a body, we're already re-parented
287+
// everything so pretend we're inside the getter.
288+
if (auto getter = lazyVar->getGetter()) {
289+
if (getter->getBody(/*canSynthesize=*/false)) {
290+
TmpDC = getter;
291+
continue;
292+
}
293+
}
295294
}
296295
}
297296

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
11
public struct Test1 {
2-
lazy var property: String = "help"
2+
lazy var property: String = "help"
3+
}
4+
5+
public class Test2 {
6+
var x = 0
7+
var y = 1
8+
9+
lazy var property = {
10+
return [self.x, self.y]
11+
}()
312
}

test/multifile/lazy.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
// RUN: %target-swift-frontend -emit-sil -verify -primary-file %s %S/Inputs/external_lazy_property.swift
2+
// RUN: %target-swift-frontend -emit-sil -verify -primary-file %s -primary-file %S/Inputs/external_lazy_property.swift
23

34
// rdar://45712204
45
func test1(s: Test1) {
5-
s.property // expected-error {{cannot use mutating getter on immutable value: 's' is a 'let' constant}}
6+
_ = s.property // expected-error {{cannot use mutating getter on immutable value: 's' is a 'let' constant}}
7+
}
8+
9+
func test2(s: Test2) {
10+
_ = s.property
611
}

0 commit comments

Comments
 (0)