Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 56fa015

Browse files
author
Dart CI
committed
Version 2.13.0-35.0.dev
Merge commit 'c2eb847697a34d7be5882385d27bdbd7a3e8a367' into 'dev'
2 parents 4c8147b + c2eb847 commit 56fa015

File tree

6 files changed

+185
-93
lines changed

6 files changed

+185
-93
lines changed
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// This test contains a test case for each kind of error that can arise from an
6+
// expression being nullable, for which we wish to report "why not promoted"
7+
// errors.
8+
9+
class C {
10+
int? i;
11+
void Function()? f;
12+
}
13+
14+
extension on int {
15+
get propertyOnNonNullInt => null;
16+
void methodOnNonNullInt() {}
17+
}
18+
19+
extension on int? {
20+
get propertyOnNullableInt => null;
21+
void methodOnNullableInt() {}
22+
}
23+
24+
property_get_of_variable(int? i, int? j) {
25+
if (i == null) return;
26+
/*cfe.update: explicitWrite*/ /*analyzer.explicitWrite*/ i = j;
27+
i. /*notPromoted(explicitWrite)*/ isEven;
28+
}
29+
30+
extension_property_get_of_variable(int? i, int? j) {
31+
if (i == null) return;
32+
/*cfe.update: explicitWrite*/ /*analyzer.explicitWrite*/ i = j;
33+
i.propertyOnNullableInt;
34+
i.
35+
/*cfe.invoke: notPromoted(explicitWrite)*/
36+
/*analyzer.notPromoted(explicitWrite)*/
37+
propertyOnNonNullInt;
38+
}
39+
40+
property_get_of_expression(C c) {
41+
if (c.i == null) return;
42+
c.i. /*notPromoted(propertyNotPromoted(member:C.i))*/ isEven;
43+
}
44+
45+
extension_property_get_of_expression(C c) {
46+
if (c.i == null) return;
47+
c.i.propertyOnNullableInt;
48+
c
49+
.i
50+
.
51+
/*cfe.invoke: notPromoted(propertyNotPromoted(member:C.i))*/
52+
/*analyzer.notPromoted(propertyNotPromoted(member:C.i))*/
53+
propertyOnNonNullInt;
54+
}
55+
56+
method_invocation(C c) {
57+
if (c.i == null) return;
58+
c.i
59+
.
60+
/*cfe.invoke: notPromoted(propertyNotPromoted(member:C.i))*/
61+
/*analyzer.notPromoted(propertyNotPromoted(member:C.i))*/
62+
abs();
63+
}
64+
65+
extension_method_invocation(C c) {
66+
if (c.i == null) return;
67+
c.i.methodOnNullableInt();
68+
c.i
69+
.
70+
/*cfe.invoke: notPromoted(propertyNotPromoted(member:C.i))*/
71+
/*analyzer.notPromoted(propertyNotPromoted(member:C.i))*/
72+
methodOnNonNullInt();
73+
}
74+
75+
call_invocation(C c) {
76+
if (c.f == null) return;
77+
c.f
78+
.
79+
/*cfe.invoke: notPromoted(propertyNotPromoted(member:C.f))*/
80+
/*analyzer.notPromoted(propertyNotPromoted(member:C.f))*/
81+
call();
82+
}

pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart

Lines changed: 1 addition & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,9 @@
55
// @dart = 2.9
66

77
import 'dart:core' hide MapEntry;
8-
import 'dart:core' as core;
98

10-
import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis.dart';
11-
import 'package:_fe_analyzer_shared/src/testing/id.dart';
129
import 'package:_fe_analyzer_shared/src/util/link.dart';
1310
import 'package:front_end/src/api_prototype/lowering_predicates.dart';
14-
import 'package:front_end/src/testing/id_extractor.dart';
1511
import 'package:kernel/ast.dart'
1612
hide Reference; // Work around https://github.com/dart-lang/sdk/issues/44667
1713
import 'package:kernel/src/legacy_erasure.dart';
@@ -4739,36 +4735,13 @@ class InferenceVisitor
47394735

