Support set and map literals with type arguments

Change-Id: I2e5ab2b81a37b0ebcfab4c60d0ed04c7c6aeba5e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/106424
Reviewed-by: Paul Berry <paulberry@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
Brian Wilkerson 2019-06-17 22:15:48 +00:00 committed by commit-bot@chromium.org
parent 97522cfdd8
commit 29b346e020
2 changed files with 201 additions and 1 deletions

View file

@ -555,7 +555,47 @@ $stackTrace''');
@override
DecoratedType visitSetOrMapLiteral(SetOrMapLiteral node) {
throw new UnimplementedError('TODO(brianwilkerson)');
var listType = 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.
throw new UnimplementedError('TODO(brianwilkerson)');
} else if (typeArguments.length == 1) {
var elementType =
_variables.decoratedTypeAnnotation(_source, typeArguments[0]);
for (var element in node.elements) {
if (element is Expression) {
_handleAssignment(elementType, element);
} else {
// Handle spread and control flow elements.
element.accept(this);
throw new UnimplementedError('TODO(brianwilkerson)');
}
}
return DecoratedType(listType, _graph.never,
typeArguments: [elementType]);
} else if (typeArguments.length == 2) {
var keyType =
_variables.decoratedTypeAnnotation(_source, typeArguments[0]);
var valueType =
_variables.decoratedTypeAnnotation(_source, typeArguments[1]);
for (var element in node.elements) {
if (element is MapLiteralEntry) {
_handleAssignment(keyType, element.key);
_handleAssignment(valueType, element.value);
} else {
// Handle spread and control flow elements.
element.accept(this);
throw new UnimplementedError('TODO(brianwilkerson)');
}
}
return DecoratedType(listType, _graph.never,
typeArguments: [keyType, valueType]);
} else {
throw new UnimplementedError('TODO(brianwilkerson)');
}
}
@override

View file

@ -1271,6 +1271,166 @@ 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.
}
@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);
}
@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);
}
@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);
}
test_setOrMapLiteral_map_typeArguments_noNullableKeysAndValues() async {
await analyze('''
Map<String, int> f() {
return <String, int>{'a' : 1, 'b' : 2};
}
''');
assertNoUpstreamNullability(decoratedTypeAnnotation('Map').node);
var keyForLiteral = decoratedTypeAnnotation('String, int>{').node;
var keyForReturnType = decoratedTypeAnnotation('String, int> ').node;
assertNoUpstreamNullability(keyForLiteral);
assertEdge(keyForLiteral, keyForReturnType, hard: false);
var valueForLiteral = decoratedTypeAnnotation('int>{').node;
var valueForReturnType = decoratedTypeAnnotation('int> ').node;
assertNoUpstreamNullability(valueForLiteral);
assertEdge(valueForLiteral, valueForReturnType, hard: false);
}
test_setOrMapLiteral_map_typeArguments_nullableKey() async {
await analyze('''
Map<String, int> f() {
return <String, int>{'a' : 1, null : 2, 'c' : 3};
}
''');
assertNoUpstreamNullability(decoratedTypeAnnotation('Map').node);
assertEdge(always, decoratedTypeAnnotation('String, int>{').node,
hard: false);
assertNoUpstreamNullability(decoratedTypeAnnotation('int>{').node);
}
test_setOrMapLiteral_map_typeArguments_nullableKeyAndValue() async {
await analyze('''
Map<String, int> f() {
return <String, int>{'a' : 1, null : null, 'c' : 3};
}
''');
assertNoUpstreamNullability(decoratedTypeAnnotation('Map').node);
assertEdge(always, decoratedTypeAnnotation('String, int>{').node,
hard: false);
assertEdge(always, decoratedTypeAnnotation('int>{').node, hard: false);
}
test_setOrMapLiteral_map_typeArguments_nullableValue() async {
await analyze('''
Map<String, int> f() {
return <String, int>{'a' : 1, 'b' : null, 'c' : 3};
}
''');
assertNoUpstreamNullability(decoratedTypeAnnotation('Map').node);
assertNoUpstreamNullability(decoratedTypeAnnotation('String, int>{').node);
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.
}
@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);
}
test_setOrMapLiteral_set_typeArgument_noNullableElements() async {
await analyze('''
Set<String> f() {
return <String>{'a', 'b'};
}
''');
assertNoUpstreamNullability(decoratedTypeAnnotation('Set').node);
var typeArgForLiteral = decoratedTypeAnnotation('String>{').node;
var typeArgForReturnType = decoratedTypeAnnotation('String> ').node;
assertNoUpstreamNullability(typeArgForLiteral);
assertEdge(typeArgForLiteral, typeArgForReturnType, hard: false);
}
test_setOrMapLiteral_set_typeArgument_nullableElement() async {
await analyze('''
Set<String> f() {
return <String>{'a', null, 'c'};
}
''');
assertNoUpstreamNullability(decoratedTypeAnnotation('Set').node);
assertEdge(always, decoratedTypeAnnotation('String>{').node, hard: false);
}
test_simpleIdentifier_local() async {
await analyze('''
main() {