mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 01:30:32 +00:00
[cfe] Map [] operator enabled for const functions.
Change-Id: I19b0980fc100b3cd19da1875ec9fb08cdd1de70b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/195620 Reviewed-by: Jake Macdonald <jakemac@google.com> Reviewed-by: Dmitry Stefantsov <dmitryas@google.com> Commit-Queue: Kallen Tu <kallentu@google.com>
This commit is contained in:
parent
97e9186df8
commit
95229aa779
|
@ -2218,6 +2218,44 @@ class ConstantEvaluator implements ExpressionVisitor<Constant> {
|
|||
}
|
||||
} else if (receiver is NullConstant) {
|
||||
return createErrorConstant(node, messageConstEvalNullValue);
|
||||
} else if (receiver is MapConstant && enableConstFunctions) {
|
||||
if (arguments.length == 1) {
|
||||
final Constant other = arguments[0];
|
||||
switch (op) {
|
||||
case '[]':
|
||||
final ConstantMapEntry mapEntry = receiver.entries
|
||||
.firstWhere((entry) => entry.key == other, orElse: () => null);
|
||||
// Null value if key is not in the map.
|
||||
return mapEntry?.value ?? new NullConstant();
|
||||
}
|
||||
}
|
||||
} else if (receiver is InstanceConstant && enableConstFunctions) {
|
||||
if (arguments.length == 1) {
|
||||
final Constant other = arguments[0];
|
||||
if (receiver.classNode.name == '_ImmutableMap') {
|
||||
switch (op) {
|
||||
case '[]':
|
||||
final ListConstant values = receiver.fieldValues.entries
|
||||
.firstWhere(
|
||||
(entry) => entry.key.canonicalName.name == '_kvPairs',
|
||||
orElse: () => null)
|
||||
.value;
|
||||
assert(values != null);
|
||||
|
||||
// Each i index element in [values] is a key whose value is the
|
||||
// i+1 index element.
|
||||
int keyIndex = values.entries.indexOf(other);
|
||||
if (keyIndex != -1) {
|
||||
int valueIndex = keyIndex + 1;
|
||||
assert(valueIndex != values.entries.length);
|
||||
return values.entries[valueIndex];
|
||||
} else {
|
||||
// Null value if key is not in the map.
|
||||
return new NullConstant();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return createErrorConstant(
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// Tests map usage with const functions.
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
const var1 = fn({'key': 'val'}, 'key');
|
||||
|
||||
const var2 = fn({'key': 2}, 'key');
|
||||
|
||||
const var3 = fn({'key': 2}, 'invalid');
|
||||
|
||||
const map = {'key1': 2, 'key2': 3, 'key3': 4};
|
||||
const var4 = fn(map, 'key1');
|
||||
const var5 = fn(map, 'key2');
|
||||
const var6 = fn(map, 'key3');
|
||||
|
||||
Object? fn(Map<Object, Object> map, Object key) {
|
||||
return map[key];
|
||||
}
|
||||
|
||||
const var7 = fn2();
|
||||
int? fn2() {
|
||||
const y = {'key': 2};
|
||||
return y['key'];
|
||||
}
|
||||
|
||||
void main() {
|
||||
Expect.equals(var1, 'val');
|
||||
Expect.equals(var2, 2);
|
||||
Expect.equals(var3, null);
|
||||
Expect.equals(var4, 2);
|
||||
Expect.equals(var5, 3);
|
||||
Expect.equals(var6, 4);
|
||||
Expect.equals(var7, 2);
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "package:expect/expect.dart" as exp;
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
static const field core::Object? var1 = #C1;
|
||||
static const field core::Object? var2 = #C2;
|
||||
static const field core::Object? var3 = #C3;
|
||||
static const field core::Map<core::String, core::int> map = #C10;
|
||||
static const field core::Object? var4 = #C2;
|
||||
static const field core::Object? var5 = #C6;
|
||||
static const field core::Object? var6 = #C8;
|
||||
static const field core::int? var7 = #C2;
|
||||
static method fn(core::Map<core::Object, core::Object> map, core::Object key) → core::Object? {
|
||||
return map.{core::Map::[]}(key);
|
||||
}
|
||||
static method fn2() → core::int? {
|
||||
return (#C13).{core::Map::[]}("key");
|
||||
}
|
||||
static method main() → void {
|
||||
exp::Expect::equals(#C1, "val");
|
||||
exp::Expect::equals(#C2, 2);
|
||||
exp::Expect::equals(#C3, null);
|
||||
exp::Expect::equals(#C2, 2);
|
||||
exp::Expect::equals(#C6, 3);
|
||||
exp::Expect::equals(#C8, 4);
|
||||
exp::Expect::equals(#C2, 2);
|
||||
}
|
||||
|
||||
constants {
|
||||
#C1 = "val"
|
||||
#C2 = 2
|
||||
#C3 = null
|
||||
#C4 = "key1"
|
||||
#C5 = "key2"
|
||||
#C6 = 3
|
||||
#C7 = "key3"
|
||||
#C8 = 4
|
||||
#C9 = <dynamic>[#C4, #C2, #C5, #C6, #C7, #C8]
|
||||
#C10 = core::_ImmutableMap<core::String, core::int> {_kvPairs:#C9}
|
||||
#C11 = "key"
|
||||
#C12 = <dynamic>[#C11, #C2]
|
||||
#C13 = core::_ImmutableMap<core::String, core::int> {_kvPairs:#C12}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "package:expect/expect.dart" as exp;
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
static const field core::Object? var1 = #C1;
|
||||
static const field core::Object? var2 = #C2;
|
||||
static const field core::Object? var3 = #C3;
|
||||
static const field core::Map<core::String, core::int> map = #C10;
|
||||
static const field core::Object? var4 = #C2;
|
||||
static const field core::Object? var5 = #C6;
|
||||
static const field core::Object? var6 = #C8;
|
||||
static const field core::int? var7 = #C2;
|
||||
static method fn(core::Map<core::Object, core::Object> map, core::Object key) → core::Object? {
|
||||
return map.{core::Map::[]}(key);
|
||||
}
|
||||
static method fn2() → core::int? {
|
||||
return (#C13).{core::Map::[]}("key");
|
||||
}
|
||||
static method main() → void {
|
||||
exp::Expect::equals(#C1, "val");
|
||||
exp::Expect::equals(#C2, 2);
|
||||
exp::Expect::equals(#C3, null);
|
||||
exp::Expect::equals(#C2, 2);
|
||||
exp::Expect::equals(#C6, 3);
|
||||
exp::Expect::equals(#C8, 4);
|
||||
exp::Expect::equals(#C2, 2);
|
||||
}
|
||||
|
||||
constants {
|
||||
#C1 = "val"
|
||||
#C2 = 2
|
||||
#C3 = null
|
||||
#C4 = "key1"
|
||||
#C5 = "key2"
|
||||
#C6 = 3
|
||||
#C7 = "key3"
|
||||
#C8 = 4
|
||||
#C9 = <dynamic>[#C4, #C2, #C5, #C6, #C7, #C8]
|
||||
#C10 = core::_ImmutableMap<core::String, core::int> {_kvPairs:#C9}
|
||||
#C11 = "key"
|
||||
#C12 = <dynamic>[#C11, #C2]
|
||||
#C13 = core::_ImmutableMap<core::String, core::int> {_kvPairs:#C12}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import "package:expect/expect.dart";
|
||||
|
||||
const var1 = fn({'key': 'val'}, 'key');
|
||||
const var2 = fn({'key': 2}, 'key');
|
||||
const var3 = fn({'key': 2}, 'invalid');
|
||||
const map = {'key1': 2, 'key2': 3, 'key3': 4};
|
||||
const var4 = fn(map, 'key1');
|
||||
const var5 = fn(map, 'key2');
|
||||
const var6 = fn(map, 'key3');
|
||||
Object? fn(Map<Object, Object> map, Object key) {}
|
||||
const var7 = fn2();
|
||||
int? fn2() {}
|
||||
void main() {}
|
|
@ -0,0 +1,13 @@
|
|||
import "package:expect/expect.dart";
|
||||
|
||||
Object? fn(Map<Object, Object> map, Object key) {}
|
||||
const map = {'key1': 2, 'key2': 3, 'key3': 4};
|
||||
const var1 = fn({'key': 'val'}, 'key');
|
||||
const var2 = fn({'key': 2}, 'key');
|
||||
const var3 = fn({'key': 2}, 'invalid');
|
||||
const var4 = fn(map, 'key1');
|
||||
const var5 = fn(map, 'key2');
|
||||
const var6 = fn(map, 'key3');
|
||||
const var7 = fn2();
|
||||
int? fn2() {}
|
||||
void main() {}
|
|
@ -0,0 +1,46 @@
|
|||
library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "package:expect/expect.dart" as exp;
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
static const field core::Object? var1 = #C1;
|
||||
static const field core::Object? var2 = #C2;
|
||||
static const field core::Object? var3 = #C3;
|
||||
static const field core::Map<core::String, core::int> map = #C10;
|
||||
static const field core::Object? var4 = #C2;
|
||||
static const field core::Object? var5 = #C6;
|
||||
static const field core::Object? var6 = #C8;
|
||||
static const field core::int? var7 = #C2;
|
||||
static method fn(core::Map<core::Object, core::Object> map, core::Object key) → core::Object? {
|
||||
return map.{core::Map::[]}(key);
|
||||
}
|
||||
static method fn2() → core::int? {
|
||||
return (#C13).{core::Map::[]}("key");
|
||||
}
|
||||
static method main() → void {
|
||||
exp::Expect::equals(#C1, "val");
|
||||
exp::Expect::equals(#C2, 2);
|
||||
exp::Expect::equals(#C3, null);
|
||||
exp::Expect::equals(#C2, 2);
|
||||
exp::Expect::equals(#C6, 3);
|
||||
exp::Expect::equals(#C8, 4);
|
||||
exp::Expect::equals(#C2, 2);
|
||||
}
|
||||
|
||||
constants {
|
||||
#C1 = "val"
|
||||
#C2 = 2
|
||||
#C3 = null
|
||||
#C4 = "key1"
|
||||
#C5 = "key2"
|
||||
#C6 = 3
|
||||
#C7 = "key3"
|
||||
#C8 = 4
|
||||
#C9 = <dynamic>[#C4, #C2, #C5, #C6, #C7, #C8]
|
||||
#C10 = core::_ImmutableMap<core::String*, core::int*> {_kvPairs:#C9}
|
||||
#C11 = "key"
|
||||
#C12 = <dynamic>[#C11, #C2]
|
||||
#C13 = core::_ImmutableMap<core::String*, core::int*> {_kvPairs:#C12}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
static const field core::Object? var1 = self::fn(const <core::Object, core::Object>{"key": "val"}, "key");
|
||||
static const field core::Object? var2 = self::fn(const <core::Object, core::Object>{"key": 2}, "key");
|
||||
static const field core::Object? var3 = self::fn(const <core::Object, core::Object>{"key": 2}, "invalid");
|
||||
static const field core::Map<core::String, core::int> map = const <core::String, core::int>{"key1": 2, "key2": 3, "key3": 4};
|
||||
static const field core::Object? var4 = self::fn(self::map, "key1");
|
||||
static const field core::Object? var5 = self::fn(self::map, "key2");
|
||||
static const field core::Object? var6 = self::fn(self::map, "key3");
|
||||
static const field core::int? var7 = self::fn2();
|
||||
static method fn(core::Map<core::Object, core::Object> map, core::Object key) → core::Object?
|
||||
;
|
||||
static method fn2() → core::int?
|
||||
;
|
||||
static method main() → void
|
||||
;
|
||||
|
||||
|
||||
Extra constant evaluation status:
|
||||
Evaluated: MapLiteral @ org-dartlang-testcase:///const_functions_map.dart:9:17 -> InstanceConstant(const _ImmutableMap<Object*, Object*>{_ImmutableMap._kvPairs: const <dynamic>["key", "val"]})
|
||||
Evaluated: MapLiteral @ org-dartlang-testcase:///const_functions_map.dart:11:17 -> InstanceConstant(const _ImmutableMap<Object*, Object*>{_ImmutableMap._kvPairs: const <dynamic>["key", 2]})
|
||||
Evaluated: MapLiteral @ org-dartlang-testcase:///const_functions_map.dart:13:17 -> InstanceConstant(const _ImmutableMap<Object*, Object*>{_ImmutableMap._kvPairs: const <dynamic>["key", 2]})
|
||||
Evaluated: MapLiteral @ org-dartlang-testcase:///const_functions_map.dart:15:13 -> InstanceConstant(const _ImmutableMap<String*, int*>{_ImmutableMap._kvPairs: const <dynamic>["key1", 2, "key2", 3, "key3", 4]})
|
||||
Evaluated: StaticGet @ org-dartlang-testcase:///const_functions_map.dart:16:17 -> InstanceConstant(const _ImmutableMap<String*, int*>{_ImmutableMap._kvPairs: const <dynamic>["key1", 2, "key2", 3, "key3", 4]})
|
||||
Evaluated: StaticGet @ org-dartlang-testcase:///const_functions_map.dart:17:17 -> InstanceConstant(const _ImmutableMap<String*, int*>{_ImmutableMap._kvPairs: const <dynamic>["key1", 2, "key2", 3, "key3", 4]})
|
||||
Evaluated: StaticGet @ org-dartlang-testcase:///const_functions_map.dart:18:17 -> InstanceConstant(const _ImmutableMap<String*, int*>{_ImmutableMap._kvPairs: const <dynamic>["key1", 2, "key2", 3, "key3", 4]})
|
||||
Extra constant evaluation: evaluated: 14, effectively constant: 7
|
|
@ -0,0 +1,46 @@
|
|||
library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "package:expect/expect.dart" as exp;
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
static const field core::Object? var1 = #C1;
|
||||
static const field core::Object? var2 = #C2;
|
||||
static const field core::Object? var3 = #C3;
|
||||
static const field core::Map<core::String, core::int> map = #C10;
|
||||
static const field core::Object? var4 = #C2;
|
||||
static const field core::Object? var5 = #C6;
|
||||
static const field core::Object? var6 = #C8;
|
||||
static const field core::int? var7 = #C2;
|
||||
static method fn(core::Map<core::Object, core::Object> map, core::Object key) → core::Object? {
|
||||
return map.{core::Map::[]}(key);
|
||||
}
|
||||
static method fn2() → core::int? {
|
||||
return (#C13).{core::Map::[]}("key");
|
||||
}
|
||||
static method main() → void {
|
||||
exp::Expect::equals(#C1, "val");
|
||||
exp::Expect::equals(#C2, 2);
|
||||
exp::Expect::equals(#C3, null);
|
||||
exp::Expect::equals(#C2, 2);
|
||||
exp::Expect::equals(#C6, 3);
|
||||
exp::Expect::equals(#C8, 4);
|
||||
exp::Expect::equals(#C2, 2);
|
||||
}
|
||||
|
||||
constants {
|
||||
#C1 = "val"
|
||||
#C2 = 2
|
||||
#C3 = null
|
||||
#C4 = "key1"
|
||||
#C5 = "key2"
|
||||
#C6 = 3
|
||||
#C7 = "key3"
|
||||
#C8 = 4
|
||||
#C9 = <dynamic>[#C4, #C2, #C5, #C6, #C7, #C8]
|
||||
#C10 = core::_ImmutableMap<core::String*, core::int*> {_kvPairs:#C9}
|
||||
#C11 = "key"
|
||||
#C12 = <dynamic>[#C11, #C2]
|
||||
#C13 = core::_ImmutableMap<core::String*, core::int*> {_kvPairs:#C12}
|
||||
}
|
54
tests/language/const_functions/const_functions_map_test.dart
Normal file
54
tests/language/const_functions/const_functions_map_test.dart
Normal file
|
@ -0,0 +1,54 @@
|
|||
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// Tests map usage with const functions.
|
||||
|
||||
// SharedOptions=--enable-experiment=const-functions
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
const var1 = fn({'key': 'val'}, 'key');
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
|
||||
|
||||
const var2 = fn({'key': 2}, 'key');
|
||||
// ^^^^^^^^^^^^^^^^^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
|
||||
|
||||
const var3 = fn({'key': 2}, 'invalid');
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
|
||||
|
||||
const map = {'key1': 2, 'key2': 3, 'key3': 4};
|
||||
const var4 = fn(map, 'key1');
|
||||
// ^^^^^^^^^^^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
|
||||
const var5 = fn(map, 'key2');
|
||||
// ^^^^^^^^^^^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
|
||||
const var6 = fn(map, 'key3');
|
||||
// ^^^^^^^^^^^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
|
||||
|
||||
Object? fn(Map<Object, Object> map, Object key) {
|
||||
return map[key];
|
||||
}
|
||||
|
||||
const var7 = fn2();
|
||||
// ^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
|
||||
int? fn2() {
|
||||
const y = {'key': 2};
|
||||
return y['key'];
|
||||
}
|
||||
|
||||
void main() {
|
||||
Expect.equals(var1, 'val');
|
||||
Expect.equals(var2, 2);
|
||||
Expect.equals(var3, null);
|
||||
Expect.equals(var4, 2);
|
||||
Expect.equals(var5, 3);
|
||||
Expect.equals(var6, 4);
|
||||
Expect.equals(var7, 2);
|
||||
}
|
Loading…
Reference in a new issue