47404736
readResult ??= new ExpressionInferenceResult(readType, read);
47414737
if (!inferrer.isTopLevel && readTarget.isNullable) {
4742-
Map<DartType, NonPromotionReason> whyNotPromoted =
4743-
inferrer.flowAnalysis?.whyNotPromoted(receiver);
4744-
List<LocatedMessage> context;
4745-
if (whyNotPromoted != null && whyNotPromoted.isNotEmpty) {
4746-
_WhyNotPromotedVisitor whyNotPromotedVisitor =
4747-
new _WhyNotPromotedVisitor(inferrer, receiver);
4748-
for (core.MapEntry<DartType, NonPromotionReason> entry
4749-
in whyNotPromoted.entries) {
4750-
if (entry.key.isPotentiallyNullable) continue;
4751-
LocatedMessage message = entry.value.accept(whyNotPromotedVisitor);
4752-
if (inferrer.dataForTesting != null) {
4753-
String nonPromotionReasonText = entry.value.shortName;
4754-
if (whyNotPromotedVisitor.propertyReference != null) {
4755-
Id id = computeMemberId(whyNotPromotedVisitor.propertyReference);
4756-
nonPromotionReasonText += '($id)';
4757-
}
4758-
inferrer.dataForTesting.flowAnalysisResult
4759-
.nonPromotionReasons[read] = nonPromotionReasonText;
4760-
}
4761-
context = [message];
4762-
break;
4763-
}
4764-
}
47654738
readResult = inferrer.wrapExpressionInferenceResultInProblem(
47664739
readResult,
47674740
templateNullablePropertyAccessError.withArguments(
47684741
propertyName.text, receiverType, inferrer.isNonNullableByDefault),
47694742
read.fileOffset,
47704743
propertyName.text.length,
4771-
context: context);
4744+
context: inferrer.getWhyNotPromotedContext(receiver, read));
47724745
}
47734746
return readResult;
47744747
}
@@ -6988,66 +6961,6 @@ class InferenceVisitor
69886961
}
69896962
}
69906963

