Skip to content

Commit

Permalink
Fix INFERENCE_FAILURE_ON_COLLECTION_LITERAL to allow for dynamically-…
Browse files Browse the repository at this point in the history
…typed elements.

Previously, strict-inference would declare that the type of this list could not be inferred:

    var a;
    var l = [e];

Now it is considered that the types of elements of a collection are "settled",
("resolved"?) and that the collection should not be punished (marked as
inference failure) just because it contains dynamic types.

Change-Id: I5b0762420235da187e08bcf6f3fea0c0d3f2195e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/111311
Commit-Queue: Samuel Rawlins <[email protected]>
Reviewed-by: Brian Wilkerson <[email protected]>
  • Loading branch information
srawlins authored and [email protected] committed Jul 31, 2019
1 parent 3b1cb90 commit 8293e96
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 31 deletions.
22 changes: 0 additions & 22 deletions pkg/analyzer/lib/src/generated/error_verifier.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1081,7 +1081,6 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
_checkTypeArgumentCount(typeArguments, 1,
StaticTypeWarningCode.EXPECTED_ONE_LIST_TYPE_ARGUMENTS);
}
_checkForInferenceFailureOnCollectionLiteral(node);
_checkForImplicitDynamicTypedLiteral(node);
_checkForListElementTypeNotAssignable(node);

Expand Down Expand Up @@ -1303,7 +1302,6 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
_checkTypeArgumentCount(typeArguments, 2,
StaticTypeWarningCode.EXPECTED_TWO_MAP_TYPE_ARGUMENTS);
}
_checkForInferenceFailureOnCollectionLiteral(node);
_checkForImplicitDynamicTypedLiteral(node);
_checkForMapTypeNotAssignable(node);
_checkForNonConstMapAsExpressionStatement3(node);
Expand All @@ -1319,7 +1317,6 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
_checkTypeArgumentCount(typeArguments, 1,
StaticTypeWarningCode.EXPECTED_ONE_SET_TYPE_ARGUMENTS);
}
_checkForInferenceFailureOnCollectionLiteral(node);
_checkForImplicitDynamicTypedLiteral(node);
_checkForSetElementTypeNotAssignable3(node);
}
Expand Down Expand Up @@ -3833,25 +3830,6 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
[directive.uri.stringValue]);
}

/// Checks a collection literal for an inference failure, and reports the
/// appropriate error if [AnalysisOptionsImpl.strictInference] is set.
///
/// This checks if [node] does not have explicit or inferred type arguments.
/// When that happens, it reports a
/// HintCode.INFERENCE_FAILURE_ON_COLLECTION_LITERAL error.
void _checkForInferenceFailureOnCollectionLiteral(TypedLiteral node) {
if (!_options.strictInference || node == null) return;
if (node.typeArguments != null) {
// Type has explicit type arguments.
return;
}
var type = node.staticType;
if (_isMissingTypeArguments(node, type, type.element, node)) {
_errorReporter.reportErrorForNode(
HintCode.INFERENCE_FAILURE_ON_COLLECTION_LITERAL, node, [type.name]);
}
}

