[nnbd_migration] support untyped set & map literals
Change-Id: Iaf2c72cfe9415e89e8d9000f473aa364bbcf012a Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/115267 Reviewed-by: Paul Berry <paulberry@google.com> Commit-Queue: Mike Fairhurst <mfairhurst@google.com>
This commit is contained in:
committed by
commit-bot@chromium.org
parent
ea5f0db671
commit
a931a457f0
@@ -1023,34 +1023,50 @@ class EdgeBuilder extends GeneralizingAstVisitor<DecoratedType>
|
||||
|
||||
@override
|
||||
DecoratedType visitSetOrMapLiteral(SetOrMapLiteral node) {
|
||||
var listType = node.staticType as InterfaceType;
|
||||
var setOrMapType = node.staticType as InterfaceType;
|
||||
var typeArguments = node.typeArguments?.arguments;
|
||||
if (typeArguments == null) {
|
||||
// TODO(brianwilkerson) We might want to create fake nodes in the graph to
|
||||
// represent the type arguments so that we can still create edges from
|
||||
// the elements to them.
|
||||
// TODO(brianwilkerson)
|
||||
_unimplemented(node, 'Set or map literal with no type arguments');
|
||||
} else if (typeArguments.length == 1) {
|
||||
var elementType =
|
||||
_variables.decoratedTypeAnnotation(source, typeArguments[0]);
|
||||
|
||||
if (node.isSet) {
|
||||
DecoratedType elementType;
|
||||
if (typeArguments == null) {
|
||||
assert(setOrMapType.typeArguments.length == 1);
|
||||
elementType = DecoratedType.forImplicitType(
|
||||
_typeProvider, setOrMapType.typeArguments[0], _graph);
|
||||
} else {
|
||||
assert(typeArguments.length == 1);
|
||||
elementType =
|
||||
_variables.decoratedTypeAnnotation(source, typeArguments[0]);
|
||||
}
|
||||
for (var element in node.elements) {
|
||||
if (element is Expression) {
|
||||
_handleAssignment(element, destinationType: elementType);
|
||||
} else {
|
||||
// Handle spread and control flow elements.
|
||||
element.accept(this);
|
||||
// TODO(brianwilkerson)
|
||||
// TODO(mfairhurst)
|
||||
_unimplemented(node, 'Spread or control flow element');
|
||||
}
|
||||
}
|
||||
return DecoratedType(listType, _graph.never,
|
||||
return DecoratedType(setOrMapType, _graph.never,
|
||||
typeArguments: [elementType]);
|
||||
} else if (typeArguments.length == 2) {
|
||||
var keyType =
|
||||
_variables.decoratedTypeAnnotation(source, typeArguments[0]);
|
||||
var valueType =
|
||||
_variables.decoratedTypeAnnotation(source, typeArguments[1]);
|
||||
} else {
|
||||
assert(node.isMap);
|
||||
DecoratedType keyType;
|
||||
DecoratedType valueType;
|
||||
|
||||
if (typeArguments == null) {
|
||||
assert(setOrMapType.typeArguments.length == 2);
|
||||
keyType = DecoratedType.forImplicitType(
|
||||
_typeProvider, setOrMapType.typeArguments[0], _graph);
|
||||
valueType = DecoratedType.forImplicitType(
|
||||
_typeProvider, setOrMapType.typeArguments[1], _graph);
|
||||
} else {
|
||||
assert(typeArguments.length == 2);
|
||||
keyType = _variables.decoratedTypeAnnotation(source, typeArguments[0]);
|
||||
valueType =
|
||||
_variables.decoratedTypeAnnotation(source, typeArguments[1]);
|
||||
}
|
||||
|
||||
for (var element in node.elements) {
|
||||
if (element is MapLiteralEntry) {
|
||||
_handleAssignment(element.key, destinationType: keyType);
|
||||
@@ -1058,16 +1074,12 @@ class EdgeBuilder extends GeneralizingAstVisitor<DecoratedType>
|
||||
} else {
|
||||
// Handle spread and control flow elements.
|
||||
element.accept(this);
|
||||
// TODO(brianwilkerson)
|
||||
// TODO(mfairhurst)
|
||||
_unimplemented(node, 'Spread or control flow element');
|
||||
}
|
||||
}
|
||||
return DecoratedType(listType, _graph.never,
|
||||
return DecoratedType(setOrMapType, _graph.never,
|
||||
typeArguments: [keyType, valueType]);
|
||||
} else {
|
||||
// TODO(brianwilkerson)
|
||||
_unimplemented(
|
||||
node, 'Set or map literal with more than two type arguments');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1017,6 +1017,38 @@ class C {
|
||||
await _checkSingleFileChanges(content, expected);
|
||||
}
|
||||
|
||||
test_field_initializer_untyped_map_literal() async {
|
||||
var content = '''
|
||||
class C {
|
||||
Map<String, int> f;
|
||||
C() : f = {"foo": null};
|
||||
}
|
||||
''';
|
||||
var expected = '''
|
||||
class C {
|
||||
Map<String, int?> f;
|
||||
C() : f = {"foo": null};
|
||||
}
|
||||
''';
|
||||
await _checkSingleFileChanges(content, expected);
|
||||
}
|
||||
|
||||
test_field_initializer_untyped_set_literal() async {
|
||||
var content = '''
|
||||
class C {
|
||||
Set<int> f;
|
||||
C() : f = {null};
|
||||
}
|
||||
''';
|
||||
var expected = '''
|
||||
class C {
|
||||
Set<int?> f;
|
||||
C() : f = {null};
|
||||
}
|
||||
''';
|
||||
await _checkSingleFileChanges(content, expected);
|
||||
}
|
||||
|
||||
test_field_type_inferred() async {
|
||||
var content = '''
|
||||
int f() => null;
|
||||
|
||||
@@ -3757,60 +3757,74 @@ class C<T> {
|
||||
checkExpression('null'), assertEdge(always, tNode, hard: false));
|
||||
}
|
||||
|
||||
@failingTest
|
||||
test_setOrMapLiteral_map_noTypeArgument_noNullableKeysAndValues() async {
|
||||
// Failing because we're not yet handling collection literals without a
|
||||
// type argument.
|
||||
await analyze('''
|
||||
Map<String, int> f() {
|
||||
return {'a' : 1, 'b' : 2};
|
||||
}
|
||||
''');
|
||||
assertNoUpstreamNullability(decoratedTypeAnnotation('Map').node);
|
||||
// TODO(brianwilkerson) Add an assertion that there is an edge from the set
|
||||
// literal's fake type argument to the return type's type argument.
|
||||
var keyNode = decoratedTypeAnnotation('String').node;
|
||||
var valueNode = decoratedTypeAnnotation('int').node;
|
||||
var mapNode = decoratedTypeAnnotation('Map').node;
|
||||
|
||||
assertNoUpstreamNullability(mapNode);
|
||||
assertNoUpstreamNullability(
|
||||
assertEdge(anyNode, keyNode, hard: false).primarySource);
|
||||
assertNoUpstreamNullability(
|
||||
assertEdge(anyNode, valueNode, hard: false).primarySource);
|
||||
}
|
||||
|
||||
@failingTest
|
||||
test_setOrMapLiteral_map_noTypeArgument_nullableKey() async {
|
||||
// Failing because we're not yet handling collection literals without a
|
||||
// type argument.
|
||||
await analyze('''
|
||||
Map<String, int> f() {
|
||||
return {'a' : 1, null : 2, 'c' : 3};
|
||||
}
|
||||
''');
|
||||
assertNoUpstreamNullability(decoratedTypeAnnotation('Map').node);
|
||||
assertEdge(always, decoratedTypeAnnotation('String').node, hard: false);
|
||||
assertNoUpstreamNullability(decoratedTypeAnnotation('int').node);
|
||||
var keyNode = decoratedTypeAnnotation('String').node;
|
||||
var valueNode = decoratedTypeAnnotation('int').node;
|
||||
var mapNode = decoratedTypeAnnotation('Map').node;
|
||||
|
||||
assertNoUpstreamNullability(mapNode);
|
||||
assertEdge(always, assertEdge(anyNode, keyNode, hard: false).primarySource,
|
||||
hard: false);
|
||||
assertNoUpstreamNullability(
|
||||
assertEdge(anyNode, valueNode, hard: false).primarySource);
|
||||
}
|
||||
|
||||
@failingTest
|
||||
test_setOrMapLiteral_map_noTypeArgument_nullableKeyAndValue() async {
|
||||
// Failing because we're not yet handling collection literals without a
|
||||
// type argument.
|
||||
await analyze('''
|
||||
Map<String, int> f() {
|
||||
return {'a' : 1, null : null, 'c' : 3};
|
||||
}
|
||||
''');
|
||||
assertNoUpstreamNullability(decoratedTypeAnnotation('Map').node);
|
||||
assertEdge(always, decoratedTypeAnnotation('String').node, hard: false);
|
||||
assertEdge(always, decoratedTypeAnnotation('int').node, hard: false);
|
||||
var keyNode = decoratedTypeAnnotation('String').node;
|
||||
var valueNode = decoratedTypeAnnotation('int').node;
|
||||
var mapNode = decoratedTypeAnnotation('Map').node;
|
||||
|
||||
assertNoUpstreamNullability(mapNode);
|
||||
assertEdge(always, assertEdge(anyNode, keyNode, hard: false).primarySource,
|
||||
hard: false);
|
||||
assertEdge(
|
||||
always, assertEdge(anyNode, valueNode, hard: false).primarySource,
|
||||
hard: false);
|
||||
}
|
||||
|
||||
@failingTest
|
||||
test_setOrMapLiteral_map_noTypeArgument_nullableValue() async {
|
||||
// Failing because we're not yet handling collection literals without a
|
||||
// type argument.
|
||||
await analyze('''
|
||||
Map<String, int> f() {
|
||||
return {'a' : 1, 'b' : null, 'c' : 3};
|
||||
}
|
||||
''');
|
||||
assertNoUpstreamNullability(decoratedTypeAnnotation('Map').node);
|
||||
assertNoUpstreamNullability(decoratedTypeAnnotation('String').node);
|
||||
assertEdge(always, decoratedTypeAnnotation('int').node, hard: false);
|
||||
var keyNode = decoratedTypeAnnotation('String').node;
|
||||
var valueNode = decoratedTypeAnnotation('int').node;
|
||||
var mapNode = decoratedTypeAnnotation('Map').node;
|
||||
|
||||
assertNoUpstreamNullability(mapNode);
|
||||
assertNoUpstreamNullability(
|
||||
assertEdge(anyNode, keyNode, hard: false).primarySource);
|
||||
assertEdge(
|
||||
always, assertEdge(anyNode, valueNode, hard: false).primarySource,
|
||||
hard: false);
|
||||
}
|
||||
|
||||
test_setOrMapLiteral_map_typeArguments_noNullableKeysAndValues() async {
|
||||
@@ -3867,31 +3881,33 @@ Map<String, int> f() {
|
||||
assertEdge(always, decoratedTypeAnnotation('int>{').node, hard: false);
|
||||
}
|
||||
|
||||
@failingTest
|
||||
test_setOrMapLiteral_set_noTypeArgument_noNullableElements() async {
|
||||
// Failing because we're not yet handling collection literals without a
|
||||
// type argument.
|
||||
await analyze('''
|
||||
Set<String> f() {
|
||||
return {'a', 'b'};
|
||||
}
|
||||
''');
|
||||
assertNoUpstreamNullability(decoratedTypeAnnotation('Set').node);
|
||||
// TODO(brianwilkerson) Add an assertion that there is an edge from the set
|
||||
// literal's fake type argument to the return type's type argument.
|
||||
var valueNode = decoratedTypeAnnotation('String').node;
|
||||
var setNode = decoratedTypeAnnotation('Set').node;
|
||||
|
||||
assertNoUpstreamNullability(setNode);
|
||||
assertNoUpstreamNullability(
|
||||
assertEdge(anyNode, valueNode, hard: false).primarySource);
|
||||
}
|
||||
|
||||
@failingTest
|
||||
test_setOrMapLiteral_set_noTypeArgument_nullableElement() async {
|
||||
// Failing because we're not yet handling collection literals without a
|
||||
// type argument.
|
||||
await analyze('''
|
||||
Set<String> f() {
|
||||
return {'a', null, 'c'};
|
||||
}
|
||||
''');
|
||||
assertNoUpstreamNullability(decoratedTypeAnnotation('Set').node);
|
||||
assertEdge(always, decoratedTypeAnnotation('String').node, hard: false);
|
||||
var valueNode = decoratedTypeAnnotation('String').node;
|
||||
var setNode = decoratedTypeAnnotation('Set').node;
|
||||
|
||||
assertNoUpstreamNullability(setNode);
|
||||
assertEdge(
|
||||
always, assertEdge(anyNode, valueNode, hard: false).primarySource,
|
||||
hard: false);
|
||||
}
|
||||
|
||||
test_setOrMapLiteral_set_typeArgument_noNullableElements() async {
|
||||
|
||||
Reference in New Issue
Block a user