6991-
class _WhyNotPromotedVisitor
6992-
implements
6993-
NonPromotionReasonVisitor<LocatedMessage, Node, Expression,
6994-
VariableDeclaration> {
6995-
final TypeInferrerImpl inferrer;
6996-
6997-
final Expression receiver;
6998-
6999-
Member propertyReference;
7000-
7001-
_WhyNotPromotedVisitor(this.inferrer, this.receiver);
7002-
7003-
@override
7004-
LocatedMessage visitDemoteViaExplicitWrite(
7005-
DemoteViaExplicitWrite<VariableDeclaration, Expression> reason) {
7006-
if (inferrer.dataForTesting != null) {
7007-
inferrer.dataForTesting.flowAnalysisResult
7008-
.nonPromotionReasonTargets[reason.writeExpression] = reason.shortName;
7009-
}
7010-
int offset = reason.writeExpression.fileOffset;
7011-
return templateVariableCouldBeNullDueToWrite
7012-
.withArguments(reason.variable.name)
7013-
.withLocation(inferrer.helper.uri, offset, noLength);
7014-
}
7015-
7016-
@override
7017-
LocatedMessage visitDemoteViaForEachVariableWrite(
7018-
DemoteViaForEachVariableWrite<VariableDeclaration, Node> reason) {
7019-
int offset = (reason.node as TreeNode).fileOffset;
7020-
return templateVariableCouldBeNullDueToWrite
7021-
.withArguments(reason.variable.name)
7022-
.withLocation(inferrer.helper.uri, offset, noLength);
7023-
}
7024-
7025-
@override
7026-
LocatedMessage visitPropertyNotPromoted(PropertyNotPromoted reason) {
7027-
Member member;
7028-
Expression receiver = this.receiver;
7029-
if (receiver is InstanceGet) {
7030-
member = receiver.interfaceTarget;
7031-
} else if (receiver is SuperPropertyGet) {
7032-
member = receiver.interfaceTarget;
7033-
} else if (receiver is StaticInvocation) {
7034-
member = receiver.target;
7035-
} else if (receiver is PropertyGet) {
7036-
member = receiver.interfaceTarget;
7037-
} else {
7038-
assert(false, 'Unrecognized receiver: ${receiver.runtimeType}');
7039-
}
7040-
if (member != null) {
7041-
propertyReference = member;
7042-
return templateFieldNotPromoted
7043-
.withArguments(reason.propertyName)
7044-
.withLocation(member.fileUri, member.fileOffset, noLength);
7045-
} else {
7046-
return null;
7047-
}
7048-
}
7049-
}
7050-
70516964
class ForInResult {
70526965
final VariableDeclaration variable;
70536966
final Expression iterable;

pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart

Lines changed: 100 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,17 @@
55
// @dart = 2.9
66

77
import 'dart:core' hide MapEntry;
8+
import 'dart:core' as core;
89

910
import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis.dart'
1011
hide Reference; // Work around https://github.com/dart-lang/sdk/issues/44667
1112

13+
import 'package:_fe_analyzer_shared/src/testing/id.dart';
1214
import 'package:_fe_analyzer_shared/src/util/link.dart';
1315

1416
import 'package:front_end/src/fasta/kernel/internal_ast.dart';
1517
import 'package:front_end/src/fasta/type_inference/type_demotion.dart';
18+
import 'package:front_end/src/testing/id_extractor.dart';
1619

1720
import 'package:kernel/ast.dart'
1821
hide Reference; // Work around https://github.com/dart-lang/sdk/issues/44667
@@ -301,6 +304,37 @@ class TypeInferrerImpl implements TypeInferrer {
301304
..fileOffset = fileOffset;
302305
}
303306

307+
/// Computes a list of context messages explaining why [receiver] was not
308+
/// promoted, to be used when reporting an error for a larger expression
309+
/// containing [receiver]. [expression] is the containing expression.
310+
List<LocatedMessage> getWhyNotPromotedContext(
311+
Expression receiver, Expression expression) {
312+
Map<DartType, NonPromotionReason> whyNotPromoted =
313+
flowAnalysis?.whyNotPromoted(receiver);
314+
List<LocatedMessage> context;
315+
if (whyNotPromoted != null && whyNotPromoted.isNotEmpty) {
316+
_WhyNotPromotedVisitor whyNotPromotedVisitor =
317+
new _WhyNotPromotedVisitor(this, receiver);
318+
for (core.MapEntry<DartType, NonPromotionReason> entry
319+
in whyNotPromoted.entries) {
320+
if (entry.key.isPotentiallyNullable) continue;
321+
LocatedMessage message = entry.value.accept(whyNotPromotedVisitor);
322+
if (dataForTesting != null) {
323+
String nonPromotionReasonText = entry.value.shortName;
324+
if (whyNotPromotedVisitor.propertyReference != null) {
325+
Id id = computeMemberId(whyNotPromotedVisitor.propertyReference);
326+
nonPromotionReasonText += '($id)';
327+
}
328+
dataForTesting.flowAnalysisResult.nonPromotionReasons[expression] =
329+
nonPromotionReasonText;
330+
}
331+
context = [message];
332+
break;
333+
}
334+
}
335+
return context;
336+
}
337+
304338
/// Returns `true` if exceptions should be thrown in paths reachable only due
305339
/// to unsoundness in flow analysis in mixed mode.
306340
bool get shouldThrowUnsoundnessException =>
@@ -2754,7 +2788,8 @@ class TypeInferrerImpl implements TypeInferrer {
27542788
templateNullableMethodCallError.withArguments(
27552789
name.text, receiverType, isNonNullableByDefault),
27562790
fileOffset,
2757-
name.text.length);
2791+
name.text.length,
2792+
context: getWhyNotPromotedContext(receiver, staticInvocation));
27582793
}
27592794
}
27602795
return createNullAwareExpressionInferenceResult(
@@ -2831,7 +2866,8 @@ class TypeInferrerImpl implements TypeInferrer {
28312866
templateNullableMethodCallError.withArguments(
28322867
callName.text, receiverType, isNonNullableByDefault),
28332868
fileOffset,
2834-
callName.text.length);
2869+
callName.text.length,
2870+
context: getWhyNotPromotedContext(receiver, expression));
28352871
}
28362872
}
28372873
// TODO(johnniwinther): Check that type arguments against the bounds.
@@ -2993,7 +3029,8 @@ class TypeInferrerImpl implements TypeInferrer {
29933029
templateNullableMethodCallError.withArguments(
29943030
methodName.text, receiverType, isNonNullableByDefault),
29953031
fileOffset,
2996-
methodName.text.length);
3032+
methodName.text.length,
3033+
context: getWhyNotPromotedContext(receiver, expression));
29973034
}
29983035
}
29993036

