Skip to content

Commit 4280e0a

Browse files
stereotype441commit-bot@chromium.org
authored andcommitted
Fix crash when a null shorting expression is null checked.
Postfix increments and decrements are null-shorting expressions (e.g. `x?.y++.isEven` only calls `isEven` if `x` was non-null), but it is still being decided whether postfix `!` should be null shorting (i.e. whether `x?.y!` should fail if `x` is null). See dart-lang/language#1163. Previously, the analyzer was inconsistent about whether it considered `!` to participate in null shorting; as a result, when analyzing an expression like `x?.y!`, the analyzer would fail to call `FlowAnalysis.nullAwareAccess_end`, resulting in corrupted flow analysis state, which could lead to a crash. This change makes the analyzer treat `!` as *not* participating in null shorting, which is consistent with what is currently written in the spec and implemented in the CFE. Fixes #43093. Change-Id: Ie69c5c29f226fe1a0282d0e7a1e079778dc700c3 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/159147 Commit-Queue: Paul Berry <[email protected]> Reviewed-by: Konstantin Shcheglov <[email protected]>
1 parent 1522a86 commit 4280e0a

File tree

2 files changed

+36
-1
lines changed

2 files changed

+36
-1
lines changed

pkg/analyzer/lib/src/dart/ast/ast.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8078,7 +8078,8 @@ class PostfixExpressionImpl extends ExpressionImpl
80788078
}
80798079

80808080
@override
8081-
bool _extendsNullShorting(Expression child) => identical(child, operand);
8081+
bool _extendsNullShorting(Expression child) =>
8082+
operator.type != TokenType.BANG && identical(child, operand);
80828083
}
80838084

80848085
/// An identifier that is prefixed or an access to an object property where the
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// This is a regression test for a bug in which `!` applied to a null-shorting
6+
// expression would corrupt the state of flow analysis, causing a crash when
7+
// trying to finish analyzing an enclosing `if` statement.
8+
9+
// SharedOptions=--enable-experiment=non-nullable
10+
import 'package:expect/expect.dart';
11+
12+
class C {
13+
final int? x;
14+
C(this.x);
15+
}
16+
17+
int? f(bool b, C? c) {
18+
if (b) {
19+
return c?.x!;
20+
} else {
21+
return null;
22+
}
23+
}
24+
25+
main() {
26+
// Note: it is currently being discussed whether `!` should participate in
27+
// null shorting (see https://github.com/dart-lang/language/issues/1163), so
28+
// let's not have an expectation about whether `f(true, null)` should throw an
29+
// exception.
30+
// f(true, null);
31+
32+
Expect.throws(() => f(true, C(null)));
33+
Expect.equals(f(true, C(1)), 1);
34+
}

0 commit comments

Comments
 (0)