Skip to content

Commit 6e85f33

Browse files
johnniwinthercommit-bot@chromium.org
authored andcommitted
[cfe] Support null-aware cascade
Change-Id: I1db4125b4469e6a8b6adc5ec6e4dcafc0a26da4a Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/124680 Reviewed-by: Aske Simon Christensen <[email protected]> Commit-Queue: Johnni Winther <[email protected]>
1 parent 3855eea commit 6e85f33

8 files changed

Lines changed: 110 additions & 4 deletions

pkg/front_end/lib/src/fasta/kernel/body_builder.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1481,7 +1481,8 @@ class BodyBuilder extends ScopeListener<JumpTarget>
14811481
} else {
14821482
VariableDeclaration variable =
14831483
forest.createVariableDeclarationForValue(expression);
1484-
push(new Cascade(variable)..fileOffset = expression.fileOffset);
1484+
push(new Cascade(variable, isNullAware: optional('?..', token))
1485+
..fileOffset = expression.fileOffset);
14851486
push(_createReadOnlyVariableAccess(
14861487
variable, token, expression.fileOffset, null));
14871488
}

pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -255,8 +255,19 @@ class InferenceVisitor
255255
createVariable(expressionResults[index].expression, const VoidType()),
256256
replacement);
257257
}
258-
replacement = new Let(node.variable, replacement)
259-
..fileOffset = node.fileOffset;
258+
259+
if (node.isNullAware) {
260+
Member equalsMember = inferrer
261+
.findInterfaceMember(result.inferredType, equalsName, node.fileOffset)
262+
.member;
263+
NullAwareGuard nullAwareGuard = new NullAwareGuard(
264+
node.variable, node.variable.fileOffset, equalsMember);
265+
replacement =
266+
nullAwareGuard.createExpression(result.inferredType, replacement);
267+
} else {
268+
replacement = new Let(node.variable, replacement)
269+
..fileOffset = node.fileOffset;
270+
}
260271
return new ExpressionInferenceResult(result.inferredType, replacement);
261272
}
262273

pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -380,14 +380,16 @@ class Cascade extends InternalExpression {
380380
/// initializer;
381381
VariableDeclaration variable;
382382

383+
final bool isNullAware;
384+
383385
/// The expressions performed on [variable].
384386
final List<Expression> expressions = <Expression>[];
385387

386388
/// Creates a [Cascade] using [variable] as the cascade
387389
/// variable. Caller is responsible for ensuring that [variable]'s
388390
/// initializer is the expression preceding the first `..` of the cascade
389391
/// expression.
390-
Cascade(this.variable) {
392+
Cascade(this.variable, {this.isNullAware}) : assert(isNullAware != null) {
391393
variable?.parent = this;
392394
}
393395

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright (c) 2019, 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+
class Class {
6+
Class method() => this;
7+
}
8+
9+
extension Extension on Class {
10+
Class extensionMethod() => this;
11+
}
12+
13+
main() {
14+
Class? c;
15+
c?..method();
16+
c?..method()..method();
17+
c?..extensionMethod();
18+
c?..extensionMethod()..extensionMethod();
19+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
library;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
class Class extends core::Object {
6+
synthetic constructor •() → self::Class*
7+
;
8+
method method() → self::Class
9+
;
10+
}
11+
extension Extension on self::Class {
12+
method extensionMethod = self::Extension|extensionMethod;
13+
tearoff extensionMethod = self::Extension|get#extensionMethod;
14+
}
15+
static method Extension|extensionMethod(final self::Class #this) → self::Class
16+
;
17+
static method Extension|get#extensionMethod(final self::Class #this) → () →* self::Class
18+
return () → self::Class => self::Extension|extensionMethod(#this);
19+
static method main() → dynamic
20+
;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
library;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
class Class extends core::Object {
6+
synthetic constructor •() → self::Class*
7+
: super core::Object::•()
8+
;
9+
method method() → self::Class
10+
return this;
11+
}
12+
extension Extension on self::Class {
13+
method extensionMethod = self::Extension|extensionMethod;
14+
tearoff extensionMethod = self::Extension|get#extensionMethod;
15+
}
16+
static method Extension|extensionMethod(final self::Class #this) → self::Class
17+
return #this;
18+
static method Extension|get#extensionMethod(final self::Class #this) → () →* self::Class
19+
return () → self::Class => self::Extension|extensionMethod(#this);
20+
static method main() → dynamic {
21+
self::Class? c;
22+
let final self::Class? #t1 = c in #t1.{core::Object::==}(null) ?{self::Class?} null : let final void #t2 = #t1.{self::Class::method}() in #t1;
23+
let final self::Class? #t3 = c in #t3.{core::Object::==}(null) ?{self::Class?} null : let final void #t4 = #t3.{self::Class::method}() in let final void #t5 = #t3.{self::Class::method}() in #t3;
24+
let final self::Class? #t6 = c in #t6.{core::Object::==}(null) ?{self::Class?} null : let final void #t7 = self::Extension|extensionMethod(#t6) in #t6;
25+
let final self::Class? #t8 = c in #t8.{core::Object::==}(null) ?{self::Class?} null : let final void #t9 = self::Extension|extensionMethod(#t8) in let final void #t10 = self::Extension|extensionMethod(#t8) in #t8;
26+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
library;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
class Class extends core::Object {
6+
synthetic constructor •() → self::Class*
7+
: super core::Object::•()
8+
;
9+
method method() → self::Class
10+
return this;
11+
}
12+
extension Extension on self::Class {
13+
method extensionMethod = self::Extension|extensionMethod;
14+
tearoff extensionMethod = self::Extension|get#extensionMethod;
15+
}
16+
static method Extension|extensionMethod(final self::Class #this) → self::Class
17+
return #this;
18+
static method Extension|get#extensionMethod(final self::Class #this) → () →* self::Class
19+
return () → self::Class => self::Extension|extensionMethod(#this);
20+
static method main() → dynamic {
21+
self::Class? c;
22+
let final self::Class? #t1 = c in #t1.{core::Object::==}(null) ?{self::Class?} null : let final void #t2 = #t1.{self::Class::method}() in #t1;
23+
let final self::Class? #t3 = c in #t3.{core::Object::==}(null) ?{self::Class?} null : let final void #t4 = #t3.{self::Class::method}() in let final void #t5 = #t3.{self::Class::method}() in #t3;
24+
let final self::Class? #t6 = c in #t6.{core::Object::==}(null) ?{self::Class?} null : let final void #t7 = self::Extension|extensionMethod(#t6) in #t6;
25+
let final self::Class? #t8 = c in #t8.{core::Object::==}(null) ?{self::Class?} null : let final void #t9 = self::Extension|extensionMethod(#t8) in let final void #t10 = self::Extension|extensionMethod(#t8) in #t8;
26+
}

pkg/front_end/testcases/text_serialization.status

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -898,6 +898,7 @@ nnbd/issue_39286_2: TextSerializationFailure
898898
nnbd/late: TextSerializationFailure
899899
nnbd/null_check: TextSerializationFailure
900900
nnbd/null_shorting: TextSerializationFailure
901+
nnbd/null_shorting_cascade: TextSerializationFailure
901902
nnbd/null_shorting_explicit_extension: TextSerializationFailure
902903
nnbd/null_shorting_extension: TextSerializationFailure
903904
nnbd/nullable_null: TextSerializationFailure

0 commit comments

Comments
 (0)