@@ -4836,3 +4873,63 @@ class InferredFunctionBody {
48364873

48374874
InferredFunctionBody(this.body, this.futureValueType);
48384875
}
4876+
4877+
class _WhyNotPromotedVisitor
4878+
implements
4879+
NonPromotionReasonVisitor<LocatedMessage, Node, Expression,
4880+
VariableDeclaration> {
4881+
final TypeInferrerImpl inferrer;
4882+
4883+
final Expression receiver;
4884+
4885+
Member propertyReference;
4886+
4887+
_WhyNotPromotedVisitor(this.inferrer, this.receiver);
4888+
4889+
@override
4890+
LocatedMessage visitDemoteViaExplicitWrite(
4891+
DemoteViaExplicitWrite<VariableDeclaration, Expression> reason) {
4892+
if (inferrer.dataForTesting != null) {
4893+
inferrer.dataForTesting.flowAnalysisResult
4894+
.nonPromotionReasonTargets[reason.writeExpression] = reason.shortName;
4895+
}
4896+
int offset = reason.writeExpression.fileOffset;
4897+
return templateVariableCouldBeNullDueToWrite
4898+
.withArguments(reason.variable.name)
4899+
.withLocation(inferrer.helper.uri, offset, noLength);
4900+
}
4901+
4902+
@override
4903+
LocatedMessage visitDemoteViaForEachVariableWrite(
4904+
DemoteViaForEachVariableWrite<VariableDeclaration, Node> reason) {
4905+
int offset = (reason.node as TreeNode).fileOffset;
4906+
return templateVariableCouldBeNullDueToWrite
4907+
.withArguments(reason.variable.name)
4908+
.withLocation(inferrer.helper.uri, offset, noLength);
4909+
}
4910+
4911+
@override
4912+
LocatedMessage visitPropertyNotPromoted(PropertyNotPromoted reason) {
4913+
Member member;
4914+
Expression receiver = this.receiver;
4915+
if (receiver is InstanceGet) {
4916+
member = receiver.interfaceTarget;
4917+
} else if (receiver is SuperPropertyGet) {
4918+
member = receiver.interfaceTarget;
4919+
} else if (receiver is StaticInvocation) {
4920+
member = receiver.target;
4921+
} else if (receiver is PropertyGet) {
4922+
member = receiver.interfaceTarget;
4923+
} else {
4924+
assert(false, 'Unrecognized receiver: ${receiver.runtimeType}');
4925+
}
4926+
if (member != null) {
4927+
propertyReference = member;
4928+
return templateFieldNotPromoted
4929+
.withArguments(reason.propertyName)
4930+
.withLocation(member.fileUri, member.fileOffset, noLength);
4931+
} else {
4932+
return null;
4933+
}
4934+
}
4935+
}

pkg/front_end/test/lint_test.status

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ front_end/lib/src/fasta/incremental_compiler/ImportsTwice: Fail
2020
front_end/lib/src/fasta/kernel/body_builder/ImportsTwice: Fail
2121
front_end/lib/src/fasta/kernel/constant_evaluator/ExplicitType: Pass
2222
front_end/lib/src/fasta/kernel/expression_generator_helper/ImportsTwice: Fail
23-
front_end/lib/src/fasta/kernel/inference_visitor/ImportsTwice: Fail
2423
front_end/lib/src/fasta/kernel/kernel_api/Exports: Fail
2524
front_end/lib/src/fasta/kernel/kernel_ast_api/Exports: Fail
2625
front_end/lib/src/fasta/kernel/kernel_builder/Exports: Fail

pkg/front_end/test/spell_checking_list_code.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,7 @@ existentially
390390
exp
391391
expando
392392
expense
393+
explaining
393394
exportable
394395
exportee
395396
exportees

tools/VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,5 @@ CHANNEL dev
2727
MAJOR 2
2828
MINOR 13
2929
PATCH 0
30-
PRERELEASE 34
30+
PRERELEASE 35
3131
PRERELEASE_PATCH 0

0 commit comments

Comments
 (0)