Issue 36529. Report Null typed spread in not-null-aware spreads.

R=brianwilkerson@google.com

Bug: https://github.com/dart-lang/sdk/issues/36529
Change-Id: I60c092a18b668605f53f3258f3d74c333e9d1427
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/98923
Reviewed-by: Paul Berry <paulberry@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
Konstantin Shcheglov 2019-04-09 01:53:49 +00:00 committed by commit-bot@chromium.org
parent 241f3b253e
commit ca78eed3ea
5 changed files with 136 additions and 8 deletions

View file

@ -231,6 +231,7 @@ const List<ErrorCode> errorCodeValues = const [
CompileTimeErrorCode.NOT_ENOUGH_REQUIRED_ARGUMENTS,
CompileTimeErrorCode.NOT_ITERABLE_SPREAD,
CompileTimeErrorCode.NOT_MAP_SPREAD,
CompileTimeErrorCode.NOT_NULL_AWARE_NULL_SPREAD,
CompileTimeErrorCode.NO_ANNOTATION_CONSTRUCTOR_ARGUMENTS,
CompileTimeErrorCode.NO_DEFAULT_SUPER_CONSTRUCTOR_EXPLICIT,
CompileTimeErrorCode.NO_DEFAULT_SUPER_CONSTRUCTOR_IMPLICIT,

View file

@ -2184,6 +2184,10 @@ class CompileTimeErrorCode extends ErrorCode {
'NOT_MAP_SPREAD',
"Spread elements in map literals must implement 'Map'.");
static const CompileTimeErrorCode NOT_NULL_AWARE_NULL_SPREAD =
const CompileTimeErrorCode('NOT_NULL_AWARE_NULL_SPREAD',
"The Null typed expression can't be used with a non-null-aware spread.");
/**
* 7.6.1 Generative Constructors: Let <i>C</i> be the class in which the
* superinitializer appears and let <i>S</i> be the superclass of <i>C</i>.

View file

@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/error/listener.dart';
import 'package:analyzer/src/dart/element/type.dart';
@ -82,11 +83,13 @@ class LiteralElementVerifier {
CompileTimeErrorCode.MAP_ENTRY_NOT_IN_MAP, element);
}
} else if (element is SpreadElement) {
var isNullAware = element.spreadOperator.type ==
TokenType.PERIOD_PERIOD_PERIOD_QUESTION;
Expression expression = element.expression;
if (forList || forSet) {
_verifySpreadForListOrSet(expression);
_verifySpreadForListOrSet(isNullAware, expression);
} else if (forMap) {
_verifySpreadForMap(expression);
_verifySpreadForMap(isNullAware, expression);
}
}
}
@ -123,12 +126,19 @@ class LiteralElementVerifier {
/// Verify that the type of the elements of the given [expression] can be
/// assigned to the [elementType] of the enclosing collection.
void _verifySpreadForListOrSet(Expression expression) {
void _verifySpreadForListOrSet(bool isNullAware, Expression expression) {
var expressionType = expression.staticType;
if (expressionType.isDynamic) return;
// TODO(scheglov) Check for non-null-aware spread?
if (expressionType.isDartCoreNull) return;
if (expressionType.isDartCoreNull) {
if (!isNullAware) {
errorReporter.reportErrorForNode(
CompileTimeErrorCode.NOT_NULL_AWARE_NULL_SPREAD,
expression,
);
}
return;
}
InterfaceType iterableType;
var iterableObjectType = typeProvider.iterableObjectType;
@ -161,12 +171,19 @@ class LiteralElementVerifier {
/// Verify that the [expression] is a subtype of `Map<Object, Object>`, and
/// its key and values are assignable to [mapKeyType] and [mapValueType].
void _verifySpreadForMap(Expression expression) {
void _verifySpreadForMap(bool isNullAware, Expression expression) {
var expressionType = expression.staticType;
if (expressionType.isDynamic) return;
// TODO(scheglov) Check for non-null-aware spread?
if (expressionType.isDartCoreNull) return;
if (expressionType.isDartCoreNull) {
if (!isNullAware) {
errorReporter.reportErrorForNode(
CompileTimeErrorCode.NOT_NULL_AWARE_NULL_SPREAD,
expression,
);
}
return;
}
InterfaceType mapType;
var mapObjectObjectType = typeProvider.mapObjectObjectType;

View file

@ -0,0 +1,104 @@
// Copyright (c) 2019, 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:analyzer/src/dart/analysis/experiments.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../dart/resolution/driver_resolution.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(NotNullAwareNullSpreadTest);
});
}
@reflectiveTest
class NotNullAwareNullSpreadTest extends DriverResolutionTest {
@override
AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
..enabledExperiments = [
EnableString.control_flow_collections,
EnableString.spread_collections,
];
test_listLiteral_notNullAware_nullLiteral() async {
await assertErrorsInCode('''
var v = [...null];
''', [CompileTimeErrorCode.NOT_NULL_AWARE_NULL_SPREAD]);
}
test_listLiteral_notNullAware_nullTyped() async {
await assertErrorsInCode('''
Null a = null;
var v = [...a];
''', [CompileTimeErrorCode.NOT_NULL_AWARE_NULL_SPREAD]);
}
test_listLiteral_nullAware_nullLiteral() async {
await assertNoErrorsInCode('''
var v = [...?null];
''');
}
test_listLiteral_nullAware_nullTyped() async {
await assertNoErrorsInCode('''
Null a = null;
var v = [...?a];
''');
}
test_mapLiteral_notNullAware_nullLiteral() async {
await assertErrorsInCode('''
var v = <int, int>{...null};
''', [CompileTimeErrorCode.NOT_NULL_AWARE_NULL_SPREAD]);
}
test_mapLiteral_notNullAware_nullType() async {
await assertErrorsInCode('''
Null a = null;
var v = <int, int>{...a};
''', [CompileTimeErrorCode.NOT_NULL_AWARE_NULL_SPREAD]);
}
test_mapLiteral_nullAware_nullLiteral() async {
await assertNoErrorsInCode('''
var v = <int, int>{...?null};
''');
}
test_mapLiteral_nullAware_nullType() async {
await assertNoErrorsInCode('''
Null a = null;
var v = <int, int>{...?a};
''');
}
test_setLiteral_notNullAware_nullLiteral() async {
await assertErrorsInCode('''
var v = <int>{...null};
''', [CompileTimeErrorCode.NOT_NULL_AWARE_NULL_SPREAD]);
}
test_setLiteral_notNullAware_nullTyped() async {
await assertErrorsInCode('''
Null a = null;
var v = <int>{...a};
''', [CompileTimeErrorCode.NOT_NULL_AWARE_NULL_SPREAD]);
}
test_setLiteral_nullAware_nullLiteral() async {
await assertNoErrorsInCode('''
var v = <int>{...?null};
''');
}
test_setLiteral_nullAware_nullTyped() async {
await assertNoErrorsInCode('''
Null a = null;
var v = <int>{...?a};
''');
}
}

View file

@ -81,6 +81,7 @@ import 'non_constant_spread_expression_from_deferred_library_test.dart'
as non_constant_spread_expression_from_deferred_library;
import 'not_iterable_spread_test.dart' as not_iterable_spread;
import 'not_map_spread_test.dart' as not_map_spread;
import 'not_null_aware_null_spread_test.dart' as not_null_aware_null_spread;
import 'null_aware_before_operator_test.dart' as null_aware_before_operator;
import 'null_aware_in_condition_test.dart' as null_aware_in_condition;
import 'null_aware_in_logical_operator_test.dart'
@ -197,6 +198,7 @@ main() {
non_constant_spread_expression_from_deferred_library.main();
not_iterable_spread.main();
not_map_spread.main();
not_null_aware_null_spread.main();
null_aware_before_operator.main();
null_aware_in_condition.main();
null_aware_in_logical_operator.main();