Skip to content

Commit daff4e7

Browse files
sigmundchwhesse
authored andcommitted
[dart2js] fix inference of ??= and []??=
Fixes #24134 Fixes #24135 [email protected], [email protected] Review URL: https://codereview.chromium.org//1305663002 .
1 parent 2d33572 commit daff4e7

File tree

5 files changed

+67
-36
lines changed

5 files changed

+67
-36
lines changed

pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart

Lines changed: 38 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -799,8 +799,6 @@ class SimpleTypeInferrerVisitor<T>
799799
elements.getGetterSelectorInComplexSendSet(node);
800800
TypeMask getterMask =
801801
elements.getGetterTypeMaskInComplexSendSet(node);
802-
Selector operatorSelector =
803-
elements.getOperatorSelectorInComplexSendSet(node);
804802
TypeMask operatorMask =
805803
elements.getOperatorTypeMaskInComplexSendSet(node);
806804
Selector setterSelector = elements.getSelector(node);
@@ -859,53 +857,53 @@ class SimpleTypeInferrerVisitor<T>
859857
node, element, setterSelector, setterMask, receiverType, rhsType,
860858
node.arguments.head);
861859
} else {
862-
// [: foo++ :] or [: foo += 1 :].
863-
ArgumentsTypes operatorArguments = new ArgumentsTypes<T>([rhsType], null);
860+
// [foo ??= bar], [: foo++ :] or [: foo += 1 :].
864861
T getterType;
865862
T newType;
866-
if (Elements.isErroneous(element)) {
867-
getterType = types.dynamicType;
868-
newType = types.dynamicType;
869-
} else if (Elements.isStaticOrTopLevelField(element)) {
863+
864+
if (Elements.isErroneous(element)) return types.dynamicType;
865+
866+
if (Elements.isStaticOrTopLevelField(element)) {
870867
Element getterElement = elements[node.selector];
871868
getterType = handleStaticSend(
872869
node, getterSelector, getterMask, getterElement, null);
873-
newType = handleDynamicSend(
874-
node, operatorSelector, operatorMask,
875-
getterType, operatorArguments);
876-
handleStaticSend(
877-
node, setterSelector, setterMask, element,
878-
new ArgumentsTypes<T>([newType], null));
879870
} else if (Elements.isUnresolved(element)
880871
|| element.isSetter
881872
|| element.isField) {
882873
getterType = handleDynamicSend(
883874
node, getterSelector, getterMask, receiverType, null);
884-
newType = handleDynamicSend(
885-
node, operatorSelector, operatorMask,
886-
getterType, operatorArguments);
887-
handleDynamicSend(node, setterSelector, setterMask, receiverType,
888-
new ArgumentsTypes<T>([newType], null));
889875
} else if (element.isLocal) {
890876
LocalElement local = element;
891877
getterType = locals.use(local);
892-
newType = handleDynamicSend(
893-
node, operatorSelector, operatorMask,
894-
getterType, operatorArguments);
895-
locals.update(element, newType, node);
896878
} else {
897879
// Bogus SendSet, for example [: myMethod += 42 :].
898880
getterType = types.dynamicType;
881+
}
882+
883+
if (op == '??=') {
884+
newType = types.allocateDiamondPhi(getterType, rhsType);
885+
} else {
886+
Selector operatorSelector =
887+
elements.getOperatorSelectorInComplexSendSet(node);
899888
newType = handleDynamicSend(
900889
node, operatorSelector, operatorMask,
901-
getterType, operatorArguments);
890+
getterType, new ArgumentsTypes<T>([rhsType], null));
902891
}
903892

904-
if (node.isPostfix) {
905-
return getterType;
906-
} else {
907-
return newType;
893+
if (Elements.isStaticOrTopLevelField(element)) {
894+
handleStaticSend(
895+
node, setterSelector, setterMask, element,
896+
new ArgumentsTypes<T>([newType], null));
897+
} else if (Elements.isUnresolved(element)
898+
|| element.isSetter
899+
|| element.isField) {
900+
handleDynamicSend(node, setterSelector, setterMask, receiverType,
901+
new ArgumentsTypes<T>([newType], null));
902+
} else if (element.isLocal) {
903+
locals.update(element, newType, node);
908904
}
905+
906+
return node.isPostfix ? getterType : newType;
909907
}
910908
}
911909

@@ -932,12 +930,18 @@ class SimpleTypeInferrerVisitor<T>
932930
getterMask,
933931
receiverType,
934932
new ArgumentsTypes<T>([indexType], null));
935-
T returnType = handleDynamicSend(
936-
node,
937-
operatorSelector,
938-
operatorMask,
939-
getterType,
940-
new ArgumentsTypes<T>([rhsType], null));
933+
934+
T returnType;
935+
if (node.isIfNullAssignment) {
936+
returnType = types.allocateDiamondPhi(getterType, rhsType);
937+
} else {
938+
returnType = handleDynamicSend(
939+
node,
940+
operatorSelector,
941+
operatorMask,
942+
getterType,
943+
new ArgumentsTypes<T>([rhsType], null));
944+
}
941945
handleDynamicSend(
942946
node,
943947
setterSelector,
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright (c) 2015, 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+
/// Regression for #24134: inference was not tracking ??= correctly.
6+
library tests.compiler.dart2js_extra.if_null2_test;
7+
8+
import "package:expect/expect.dart";
9+
10+
main() {
11+
var map;
12+
map ??= {};
13+
Expect.equals(0, map.length);
14+
Expect.isTrue(map.length == 0);
15+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright (c) 2015, 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+
/// Regression for #24135: inference was not tracking `[]??=` correctly.
6+
library tests.compiler.dart2js_extra.if_null3_test;
7+
8+
import "package:expect/expect.dart";
9+
10+
void main() {
11+
var map;
12+
(((map ??= {})['key1'] ??= {})['key2'] ??= {})['key3'] = 'value';
13+
Expect.equals('{key1: {key2: {key3: value}}}', '$map');
14+
}

tests/compiler/dart2js_extra/if_null_test.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5-
// SharedOptions=--enable-null-aware-operators
65
import "package:expect/expect.dart";
76

87
@NoInline() @AssumeDynamic()

tests/language/language_dart2js.status

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,6 @@ regress_22976_test/02: CompileTimeError # Issue 23132
120120

121121
if_null_assignment_behavior_test/13: Crash # Issue 23491
122122
if_null_assignment_behavior_test/14: Crash # Issue 23491
123-
nullaware_opt_test: Fail # Fails at e?.f ??= 200;
124123

125124
if_null_assignment_behavior_test/29: Crash # Issue 23611
126125
prefix_assignment_test/01: Crash # Issue 23611

0 commit comments

Comments
 (0)