mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 08:07:11 +00:00
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:
parent
241f3b253e
commit
ca78eed3ea
5 changed files with 136 additions and 8 deletions
|
@ -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,
|
||||
|
|
|
@ -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>.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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};
|
||||
''');
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue