[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:
Mike Fairhurst
2019-09-04 20:21:03 +00:00
committed by commit-bot@chromium.org
parent ea5f0db671
commit a931a457f0
3 changed files with 118 additions and 58 deletions
+35 -23
View File
@@ -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');
}
}
+32
View File
@@ -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;
+51 -35
View File
@@ -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 {