/// Checks a type on an instance creation expression for an inference
/// failure, and reports the appropriate error if
/// [AnalysisOptionsImpl.strictInference] is set.
Expand Down
20 changes: 19 additions & 1 deletion pkg/analyzer/lib/src/generated/static_type_analyzer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,13 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<void> {
'element', listTypeParam, ParameterKind.POSITIONAL);
parameters = new List.filled(elementTypes.length, syntheticParamElement);
}
if (_strictInference && parameters.isEmpty && contextType == null) {
// We cannot infer the type of a collection literal with no elements, and
// no context type. If there are any elements, inference has not failed,
// as the types of those elements are considered resolved.
_resolver.errorReporter.reportErrorForNode(
HintCode.INFERENCE_FAILURE_ON_COLLECTION_LITERAL, node, ['List']);
}
InterfaceType inferred = ts.inferGenericFunctionOrType<InterfaceType>(
_typeProvider.listType, parameters, elementTypes, contextType,
downwards: downwards,
Expand Down Expand Up @@ -636,7 +643,7 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<void> {
void visitListLiteral(ListLiteral node) {
TypeArgumentList typeArguments = node.typeArguments;

// If we have explicit arguments, use them
// If we have explicit arguments, use them.
if (typeArguments != null) {
DartType staticType = _dynamicType;
NodeList<TypeAnnotation> arguments = typeArguments.arguments;
Expand Down Expand Up @@ -973,6 +980,17 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<void> {
assert(literalType.element == _typeProvider.setType.element);
(node as SetOrMapLiteralImpl).becomeSet();
}
if (_strictInference &&
node.elements.isEmpty &&
InferenceContext.getContext(node) == null) {
// We cannot infer the type of a collection literal with no elements, and
// no context type. If there are any elements, inference has not failed,
// as the types of those elements are considered resolved.
_resolver.errorReporter.reportErrorForNode(
HintCode.INFERENCE_FAILURE_ON_COLLECTION_LITERAL,
node,
[node.isMap ? 'Map' : 'Set']);
}
// TODO(brianwilkerson) Decide whether the literalType needs to be made
// non-nullable here or whether that will have happened in
// _inferSetOrMapLiteralType.
Expand Down
59 changes: 51 additions & 8 deletions pkg/analyzer/test/src/task/strong/checker_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4270,15 +4270,58 @@ void main() {
main() {
var emptyList = /*info:INFERENCE_FAILURE_ON_COLLECTION_LITERAL*/[];
var emptyMap = /*info:INFERENCE_FAILURE_ON_COLLECTION_LITERAL*/{};
var upwardsInfersDynamicList = /*info:INFERENCE_FAILURE_ON_COLLECTION_LITERAL*/[42 as dynamic];
var upwardsInfersDynamicSet = /*info:INFERENCE_FAILURE_ON_COLLECTION_LITERAL*/{42 as dynamic};
final finalEmptyList = /*info:INFERENCE_FAILURE_ON_COLLECTION_LITERAL*/[];
final finalEmptyMap = /*info:INFERENCE_FAILURE_ON_COLLECTION_LITERAL*/{};
const constEmptyList = /*info:INFERENCE_FAILURE_ON_COLLECTION_LITERAL*/[];
const constEmptyMap = /*info:INFERENCE_FAILURE_ON_COLLECTION_LITERAL*/{};
void listFunction(
[list = /*info:INFERENCE_FAILURE_ON_COLLECTION_LITERAL*/const []]) => print(list);
void mapFunction(
[map = /*info:INFERENCE_FAILURE_ON_COLLECTION_LITERAL*/const {}]) => print(map);
var conditionalEmptyList =
"a" == "b" ? [1, 2, 3] : /*info:INFERENCE_FAILURE_ON_COLLECTION_LITERAL*/[];
dynamic returnsList1() => /*info:INFERENCE_FAILURE_ON_COLLECTION_LITERAL*/[];
Object returnsList2() => [];
void returnsList3() => [];
var onlyInnermostEmptyCollections = {
/*info:INFERENCE_FAILURE_ON_COLLECTION_LITERAL*/[]:
/*info:INFERENCE_FAILURE_ON_COLLECTION_LITERAL*/{}
};
// Inference has enough info in all of the cases below.
var upwardsInfersDynamicList = [42 as dynamic];
var upwardsInfersDynamicList2 = [42 as dynamic, 43 as dynamic];
var upwardsInfersDynamicList3 = [42 , 43.0];
var upwardsInfersDynamicSet = {42 as dynamic};
// Upwards inference provides correct types.
dynamic d;
var upwardsInfersDynamicMap1 = /*info:INFERENCE_FAILURE_ON_COLLECTION_LITERAL*/{d: 2};
var upwardsInfersDynamicMap2 = /*info:INFERENCE_FAILURE_ON_COLLECTION_LITERAL*/{4: d};
var upwardsInfersDynamicMap3 = /*info:INFERENCE_FAILURE_ON_COLLECTION_LITERAL*/{d: d};
var upwardsInfersDynamicMap1 = {d: 2};
var upwardsInfersDynamicMap2 = {4: d};
var upwardsInfersDynamicMap3 = {d: d};
var listWithElements = [1, 2, 3];
// The type of the right side of `??` is inferred from the left.
var nullAwareEmptyList = [1, 2, 3] ?? [];
// Type arguments provide types.
var typeArgList = <dynamic>[];
var typeArgSet = <dynamic>{};
var typeArgMap = <dynamic, dynamic>{};
// Downwards inference provides correct types.
Set<dynamic> downwardsInfersDynamicSet = {};
Map<dynamic, dynamic> downwardsInfersDynamicDynamicMap = {};
List<int> downwardsInfersIntList = [];
Set<int> downwardsInfersIntSet = {};
// The type of `set` is `Set<dynamic>`.
int setLength(Set set) => set.length;
setLength({});
}
''');
await check(strictInference: true);
Expand Down

0 comments on commit 8293e96

Please sign in to comment.