Version 2.13.0-62.0.dev
Merge commit '1d191a137494dd399567696bb466fe8b4c11c248' into 'dev'
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_expression_call_error.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_expression_call_error.dart
new file mode 100644
index 0000000..c603def
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_expression_call_error.dart
@@ -0,0 +1,119 @@
+// Copyright (c) 2020, 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.
+
+// This test contains a test case for each condition that can lead to the front
+// end's `NullableExpressionCallError`, for which we wish to report "why not
+// promoted" context information.
+
+class C1 {
+ C2? bad;
+}
+
+class C2 {
+ void call() {}
+}
+
+instance_method_invocation(C1 c) {
+ if (c.bad == null) return;
+ c.bad
+ /*cfe.invoke: notPromoted(propertyNotPromoted(member:C1.bad))*/
+ ();
+}
+
+class C3 {
+ C4? ok;
+ C5? bad;
+}
+
+class C4 {}
+
+class C5 {}
+
+extension on C4? {
+ void call() {}
+}
+
+extension on C5 {
+ void call() {}
+}
+
+extension_invocation_method(C3 c) {
+ if (c.ok == null) return;
+ c.ok();
+ if (c.bad == null) return;
+ c.bad
+ /*cfe.invoke: notPromoted(propertyNotPromoted(member:C3.bad))*/
+ ();
+}
+
+class C6 {
+ C7? bad;
+}
+
+class C7 {
+ void Function() get call => () {};
+}
+
+instance_getter_invocation(C6 c) {
+ if (c.bad == null) return;
+ c.bad
+ /*cfe.invoke: notPromoted(propertyNotPromoted(member:C6.bad))*/
+ ();
+}
+
+class C8 {
+ C9? ok;
+ C10? bad;
+}
+
+class C9 {}
+
+class C10 {}
+
+extension on C9? {
+ void Function() get call => () {};
+}
+
+extension on C10 {
+ void Function() get call => () {};
+}
+
+extension_invocation_getter(C8 c) {
+ if (c.ok == null) return;
+ c.ok();
+ if (c.bad == null) return;
+ c.bad
+ /*cfe.invoke: notPromoted(propertyNotPromoted(member:C8.bad))*/
+ ();
+}
+
+class C11 {
+ void Function()? bad;
+}
+
+function_invocation(C11 c) {
+ if (c.bad == null) return;
+ c.bad
+ /*cfe.invoke: notPromoted(propertyNotPromoted(member:C11.bad))*/
+ ();
+}
+
+class C12 {
+ C13? bad;
+}
+
+class C13 {
+ void Function() foo;
+ C13(this.foo);
+}
+
+instance_field_invocation(C12 c) {
+ if (c.bad == null) return;
+ c.bad
+ .
+ /*analyzer.notPromoted(propertyNotPromoted(member:C12.bad))*/
+ foo
+ /*cfe.invoke: notPromoted(propertyNotPromoted(member:C12.bad))*/
+ ();
+}
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_error_scenarios.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_method_call_error.dart
similarity index 91%
rename from pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_error_scenarios.dart
rename to pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_method_call_error.dart
index 5797fa4..40cc053 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_error_scenarios.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_method_call_error.dart
@@ -2,9 +2,9 @@
// 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.
-// This test contains a test case for each kind of error that can arise from an
-// expression being nullable, for which we wish to report "why not promoted"
-// errors.
+// This test contains a test case for each condition that can lead to the front
+// end's `NullableMethodCallError`, for which we wish to report "why not
+// promoted" context information.
class C {
int? i;
diff --git a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
index 13d0970..2f2df5f 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -4736,7 +4736,8 @@
propertyName.text, receiverType, inferrer.isNonNullableByDefault),
read.fileOffset,
propertyName.text.length,
- context: inferrer.getWhyNotPromotedContext(receiver, read));
+ context: inferrer.getWhyNotPromotedContext(
+ receiver, inferrer.flowAnalysis?.whyNotPromoted(receiver), read));
}
return readResult;
}
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index 3acf8bb..0c457c2 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -305,10 +305,8 @@
/// Computes a list of context messages explaining why [receiver] was not
/// promoted, to be used when reporting an error for a larger expression
/// containing [receiver]. [expression] is the containing expression.
- List<LocatedMessage> getWhyNotPromotedContext(
- Expression receiver, Expression expression) {
- Map<DartType, NonPromotionReason> whyNotPromoted =
- flowAnalysis?.whyNotPromoted(receiver);
+ List<LocatedMessage> getWhyNotPromotedContext(Expression receiver,
+ Map<DartType, NonPromotionReason> whyNotPromoted, Expression expression) {
List<LocatedMessage> context;
if (whyNotPromoted != null && whyNotPromoted.isNotEmpty) {
_WhyNotPromotedVisitor whyNotPromotedVisitor =
@@ -2755,12 +2753,22 @@
implicitInvocationPropertyName: name);
if (!isTopLevel && target.isNullable) {
+ // Handles cases like:
+ // C? c;
+ // c();
+ // where there is an extension on C defined as:
+ // extension on C {
+ // void Function() get call => () {};
+ // }
+ List<LocatedMessage> context = getWhyNotPromotedContext(
+ receiver, flowAnalysis?.whyNotPromoted(receiver), staticInvocation);
result = wrapExpressionInferenceResultInProblem(
result,
templateNullableExpressionCallError.withArguments(
receiverType, isNonNullableByDefault),
fileOffset,
- noLength);
+ noLength,
+ context: context);
}
return result;
@@ -2780,13 +2788,23 @@
Expression replacement = result.applyResult(staticInvocation);
if (!isTopLevel && target.isNullable) {
+ List<LocatedMessage> context = getWhyNotPromotedContext(
+ receiver, flowAnalysis?.whyNotPromoted(receiver), staticInvocation);
if (isImplicitCall) {
+ // Handles cases like:
+ // int? i;
+ // i();
+ // where there is an extension:
+ // extension on int {
+ // void call() {}
+ // }
replacement = helper.wrapInProblem(
replacement,
templateNullableExpressionCallError.withArguments(
receiverType, isNonNullableByDefault),
fileOffset,
- noLength);
+ noLength,
+ context: context);
} else {
// Handles cases like:
// int? i;
@@ -2801,7 +2819,7 @@
name.text, receiverType, isNonNullableByDefault),
fileOffset,
name.text.length,
- context: getWhyNotPromotedContext(receiver, staticInvocation));
+ context: context);
}
}
return createNullAwareExpressionInferenceResult(
@@ -2865,13 +2883,19 @@
}
Expression replacement = result.applyResult(expression);
if (!isTopLevel && target.isNullableCallFunction) {
+ List<LocatedMessage> context = getWhyNotPromotedContext(
+ receiver, flowAnalysis?.whyNotPromoted(receiver), expression);
if (isImplicitCall) {
+ // Handles cases like:
+ // void Function()? f;
+ // f();
replacement = helper.wrapInProblem(
replacement,
templateNullableExpressionCallError.withArguments(
receiverType, isNonNullableByDefault),
fileOffset,
- noLength);
+ noLength,
+ context: context);
} else {
// Handles cases like:
// void Function()? f;
@@ -2882,7 +2906,7 @@
callName.text, receiverType, isNonNullableByDefault),
fileOffset,
callName.text.length,
- context: getWhyNotPromotedContext(receiver, expression));
+ context: context);
}
}
// TODO(johnniwinther): Check that type arguments against the bounds.
@@ -3031,13 +3055,23 @@
replacement = result.applyResult(replacement);
if (!isTopLevel && target.isNullable) {
+ List<LocatedMessage> context = getWhyNotPromotedContext(
+ receiver, flowAnalysis?.whyNotPromoted(receiver), expression);
if (isImplicitCall) {
+ // Handles cases like:
+ // C? c;
+ // c();
+ // Where C is defined as:
+ // class C {
+ // void call();
+ // }
replacement = helper.wrapInProblem(
replacement,
templateNullableExpressionCallError.withArguments(
receiverType, isNonNullableByDefault),
fileOffset,
- noLength);
+ noLength,
+ context: context);
} else {
// Handles cases like:
// int? i;
@@ -3048,7 +3082,7 @@
methodName.text, receiverType, isNonNullableByDefault),
fileOffset,
methodName.text.length,
- context: getWhyNotPromotedContext(receiver, expression));
+ context: context);
}
}
@@ -3172,12 +3206,22 @@
}
if (!isTopLevel && target.isNullable) {
+ // Handles cases like:
+ // C? c;
+ // c.foo();
+ // Where C is defined as:
+ // class C {
+ // void Function() get foo => () {};
+ // }
+ List<LocatedMessage> context = getWhyNotPromotedContext(receiver,
+ flowAnalysis?.whyNotPromoted(receiver), invocationResult.expression);
invocationResult = wrapExpressionInferenceResultInProblem(
invocationResult,
templateNullableExpressionCallError.withArguments(
receiverType, isNonNullableByDefault),
fileOffset,
- noLength);
+ noLength,
+ context: context);
}
if (!library.loader.target.backendTarget.supportsExplicitGetterCalls) {
@@ -3274,6 +3318,14 @@
receiver = _hoist(receiver, receiverType, hoistedExpressions);
}
+ Map<DartType, NonPromotionReason> whyNotPromotedInfo;
+ if (!isTopLevel && target.isNullable) {
+ // We won't report the error until later (after we have an
+ // invocationResult), but we need to gather "why not promoted" info now,
+ // before we tell flow analysis about the property get.
+ whyNotPromotedInfo = flowAnalysis?.whyNotPromoted(receiver);
+ }
+
Name originalName = field.name;
Expression originalReceiver = receiver;
Member originalTarget = field;
@@ -3297,6 +3349,8 @@
kind, originalReceiver, originalName,
resultType: calleeType, interfaceTarget: originalTarget)
..fileOffset = fileOffset;
+ flowAnalysis.propertyGet(
+ originalPropertyGet, originalReceiver, originalName.name);
} else {
originalPropertyGet =
new PropertyGet(originalReceiver, originalName, originalTarget)
@@ -3343,12 +3397,25 @@
}
if (!isTopLevel && target.isNullable) {
+ // Handles cases like:
+ // C? c;
+ // c.foo();
+ // Where C is defined as:
+ // class C {
+ // void Function() foo;
+ // C(this.foo);
+ // }
+ // TODO(paulberry): would it be better to report NullableMethodCallError
+ // in this scenario?
+ List<LocatedMessage> context = getWhyNotPromotedContext(
+ receiver, whyNotPromotedInfo, invocationResult.expression);
invocationResult = wrapExpressionInferenceResultInProblem(
invocationResult,
templateNullableExpressionCallError.withArguments(
receiverType, isNonNullableByDefault),
fileOffset,
- noLength);
+ noLength,
+ context: context);
}
if (!library.loader.target.backendTarget.supportsExplicitGetterCalls) {
diff --git a/tools/VERSION b/tools/VERSION
index 739aa1d..d028b8a 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 13
PATCH 0
-PRERELEASE 61
+PRERELEASE 62
PRERELEASE_PATCH 0
\ No newline at end of file