Skip to content

Commit e83689c

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

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
@@ -5261,14 +5261,22 @@ ERROR(tryless_throwing_call_in_nonexhaustive_catch,none,
52615261
ERROR(throw_in_nonexhaustive_catch,none,
52625262
"error is not handled because the enclosing catch is not exhaustive", ())
52635263

5264+
#define EFFECTS_CONTEXT_KIND \
5265+
"%select{<<ERROR>>|" \
5266+
"a default argument|" \
5267+
"a property wrapper initializer|" \
5268+
"a property initializer|" \
5269+
"a global variable initializer|" \
5270+
"a lazy variable initializer|" \
5271+
"an enum case raw value|" \
5272+
"a catch pattern|" \
5273+
"a catch guard expression|" \
5274+
"a defer body}" \
5275+
52645276
ERROR(throwing_op_in_illegal_context,none,
5265-
"%1 can throw, but errors cannot be thrown out of "
5266-
"%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",
5267-
(unsigned, StringRef))
5277+
"%1 can throw, but errors cannot be thrown out of " EFFECTS_CONTEXT_KIND "0", (unsigned, StringRef))
52685278
ERROR(throw_in_illegal_context,none,
5269-
"errors cannot be thrown out of "
5270-
"%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",
5271-
(unsigned))
5279+
"errors cannot be thrown out of " EFFECTS_CONTEXT_KIND "0", (unsigned))
52725280

52735281
ERROR(throwing_operator_without_try,none,
52745282
"operator can throw but expression is not marked with 'try'", ())
@@ -5364,17 +5372,6 @@ ERROR(async_let_no_variables,none,
53645372
NOTE(async_let_without_await,none,
53655373
"reference to async let %0 is 'async'", (const ValueDecl *))
53665374

5367-
#define EFFECTS_CONTEXT_KIND \
5368-
"%select{<<ERROR>>|" \
5369-
"a default argument|" \
5370-
"a property wrapper initializer|" \
5371-
"a property initializer|" \
5372-
"a global variable initializer|" \
5373-
"an enum case raw value|" \
5374-
"a catch pattern|" \
5375-
"a catch guard expression|" \
5376-
"a defer body}" \
5377-
53785375
ERROR(async_call_in_illegal_context,none,
53795376
"'async' call cannot occur in " EFFECTS_CONTEXT_KIND "0",
53805377
(unsigned))

lib/Sema/TypeCheckEffects.cpp

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

945949
assert(!thrownError->hasError());
@@ -2085,6 +2089,9 @@ class Context {
20852089
/// The initializer for a global variable.
20862090
GlobalVarInitializer,
20872091

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

@@ -2100,8 +2107,12 @@ class Context {
21002107

21012108
private:
21022109
static Context getContextForPatternBinding(PatternBindingDecl *pbd) {
2110+
auto *var = pbd->getSingleVar();
2111+
21032112
if (!pbd->isStatic() && pbd->getDeclContext()->isTypeContext()) {
21042113
return Context(Kind::IVarInitializer, pbd->getDeclContext());
2114+
} else if (var && var->getAttrs().hasAttribute<LazyAttr>()) {
2115+
return Context(Kind::LazyVarInitializer, pbd->getDeclContext());
21052116
} else {
21062117
return Context(Kind::GlobalVarInitializer, pbd->getDeclContext());
21072118
}
@@ -2519,6 +2530,7 @@ class Context {
25192530

25202531
case Kind::EnumElementInitializer:
25212532
case Kind::GlobalVarInitializer:
2533+
case Kind::LazyVarInitializer:
25222534
case Kind::IVarInitializer:
25232535
case Kind::DefaultArgument:
25242536
case Kind::PropertyWrapper:
@@ -2555,6 +2567,7 @@ class Context {
25552567

25562568
case Kind::EnumElementInitializer:
25572569
case Kind::GlobalVarInitializer:
2570+
case Kind::LazyVarInitializer:
25582571
case Kind::IVarInitializer:
25592572
case Kind::DefaultArgument:
25602573
case Kind::PropertyWrapper:
@@ -2581,6 +2594,7 @@ class Context {
25812594

25822595
case Kind::EnumElementInitializer:
25832596
case Kind::GlobalVarInitializer:
2597+
case Kind::LazyVarInitializer:
25842598
case Kind::IVarInitializer:
25852599
case Kind::DefaultArgument:
25862600
case Kind::PropertyWrapper:
@@ -2690,6 +2704,7 @@ class Context {
26902704

26912705
case Kind::EnumElementInitializer:
26922706
case Kind::GlobalVarInitializer:
2707+
case Kind::LazyVarInitializer:
26932708
case Kind::IVarInitializer:
26942709
case Kind::DefaultArgument:
26952710
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)