Skip to content

Commit 3a91280

Browse files
committed
Sema: Diagnose 'lazy' variable initializer with effect
This used to crash in SILGen. Fixes #60128 Fixes #60129
1 parent 1b9d80a commit 3a91280

File tree

3 files changed

+47
-18
lines changed

3 files changed

+47
-18
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5302,14 +5302,22 @@ ERROR(tryless_throwing_call_in_nonexhaustive_catch,none,
53025302
ERROR(throw_in_nonexhaustive_catch,none,
53035303
"error is not handled because the enclosing catch is not exhaustive", ())
53045304

5305+
#define EFFECTS_CONTEXT_KIND \
5306+
"%select{<<ERROR>>|" \
5307+
"a default argument|" \
5308+
"a property wrapper initializer|" \
5309+
"a property initializer|" \
5310+
"a global variable initializer|" \
5311+
"a lazy variable initializer|" \
5312+
"an enum case raw value|" \
5313+
"a catch pattern|" \
5314+
"a catch guard expression|" \
5315+
"a defer body}" \
5316+
53055317
ERROR(throwing_op_in_illegal_context,none,
5306-
"%1 can throw, but errors cannot be thrown out of "
5307-
"%select{<<ERROR>>|a default argument|a property wrapper initializer|a property initializer|a global variable initializer|an enum case raw value|a catch pattern|a catch guard expression|a defer body}0",
5308-
(unsigned, StringRef))
5318+
"%1 can throw, but errors cannot be thrown out of " EFFECTS_CONTEXT_KIND "0", (unsigned, StringRef))
53095319
ERROR(throw_in_illegal_context,none,
5310-
"errors cannot be thrown out of "
5311-
"%select{<<ERROR>>|a default argument|a property wrapper initializer|a property initializer|a global variable initializer|an enum case raw value|a catch pattern|a catch guard expression|a defer body}0",
5312-
(unsigned))
5320+
"errors cannot be thrown out of " EFFECTS_CONTEXT_KIND "0", (unsigned))
53135321

53145322
ERROR(throwing_operator_without_try,none,
53155323
"operator can throw but expression is not marked with 'try'", ())
@@ -5405,17 +5413,6 @@ ERROR(async_let_no_variables,none,
54055413
NOTE(async_let_without_await,none,
54065414
"reference to async let %0 is 'async'", (const ValueDecl *))
54075415

5408-
#define EFFECTS_CONTEXT_KIND \
5409-
"%select{<<ERROR>>|" \
5410-
"a default argument|" \
5411-
"a property wrapper initializer|" \
5412-
"a property initializer|" \
5413-
"a global variable initializer|" \
5414-
"an enum case raw value|" \
5415-
"a catch pattern|" \
5416-
"a catch guard expression|" \
5417-
"a defer body}" \
5418-
54195416
ERROR(async_call_in_illegal_context,none,
54205417
"'async' call cannot occur in " EFFECTS_CONTEXT_KIND "0",
54215418
(unsigned))

lib/Sema/TypeCheckEffects.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,10 @@ template <class Impl>
509509
class EffectsHandlingWalker : public ASTWalker {
510510
Impl &asImpl() { return *static_cast<Impl*>(this); }
511511
public:
512+
LazyInitializerWalking getLazyInitializerWalkingBehavior() override {
513+
return LazyInitializerWalking::InAccessor;
514+
}
515+
512516
/// Only look at the expansions for effects checking.
513517
MacroWalking getMacroWalkingBehavior() const override {
514518
return MacroWalking::Expansion;
@@ -940,7 +944,7 @@ class Classification {
940944
ConditionalEffectKind conditionalKind,
941945
PotentialEffectReason reason) {
942946
Classification result;
943-
if (!thrownError || isNeverThrownError(thrownError))
947+
if (isNeverThrownError(thrownError))
944948
return result;
945949

946950
assert(!thrownError->hasError());
@@ -2086,6 +2090,9 @@ class Context {
20862090
/// The initializer for a global variable.
20872091
GlobalVarInitializer,
20882092

2093+
/// The initializer for a `lazy` variable.
2094+
LazyVarInitializer,
2095+
20892096
/// The initializer for an enum element.
20902097
EnumElementInitializer,
20912098

@@ -2101,8 +2108,12 @@ class Context {
21012108

21022109
private:
21032110
static Context getContextForPatternBinding(PatternBindingDecl *pbd) {
2111+
auto *var = pbd->getSingleVar();
2112+
21042113
if (!pbd->isStatic() && pbd->getDeclContext()->isTypeContext()) {
21052114
return Context(Kind::IVarInitializer, pbd->getDeclContext());
2115+
} else if (var && var->getAttrs().hasAttribute<LazyAttr>()) {
2116+
return Context(Kind::LazyVarInitializer, pbd->getDeclContext());
21062117
} else {
21072118
return Context(Kind::GlobalVarInitializer, pbd->getDeclContext());
21082119
}
@@ -2520,6 +2531,7 @@ class Context {
25202531

25212532
case Kind::EnumElementInitializer:
25222533
case Kind::GlobalVarInitializer:
2534+
case Kind::LazyVarInitializer:
25232535
case Kind::IVarInitializer:
25242536
case Kind::DefaultArgument:
25252537
case Kind::PropertyWrapper:
@@ -2556,6 +2568,7 @@ class Context {
25562568

25572569
case Kind::EnumElementInitializer:
25582570
case Kind::GlobalVarInitializer:
2571+
case Kind::LazyVarInitializer:
25592572
case Kind::IVarInitializer:
25602573
case Kind::DefaultArgument:
25612574
case Kind::PropertyWrapper:
@@ -2582,6 +2595,7 @@ class Context {
25822595

25832596
case Kind::EnumElementInitializer:
25842597
case Kind::GlobalVarInitializer:
2598+
case Kind::LazyVarInitializer:
25852599
case Kind::IVarInitializer:
25862600
case Kind::DefaultArgument:
25872601
case Kind::PropertyWrapper:
@@ -2691,6 +2705,7 @@ class Context {
26912705

26922706
case Kind::EnumElementInitializer:
26932707
case Kind::GlobalVarInitializer:
2708+
case Kind::LazyVarInitializer:
26942709
case Kind::IVarInitializer:
26952710
case Kind::DefaultArgument:
26962711
case Kind::PropertyWrapper:
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// RUN: %target-typecheck-verify-swift -disable-availability-checking
2+
3+
// We could make this work by having `lazy` synthesize an effectful
4+
// getter, but for now let's reject it instead of crashing.
5+
6+
func throwsFunc() throws -> Int { return 3 }
7+
func asyncFunc() async -> Int { return 3 }
8+
9+
func localLazyWithEffects() {
10+
lazy var x = try throwsFunc() // expected-error {{call can throw, but errors cannot be thrown out of a lazy variable initializer}}
11+
lazy var y = await asyncFunc() // expected-error {{'async' call cannot occur in a lazy variable initializer}}
12+
}
13+
14+
struct InstanceLazyWithEffects {
15+
lazy var x = try throwsFunc() // expected-error {{call can throw, but errors cannot be thrown out of a property initializer}}
16+
lazy var y = await asyncFunc() // expected-error {{'async' call cannot occur in a property initializer}}
17+
}

0 commit comments

Comments
 (0)