Insert implicit downcast checks for the expressions in a map literal.

Tests that have begun failing due to this change are marked with a
reference to issue #31402.

Change-Id: I40b4b45d5ea32dc34aee68bfe39912141e4d7d35
Reviewed-on: https://dart-review.googlesource.com/22806
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
This commit is contained in:
Paul Berry 2017-11-22 01:18:38 +00:00 committed by commit-bot@chromium.org
parent 6d4661e527
commit ffdae2fd4d
11 changed files with 71 additions and 32 deletions

View file

@ -1209,6 +1209,11 @@ class ShadowMapLiteral extends MapLiteral implements ShadowExpression {
List<DartType> actualTypes;
assert((_declaredKeyType == null) == (_declaredValueType == null));
bool inferenceNeeded = _declaredKeyType == null && inferrer.strongMode;
bool typeChecksNeeded = !inferrer.isTopLevel;
if (inferenceNeeded || typeChecksNeeded) {
formalTypes = [];
actualTypes = [];
}
if (inferenceNeeded) {
inferredTypes = [const UnknownType(), const UnknownType()];
inferrer.typeSchemaEnvironment.inferGenericFunctionOrType(mapType,
@ -1216,23 +1221,21 @@ class ShadowMapLiteral extends MapLiteral implements ShadowExpression {
isConst: isConst);
inferredKeyType = inferredTypes[0];
inferredValueType = inferredTypes[1];
formalTypes = [];
actualTypes = [];
} else {
inferredKeyType = _declaredKeyType ?? const DynamicType();
inferredValueType = _declaredValueType ?? const DynamicType();
}
if (inferenceNeeded || !inferrer.isTopLevel) {
if (inferenceNeeded || typeChecksNeeded) {
for (var entry in entries) {
var keyType = inferrer.inferExpression(
entry.key, inferredKeyType, inferenceNeeded);
var valueType = inferrer.inferExpression(
entry.value, inferredValueType, inferenceNeeded);
entry.key, inferredKeyType, inferenceNeeded || typeChecksNeeded);
var valueType = inferrer.inferExpression(entry.value, inferredValueType,
inferenceNeeded || typeChecksNeeded);
if (inferenceNeeded) {
formalTypes.addAll(mapType.typeArguments);
actualTypes.add(keyType);
actualTypes.add(valueType);
}
actualTypes.add(keyType);
actualTypes.add(valueType);
}
}
if (inferenceNeeded) {
@ -1254,6 +1257,17 @@ class ShadowMapLiteral extends MapLiteral implements ShadowExpression {
keyType = inferredKeyType;
valueType = inferredValueType;
}
if (typeChecksNeeded) {
for (int i = 0; i < entries.length; i++) {
var entry = entries[i];
var key = entry.key;
inferrer.checkAssignability(
keyType, actualTypes[2 * i], key, key.fileOffset);
var value = entry.value;
inferrer.checkAssignability(
valueType, actualTypes[2 * i + 1], value, value.fileOffset);
}
}
var inferredType = typeNeeded
? new InterfaceType(mapClass, [inferredKeyType, inferredValueType])
: null;

View file

@ -12,7 +12,7 @@ void foo(
/*error:MAP_KEY_TYPE_NOT_ASSIGNABLE,error:MAP_KEY_TYPE_NOT_ASSIGNABLE*/ "hello":
"world"
}]) {}
void main() {
void test() {
{
Map<int, String> l0 = /*@typeArgs=int, String*/ {};
Map<int, String> l1 = /*@typeArgs=int, String*/ {3: "hello"};
@ -90,3 +90,5 @@ void main() {
};
}
}
main() {}

View file

@ -3,7 +3,7 @@ import self as self;
import "dart:core" as core;
static method foo([core::Map<core::int, core::String> m1 = const <dynamic, dynamic>{1: "hello"}, core::Map<core::int, core::String> m2 = const <dynamic, dynamic>{"hello": "world"}]) → void {}
static method main() → void {
static method test() → void {
{
core::Map<core::int, core::String> l0 = <dynamic, dynamic>{};
core::Map<core::int, core::String> l1 = <dynamic, dynamic>{3: "hello"};
@ -45,3 +45,4 @@ static method main() → void {
const core::Map<core::int, core::String> l4 = const <dynamic, dynamic>{3: "hello", "hello": 3};
}
}
static method main() → dynamic {}

View file

@ -2,14 +2,14 @@ library test;
import self as self;
import "dart:core" as core;
static method foo([core::Map<core::int, core::String> m1 = const <core::int, core::String>{1: "hello"}, core::Map<core::int, core::String> m2 = const <core::int, core::String>{"hello": "world"}]) → void {}
static method main() → void {
static method foo([core::Map<core::int, core::String> m1 = const <core::int, core::String>{1: "hello"}, core::Map<core::int, core::String> m2 = const <core::int, core::String>{"hello" as{TypeError} core::int: "world"}]) → void {}
static method test() → void {
{
core::Map<core::int, core::String> l0 = <core::int, core::String>{};
core::Map<core::int, core::String> l1 = <core::int, core::String>{3: "hello"};
core::Map<core::int, core::String> l2 = <core::int, core::String>{"hello": "hello"};
core::Map<core::int, core::String> l3 = <core::int, core::String>{3: 3};
core::Map<core::int, core::String> l4 = <core::int, core::String>{3: "hello", "hello": 3};
core::Map<core::int, core::String> l2 = <core::int, core::String>{"hello" as{TypeError} core::int: "hello"};
core::Map<core::int, core::String> l3 = <core::int, core::String>{3: 3 as{TypeError} core::String};
core::Map<core::int, core::String> l4 = <core::int, core::String>{3: "hello", "hello" as{TypeError} core::int: 3 as{TypeError} core::String};
}
{
core::Map<dynamic, dynamic> l0 = <dynamic, dynamic>{};
@ -22,15 +22,15 @@ static method main() → void {
core::Map<dynamic, core::String> l0 = <dynamic, core::String>{};
core::Map<dynamic, core::String> l1 = <dynamic, core::String>{3: "hello"};
core::Map<dynamic, core::String> l2 = <dynamic, core::String>{"hello": "hello"};
core::Map<dynamic, core::String> l3 = <dynamic, core::String>{3: 3};
core::Map<dynamic, core::String> l4 = <dynamic, core::String>{3: "hello", "hello": 3};
core::Map<dynamic, core::String> l3 = <dynamic, core::String>{3: 3 as{TypeError} core::String};
core::Map<dynamic, core::String> l4 = <dynamic, core::String>{3: "hello", "hello": 3 as{TypeError} core::String};
}
{
core::Map<core::int, dynamic> l0 = <core::int, dynamic>{};
core::Map<core::int, dynamic> l1 = <core::int, dynamic>{3: "hello"};
core::Map<core::int, dynamic> l2 = <core::int, dynamic>{"hello": "hello"};
core::Map<core::int, dynamic> l2 = <core::int, dynamic>{"hello" as{TypeError} core::int: "hello"};
core::Map<core::int, dynamic> l3 = <core::int, dynamic>{3: 3};
core::Map<core::int, dynamic> l4 = <core::int, dynamic>{3: "hello", "hello": 3};
core::Map<core::int, dynamic> l4 = <core::int, dynamic>{3: "hello", "hello" as{TypeError} core::int: 3};
}
{
core::Map<core::int, core::String> l0 = <core::num, dynamic>{} as{TypeError} core::Map<core::int, core::String>;
@ -40,8 +40,9 @@ static method main() → void {
{
const core::Map<core::int, core::String> l0 = const <core::int, core::String>{};
const core::Map<core::int, core::String> l1 = const <core::int, core::String>{3: "hello"};
const core::Map<core::int, core::String> l2 = const <core::int, core::String>{"hello": "hello"};
const core::Map<core::int, core::String> l3 = const <core::int, core::String>{3: 3};
const core::Map<core::int, core::String> l4 = const <core::int, core::String>{3: "hello", "hello": 3};
const core::Map<core::int, core::String> l2 = const <core::int, core::String>{"hello" as{TypeError} core::int: "hello"};
const core::Map<core::int, core::String> l3 = const <core::int, core::String>{3: 3 as{TypeError} core::String};
const core::Map<core::int, core::String> l4 = const <core::int, core::String>{3: "hello", "hello" as{TypeError} core::int: 3 as{TypeError} core::String};
}
}
static method main() → dynamic {}

View file

@ -21,6 +21,6 @@ static method getResource(core::String str) → self::Resource
return null;
static method main() → dynamic {
core::Map<core::String, core::List<self::Folder>> map = <core::String, core::List<self::Folder>>{"pkgA": <self::Folder>[self::getResource("/pkgA/lib/") as{TypeError} self::Folder], "pkgB": <self::Folder>[self::getResource("/pkgB/lib/") as{TypeError} self::Folder]};
core::List<core::Map<core::String, self::Folder>> list = <core::Map<core::String, self::Folder>>[<core::String, self::Folder>{"pkgA": self::getResource("/pkgA/lib/")}, <core::String, self::Folder>{"pkgB": self::getResource("/pkgB/lib/")}];
core::List<core::Map<core::String, self::Folder>> list = <core::Map<core::String, self::Folder>>[<core::String, self::Folder>{"pkgA": self::getResource("/pkgA/lib/") as{TypeError} self::Folder}, <core::String, self::Folder>{"pkgB": self::getResource("/pkgB/lib/") as{TypeError} self::Folder}];
self::Foo<core::List<self::Folder>> foo = new self::Foo::•<core::List<self::Folder>>(<self::Folder>[self::getResource("/pkgA/lib/") as{TypeError} self::Folder]);
}

View file

@ -77,7 +77,6 @@ inference/downwards_inference_on_function_expressions: TypeCheckError
inference/downwards_inference_on_function_of_t_using_the_t: Fail # Issue #29798
inference/downwards_inference_on_generic_function_expressions: TypeCheckError
inference/downwards_inference_on_list_literals_infer_downwards: RuntimeError
inference/downwards_inference_on_map_literals: TypeCheckError
inference/downwards_inference_yield_yield_star: TypeCheckError
inference/future_then_2: TypeCheckError
inference/future_then_4: TypeCheckError

View file

@ -0,0 +1,22 @@
// Copyright (c) 2017, 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.
import "package:expect/expect.dart";
class A {}
class B extends A {}
void main() {
A a1 = new B();
A a2 = new A();
<B, Object>{a1: 1}; // No error
<Object, B>{1: a1}; // No error
Expect.throwsTypeError(() {
<B, Object>{a2: 1};
});
Expect.throwsTypeError(() {
<Object, B>{1: a2};
});
}

View file

@ -1074,6 +1074,7 @@ implicit_downcast_during_compound_assignment_test: RuntimeError
implicit_downcast_during_conditional_expression_test: RuntimeError
implicit_downcast_during_if_null_assignment_test: RuntimeError
implicit_downcast_during_invocation_test: RuntimeError
implicit_downcast_during_map_literal_test: RuntimeError
implicit_downcast_during_variable_declaration_test: RuntimeError
inferrer_synthesized_constructor_test: RuntimeError
malformed2_test/00: MissingCompileTimeError
@ -2976,6 +2977,7 @@ implicit_downcast_during_combiner_test: RuntimeError
implicit_downcast_during_compound_assignment_test: RuntimeError
implicit_downcast_during_conditional_expression_test: RuntimeError
implicit_downcast_during_if_null_assignment_test: RuntimeError
implicit_downcast_during_map_literal_test: RuntimeError
implicit_downcast_during_variable_declaration_test: RuntimeError
[ $compiler == dart2js && $dart2js_with_kernel && $checked ]

View file

@ -105,6 +105,7 @@ built_in_identifier_type_annotation_test/68: MissingCompileTimeError # Issue 288
call_constructor_on_unresolvable_class_test/01: MissingCompileTimeError
call_constructor_on_unresolvable_class_test/02: MissingCompileTimeError
call_constructor_on_unresolvable_class_test/03: MissingCompileTimeError
call_function2_test: CompileTimeError # Issue 31402 (map literal)
call_function_apply_test: CompileTimeError # Issue 31402 (Invocation arguments)
call_function_test: CompileTimeError
call_non_method_field_test/01: MissingCompileTimeError
@ -834,15 +835,11 @@ malformed_test/23: MissingCompileTimeError
malformed_test/24: MissingCompileTimeError
malformed_type_test: MissingCompileTimeError
many_generic_instanceof_test: RuntimeError
map_literal1_test/01: MissingCompileTimeError
map_literal3_test/01: MissingCompileTimeError
map_literal3_test/02: MissingCompileTimeError
map_literal3_test/03: MissingCompileTimeError
map_literal3_test/04: MissingCompileTimeError
map_literal4_test/01: MissingCompileTimeError
map_literal4_test/02: MissingCompileTimeError
map_literal4_test/03: MissingCompileTimeError
map_literal4_test/04: MissingCompileTimeError
map_literal4_test/06: MissingCompileTimeError
method_override2_test/00: MissingCompileTimeError
method_override2_test/01: MissingCompileTimeError
@ -1684,6 +1681,7 @@ built_in_identifier_type_annotation_test/74: MissingCompileTimeError # Issue 288
call_constructor_on_unresolvable_class_test/01: MissingCompileTimeError
call_constructor_on_unresolvable_class_test/02: MissingCompileTimeError
call_constructor_on_unresolvable_class_test/03: MissingCompileTimeError
call_function2_test: CompileTimeError # Issue 31402 (map literal)
call_function_apply_test: CompileTimeError # Issue 31402 (Invocation arguments)
call_function_test: CompileTimeError
call_non_method_field_test/01: MissingCompileTimeError
@ -2328,6 +2326,7 @@ implicit_downcast_during_compound_assignment_test: Pass # Correctly passes.
implicit_downcast_during_conditional_expression_test: Pass # Correctly passes.
implicit_downcast_during_if_null_assignment_test: Pass # Correctly passes.
implicit_downcast_during_list_literal_test: Pass # Correctly passes.
implicit_downcast_during_map_literal_test: Pass # Correctly passes.
implicit_downcast_during_variable_declaration_test: Pass # Correctly passes.
implicit_this_test/01: MissingCompileTimeError
implicit_this_test/02: MissingCompileTimeError
@ -2500,15 +2499,11 @@ malformed_test/24: MissingCompileTimeError
malformed_type_test: MissingCompileTimeError
many_generic_instanceof_test: RuntimeError
many_overridden_no_such_method_test: SkipByDesign
map_literal1_test/01: MissingCompileTimeError
map_literal3_test/01: MissingCompileTimeError
map_literal3_test/02: MissingCompileTimeError
map_literal3_test/03: MissingCompileTimeError
map_literal3_test/04: MissingCompileTimeError
map_literal4_test/01: MissingCompileTimeError
map_literal4_test/02: MissingCompileTimeError
map_literal4_test/03: MissingCompileTimeError
map_literal4_test/04: MissingCompileTimeError
map_literal4_test/06: MissingCompileTimeError
map_literal8_test: Pass
map_literal8_test: RuntimeError
@ -3347,6 +3342,7 @@ implicit_downcast_during_compound_assignment_test: RuntimeError
implicit_downcast_during_conditional_expression_test: RuntimeError
implicit_downcast_during_if_null_assignment_test: RuntimeError
implicit_downcast_during_list_literal_test: RuntimeError
implicit_downcast_during_map_literal_test: RuntimeError
implicit_downcast_during_variable_declaration_test: RuntimeError
mixin_forwarding_constructor4_test/01: MissingCompileTimeError # KernelVM bug: Issue 15101
mixin_forwarding_constructor4_test/02: MissingCompileTimeError # KernelVM bug: Issue 15101

View file

@ -1035,6 +1035,7 @@ implicit_downcast_during_conditional_expression_test: RuntimeError
implicit_downcast_during_if_null_assignment_test: RuntimeError
implicit_downcast_during_invocation_test: RuntimeError
implicit_downcast_during_list_literal_test: RuntimeError
implicit_downcast_during_map_literal_test: RuntimeError
implicit_downcast_during_variable_declaration_test: RuntimeError
tearoff_dynamic_test: RuntimeError
type_argument_in_super_type_test: RuntimeError

View file

@ -1005,6 +1005,7 @@ implicit_downcast_during_compound_assignment_test: RuntimeError
implicit_downcast_during_conditional_expression_test: RuntimeError
implicit_downcast_during_if_null_assignment_test: RuntimeError
implicit_downcast_during_list_literal_test: RuntimeError
implicit_downcast_during_map_literal_test: RuntimeError
implicit_downcast_during_variable_declaration_test: RuntimeError
[ $runtime == vm && $checked && $mode == debug && $compiler != dartk ]