From bc6cdf54fd1f1473075d990dcc370601438fbadd Mon Sep 17 00:00:00 2001 From: Paul Berry Date: Tue, 6 Apr 2021 06:55:28 +0000 Subject: [PATCH] Flow analysis: track property get targets. These targets are needed for "why not promoted" error messages, and it's easier to have flow analysis keep track of them than to have the analyzer and CFE try to reconstruct them at the time of reporting the error. Bug: https://github.com/dart-lang/sdk/issues/44898 Change-Id: Ia8ef4a7ce13cc30860e59b7369e6230d233e252d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/193832 Commit-Queue: Paul Berry Reviewed-by: Johnni Winther Reviewed-by: Konstantin Shcheglov --- .../lib/src/flow_analysis/flow_analysis.dart | 72 +++++++++++++------ pkg/_fe_analyzer_shared/test/mini_ast.dart | 4 +- .../assignment_expression_resolver.dart | 3 +- .../resolver/method_invocation_resolver.dart | 6 +- .../resolver/property_element_resolver.dart | 11 ++- .../dart/resolver/type_property_resolver.dart | 4 +- .../src/error/bool_expression_verifier.dart | 2 +- .../error/nullable_dereference_verifier.dart | 4 +- .../generated/error_detection_helpers.dart | 8 +-- .../lib/src/generated/error_verifier.dart | 1 - pkg/analyzer/lib/src/generated/resolver.dart | 26 +------ .../src/fasta/kernel/inference_visitor.dart | 46 ++++++------ .../fasta/type_inference/type_inferrer.dart | 55 ++++++-------- 13 files changed, 121 insertions(+), 121 deletions(-) diff --git a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart index e4c7261dc57..bf501a059c2 100644 --- a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart +++ b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart @@ -736,8 +736,13 @@ abstract class FlowAnalysis _wrapped.propertyGet( - wholeExpression, target, propertyName, staticType)); + wholeExpression, target, propertyName, propertyMember, staticType)); } @override @@ -1378,12 +1389,13 @@ class FlowAnalysisDebug _wrapped.thisOrSuperPropertyGet( - expression, propertyName, staticType)); + expression, propertyName, propertyMember, staticType)); } @override @@ -2334,12 +2346,17 @@ class PropertyNotPromoted extends NonPromotionReason { /// The name of the property. final String propertyName; + /// The field or property being accessed. This matches a `propertyMember` + /// value that was passed to either [FlowAnalysis.propertyGet] or + /// [FlowAnalysis.thisOrSuperPropertyGet]. + final Object? propertyMember; + /// The static type of the property at the time of the access. This is the /// type that was passed to [FlowAnalysis.whyNotPromoted]; it is provided to /// the client as a convenience for ID testing. final Type staticType; - PropertyNotPromoted(this.propertyName, this.staticType); + PropertyNotPromoted(this.propertyName, this.propertyMember, this.staticType); @override String get documentationLink => 'http://dart.dev/go/non-promo-property'; @@ -2517,8 +2534,10 @@ abstract class Reference { /// Creates a reference representing a get of a property called [propertyName] /// on the reference represented by `this`. - Reference propertyGet(String propertyName) => - new _PropertyGetReference(this, propertyName); + Reference propertyGet( + String propertyName, Object? propertyMember) => + new _PropertyGetReference( + this, propertyName, propertyMember); /// Stores info for this reference in [variableInfo]. void storeInfo(Map> variableInfo, @@ -3952,14 +3971,14 @@ class _FlowAnalysisImpl? reference = _getExpressionReference(target)?.reference; if (reference != null) { _storeExpressionReference( wholeExpression, new ReferenceWithType( - reference.propertyGet(propertyName), staticType)); + reference.propertyGet(propertyName, propertyMember), staticType)); } } @@ -4016,12 +4035,13 @@ class _FlowAnalysisImpl( - new _ThisReference().propertyGet(propertyName), + new _ThisReference() + .propertyGet(propertyName, propertyMember), staticType)); } @@ -4686,7 +4706,7 @@ class _LegacyTypePromotion? ssaNodeForTesting(Variable variable) { @@ -4706,8 +4726,8 @@ class _LegacyTypePromotion /// The name of the property. final String propertyName; - _PropertyGetReference(this.target, this.propertyName); + /// The field or property being accessed. This matches a `propertyMember` + /// value that was passed to either [FlowAnalysis.propertyGet] or + /// [FlowAnalysis.thisOrSuperPropertyGet]. + final Object? propertyMember; + + _PropertyGetReference(this.target, this.propertyName, this.propertyMember); @override Map Function() getNonPromotionReasons( @@ -4920,7 +4945,8 @@ class _PropertyGetReference return () { Map result = {}; for (Type type in promotedTypes) { - result[type] = new PropertyNotPromoted(propertyName, staticType); + result[type] = + new PropertyNotPromoted(propertyName, propertyMember, staticType); } return result; }; diff --git a/pkg/_fe_analyzer_shared/test/mini_ast.dart b/pkg/_fe_analyzer_shared/test/mini_ast.dart index 5e41049c48b..fd0db4bbbf3 100644 --- a/pkg/_fe_analyzer_shared/test/mini_ast.dart +++ b/pkg/_fe_analyzer_shared/test/mini_ast.dart @@ -1510,7 +1510,7 @@ class _Property extends LValue { Harness h, FlowAnalysis flow) { var targetType = target._visit(h, flow); var propertyType = h.getMember(targetType, propertyName); - flow.propertyGet(this, target, propertyName, propertyType); + flow.propertyGet(this, target, propertyName, propertyName, propertyType); return propertyType; } @@ -1614,7 +1614,7 @@ class _ThisOrSuperPropertyGet extends Expression { @override Type _visit( Harness h, FlowAnalysis flow) { - flow.thisOrSuperPropertyGet(this, propertyName, type); + flow.thisOrSuperPropertyGet(this, propertyName, propertyName, type); return type; } } diff --git a/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart index aaaa1821017..3b63d6ce608 100644 --- a/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart +++ b/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart @@ -121,8 +121,7 @@ class AssignmentExpressionResolver { CompileTimeErrorCode.INVALID_ASSIGNMENT, right, [rightType, writeType], - _resolver.computeWhyNotPromotedMessages( - right, right, whyNotPromoted?.call()), + _resolver.computeWhyNotPromotedMessages(right, whyNotPromoted?.call()), ); } diff --git a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart index caff68307d9..a6ab6e7bf85 100644 --- a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart +++ b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart @@ -807,7 +807,11 @@ class MethodInvocationResolver { ); } _resolver.flowAnalysis?.flow?.propertyGet( - functionExpression, target, node.methodName.name, getterReturnType); + functionExpression, + target, + node.methodName.name, + node.methodName.staticElement, + getterReturnType); functionExpression.staticType = targetType; } diff --git a/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart index 8a6475857f0..e2d53364994 100644 --- a/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart +++ b/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart @@ -203,8 +203,8 @@ class PropertyElementResolver { readElementRequested = readLookup.requested; if (readElementRequested is PropertyAccessorElement && !readElementRequested.isStatic) { - _resolver.flowAnalysis?.flow?.thisOrSuperPropertyGet( - node, node.name, readElementRequested.returnType); + _resolver.flowAnalysis?.flow?.thisOrSuperPropertyGet(node, node.name, + readElementRequested, readElementRequested.returnType); } _resolver.checkReadOfNotAssignedLocalVariable(node, readElementRequested); } @@ -373,7 +373,11 @@ class PropertyElementResolver { nameErrorEntity: propertyName, ); - _resolver.flowAnalysis?.flow?.propertyGet(node, target, propertyName.name, + _resolver.flowAnalysis?.flow?.propertyGet( + node, + target, + propertyName.name, + result.getter, result.getter?.returnType ?? _typeSystem.typeProvider.dynamicType); if (hasRead && result.needsGetterError) { @@ -653,6 +657,7 @@ class PropertyElementResolver { node, target, propertyName.name, + readElement, readElement?.returnType ?? _typeSystem.typeProvider.dynamicType); } diff --git a/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart index cff8b7e4257..4ffbaaa8b07 100644 --- a/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart +++ b/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart @@ -130,11 +130,11 @@ class TypePropertyResolver { if (flow != null) { if (receiver != null) { messages = _resolver.computeWhyNotPromotedMessages( - receiver, nameErrorEntity, flow.whyNotPromoted(receiver)()); + nameErrorEntity, flow.whyNotPromoted(receiver)()); } else { var thisType = _resolver.thisType; if (thisType != null) { - messages = _resolver.computeWhyNotPromotedMessages(receiver, + messages = _resolver.computeWhyNotPromotedMessages( nameErrorEntity, flow.whyNotPromotedImplicitThis(thisType)()); } } diff --git a/pkg/analyzer/lib/src/error/bool_expression_verifier.dart b/pkg/analyzer/lib/src/error/bool_expression_verifier.dart index 43d246299da..e56e3ad7d48 100644 --- a/pkg/analyzer/lib/src/error/bool_expression_verifier.dart +++ b/pkg/analyzer/lib/src/error/bool_expression_verifier.dart @@ -57,7 +57,7 @@ class BoolExpressionVerifier { errorCode: CompileTimeErrorCode .UNCHECKED_USE_OF_NULLABLE_VALUE_AS_CONDITION, messages: _resolver.computeWhyNotPromotedMessages( - expression, expression, whyNotPromoted?.call())); + expression, whyNotPromoted?.call())); } else { _errorReporter.reportErrorForNode(errorCode, expression, arguments); } diff --git a/pkg/analyzer/lib/src/error/nullable_dereference_verifier.dart b/pkg/analyzer/lib/src/error/nullable_dereference_verifier.dart index cf1f3b53e1b..fb96d1b6712 100644 --- a/pkg/analyzer/lib/src/error/nullable_dereference_verifier.dart +++ b/pkg/analyzer/lib/src/error/nullable_dereference_verifier.dart @@ -76,8 +76,8 @@ class NullableDereferenceVerifier { List? messages; if (errorNode is Expression) { - messages = _resolver.computeWhyNotPromotedMessages(errorNode, errorNode, - _resolver.flowAnalysis?.flow?.whyNotPromoted(errorNode)()); + messages = _resolver.computeWhyNotPromotedMessages( + errorNode, _resolver.flowAnalysis?.flow?.whyNotPromoted(errorNode)()); } report(errorNode, receiverType, errorCode: errorCode, messages: messages); return true; diff --git a/pkg/analyzer/lib/src/generated/error_detection_helpers.dart b/pkg/analyzer/lib/src/generated/error_detection_helpers.dart index af745c8a6d8..ce693933d51 100644 --- a/pkg/analyzer/lib/src/generated/error_detection_helpers.dart +++ b/pkg/analyzer/lib/src/generated/error_detection_helpers.dart @@ -85,8 +85,8 @@ mixin ErrorDetectionHelpers { } return; } - var messages = computeWhyNotPromotedMessages( - expression, expression, whyNotPromoted?.call()); + var messages = + computeWhyNotPromotedMessages(expression, whyNotPromoted?.call()); // report problem if (isConstConstructor) { // TODO(paulberry): this error should be based on the actual type of the @@ -229,7 +229,6 @@ mixin ErrorDetectionHelpers { /// [whyNotPromoted] should be the non-promotion details returned by the flow /// analysis engine. List computeWhyNotPromotedMessages( - Expression? expression, SyntacticEntity errorEntity, Map? whyNotPromoted); @@ -313,8 +312,7 @@ mixin ErrorDetectionHelpers { errorCode, getErrorNode(expression), [actualStaticType, expectedStaticType], - computeWhyNotPromotedMessages( - expression, expression, whyNotPromoted?.call()), + computeWhyNotPromotedMessages(expression, whyNotPromoted?.call()), ); return false; } diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart index 9601c2e9b08..0d097e9a9ce 100644 --- a/pkg/analyzer/lib/src/generated/error_verifier.dart +++ b/pkg/analyzer/lib/src/generated/error_verifier.dart @@ -312,7 +312,6 @@ class ErrorVerifier extends RecursiveAstVisitor @override List computeWhyNotPromotedMessages( - Expression? expression, SyntacticEntity errorEntity, Map? whyNotPromoted) { return []; diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart index 1a1918de1dd..b8787935156 100644 --- a/pkg/analyzer/lib/src/generated/resolver.dart +++ b/pkg/analyzer/lib/src/generated/resolver.dart @@ -533,17 +533,13 @@ class ResolverVisitor extends ScopedVisitor with ErrorDetectionHelpers { @override List computeWhyNotPromotedMessages( - Expression? expression, SyntacticEntity errorEntity, Map? whyNotPromoted) { - if (expression is NamedExpression) { - expression = expression.expression; - } List messages = []; if (whyNotPromoted != null) { for (var entry in whyNotPromoted.entries) { var whyNotPromotedVisitor = _WhyNotPromotedVisitor( - source, expression, errorEntity, flowAnalysis!.dataForTesting); + source, errorEntity, flowAnalysis!.dataForTesting); if (typeSystem.isPotentiallyNullable(entry.key)) continue; var message = entry.value.accept(whyNotPromotedVisitor); if (message != null) { @@ -3447,10 +3443,6 @@ class _WhyNotPromotedVisitor PromotableElement, DartType> { final Source source; - /// The expression that was not promoted, or `null` if the thing that was not - /// promoted was an implicit `this`. - final Expression? _expression; - final SyntacticEntity _errorEntity; final FlowAnalysisDataForTesting? _dataForTesting; @@ -3459,8 +3451,7 @@ class _WhyNotPromotedVisitor DartType? propertyType; - _WhyNotPromotedVisitor( - this.source, this._expression, this._errorEntity, this._dataForTesting); + _WhyNotPromotedVisitor(this.source, this._errorEntity, this._dataForTesting); @override DiagnosticMessage? visitDemoteViaExplicitWrite( @@ -3480,18 +3471,7 @@ class _WhyNotPromotedVisitor @override DiagnosticMessage? visitPropertyNotPromoted( PropertyNotPromoted reason) { - var expression = _expression; - Element? receiverElement; - if (expression is SimpleIdentifier) { - receiverElement = expression.staticElement; - } else if (expression is PropertyAccess) { - receiverElement = expression.propertyName.staticElement; - } else if (expression is PrefixedIdentifier) { - receiverElement = expression.identifier.staticElement; - } else { - assert(false, - 'Unrecognized property access expression: ${expression.runtimeType}'); - } + var receiverElement = reason.propertyMember; if (receiverElement is PropertyAccessorElement) { propertyReference = receiverElement; propertyType = reason.staticType; 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 89fdd5e240b..3458ef6436a 100644 --- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart +++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart @@ -1480,7 +1480,6 @@ class InferenceVisitor replacement = inferrer.helper.buildProblem( messageNullableSpreadError, receiver.fileOffset, 1, context: inferrer.getWhyNotPromotedContext( - receiver, inferrer.flowAnalysis?.whyNotPromoted(receiver)(), element, (type) => !type.isPotentiallyNullable)); @@ -1550,7 +1549,6 @@ class InferenceVisitor replacement = inferrer.helper.buildProblem( messageNullableSpreadError, receiver.fileOffset, 1, context: inferrer.getWhyNotPromotedContext( - receiver, inferrer.flowAnalysis?.whyNotPromoted(receiver)(), element, (type) => !type.isPotentiallyNullable)); @@ -1988,7 +1986,6 @@ class InferenceVisitor Expression problem = inferrer.helper.buildProblem( messageNullableSpreadError, receiver.fileOffset, 1, context: inferrer.getWhyNotPromotedContext( - receiver, inferrer.flowAnalysis?.whyNotPromoted(receiver)(), entry, (type) => !type.isPotentiallyNullable)); @@ -2008,7 +2005,6 @@ class InferenceVisitor receiver.fileOffset, 1, context: inferrer.getWhyNotPromotedContext( - receiver, inferrer.flowAnalysis?.whyNotPromoted(receiver)(), entry, (type) => !type.isPotentiallyNullable)); @@ -2119,7 +2115,6 @@ class InferenceVisitor keyError = inferrer.helper.buildProblem( messageNullableSpreadError, receiver.fileOffset, 1, context: inferrer.getWhyNotPromotedContext( - receiver, inferrer.flowAnalysis?.whyNotPromoted(receiver)(), entry, (type) => !type.isPotentiallyNullable)); @@ -2884,8 +2879,9 @@ class InferenceVisitor } ExpressionInferenceResult readResult = _computePropertyGet(node.readOffset, - readReceiver, receiverType, node.propertyName, const UnknownType(), - isThisReceiver: node.receiver is ThisExpression); + readReceiver, receiverType, node.propertyName, const UnknownType(), + isThisReceiver: node.receiver is ThisExpression) + .expressionInferenceResult; Expression read = readResult.expression; DartType readType = readResult.inferredType; @@ -2941,8 +2937,9 @@ class InferenceVisitor Expression writeReceiver = createVariableGet(receiverVariable); ExpressionInferenceResult readResult = _computePropertyGet(node.readOffset, - readReceiver, receiverType, node.propertyName, const UnknownType(), - isThisReceiver: node.receiver is ThisExpression); + readReceiver, receiverType, node.propertyName, const UnknownType(), + isThisReceiver: node.receiver is ThisExpression) + .expressionInferenceResult; reportNonNullableInNullAwareWarningIfNeeded( readResult.inferredType, "??=", node.readOffset); @@ -4695,7 +4692,7 @@ class InferenceVisitor /// [typeContext] is used to create implicit generic tearoff instantiation /// if necessary. [isThisReceiver] must be set to `true` if the receiver is a /// `this` expression. - ExpressionInferenceResult _computePropertyGet( + PropertyGetInferenceResult _computePropertyGet( int fileOffset, Expression receiver, DartType receiverType, @@ -4879,12 +4876,11 @@ class InferenceVisitor read.fileOffset, propertyName.text.length, context: inferrer.getWhyNotPromotedContext( - receiver, inferrer.flowAnalysis?.whyNotPromoted(receiver)(), read, (type) => !type.isPotentiallyNullable)); } - return readResult; + return new PropertyGetInferenceResult(readResult, readTarget.member); } /// Creates a property set operation of [writeTarget] on [receiver] using @@ -5216,12 +5212,13 @@ class InferenceVisitor DartType nonNullReceiverType = receiverType.toNonNull(); ExpressionInferenceResult readResult = _computePropertyGet( - node.readOffset, - readReceiver, - nonNullReceiverType, - node.propertyName, - const UnknownType(), - isThisReceiver: node.receiver is ThisExpression); + node.readOffset, + readReceiver, + nonNullReceiverType, + node.propertyName, + const UnknownType(), + isThisReceiver: node.receiver is ThisExpression) + .expressionInferenceResult; Expression read = readResult.expression; DartType readType = readResult.inferredType; @@ -5752,8 +5749,9 @@ class InferenceVisitor DartType nonNullReceiverType = receiverType.toNonNull(); ExpressionInferenceResult readResult = _computePropertyGet(node.readOffset, - readReceiver, nonNullReceiverType, node.name, typeContext, - isThisReceiver: node.receiver is ThisExpression); + readReceiver, nonNullReceiverType, node.name, typeContext, + isThisReceiver: node.receiver is ThisExpression) + .expressionInferenceResult; Expression read = readResult.expression; DartType readType = readResult.inferredType; inferrer.flowAnalysis.ifNullExpression_rightBegin(read, readType); @@ -5845,11 +5843,13 @@ class InferenceVisitor DartType receiverType = result.nullAwareActionType; node.receiver = receiver..parent = node; - ExpressionInferenceResult readResult = _computePropertyGet( + PropertyGetInferenceResult propertyGetInferenceResult = _computePropertyGet( node.fileOffset, receiver, receiverType, node.name, typeContext, isThisReceiver: node.receiver is ThisExpression); - inferrer.flowAnalysis.propertyGet( - node, node.receiver, node.name.text, readResult.inferredType); + ExpressionInferenceResult readResult = + propertyGetInferenceResult.expressionInferenceResult; + inferrer.flowAnalysis.propertyGet(node, node.receiver, node.name.text, + propertyGetInferenceResult.member, readResult.inferredType); ExpressionInferenceResult expressionInferenceResult = inferrer.createNullAwareExpressionInferenceResult( readResult.inferredType, readResult.expression, nullAwareGuards); 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 15606b8f539..463c05b653f 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 @@ -290,14 +290,13 @@ class TypeInferrerImpl implements TypeInferrer { /// promoted, to be used when reporting an error for a larger expression /// containing [receiver]. [node] is the containing tree node. List getWhyNotPromotedContext( - Expression receiver, Map whyNotPromoted, TreeNode node, bool Function(DartType) typeFilter) { List context; if (whyNotPromoted != null && whyNotPromoted.isNotEmpty) { _WhyNotPromotedVisitor whyNotPromotedVisitor = - new _WhyNotPromotedVisitor(this, receiver); + new _WhyNotPromotedVisitor(this); for (core.MapEntry entry in whyNotPromoted.entries) { if (!typeFilter(entry.key)) continue; @@ -615,7 +614,6 @@ class TypeInferrerImpl implements TypeInferrer { nullabilityErrorTemplate.withArguments(expressionType, declaredContextType ?? contextType, isNonNullableByDefault), context: getWhyNotPromotedContext( - expression, flowAnalysis?.whyNotPromoted(expression)(), expression, (type) => typeSchemaEnvironment.isSubtypeOf(type, @@ -2826,7 +2824,6 @@ class TypeInferrerImpl implements TypeInferrer { // void Function() get call => () {}; // } List context = getWhyNotPromotedContext( - receiver, flowAnalysis?.whyNotPromoted(receiver)(), staticInvocation, (type) => !type.isPotentiallyNullable); @@ -2858,7 +2855,6 @@ class TypeInferrerImpl implements TypeInferrer { Expression replacement = result.applyResult(staticInvocation); if (!isTopLevel && target.isNullable) { List context = getWhyNotPromotedContext( - receiver, flowAnalysis?.whyNotPromoted(receiver)(), staticInvocation, (type) => !type.isPotentiallyNullable); @@ -2972,7 +2968,6 @@ class TypeInferrerImpl implements TypeInferrer { Expression replacement = result.applyResult(expression); if (!isTopLevel && target.isNullableCallFunction) { List context = getWhyNotPromotedContext( - receiver, flowAnalysis?.whyNotPromoted(receiver)(), expression, (type) => !type.isPotentiallyNullable); @@ -3147,7 +3142,6 @@ class TypeInferrerImpl implements TypeInferrer { replacement = result.applyResult(replacement); if (!isTopLevel && target.isNullable) { List context = getWhyNotPromotedContext( - receiver, flowAnalysis?.whyNotPromoted(receiver)(), expression, (type) => !type.isPotentiallyNullable); @@ -3308,7 +3302,6 @@ class TypeInferrerImpl implements TypeInferrer { // void Function() get foo => () {}; // } List context = getWhyNotPromotedContext( - receiver, flowAnalysis?.whyNotPromoted(receiver)(), invocationResult.expression, (type) => !type.isPotentiallyNullable); @@ -3465,8 +3458,8 @@ class TypeInferrerImpl implements TypeInferrer { new PropertyGet(originalReceiver, originalName, originalTarget) ..fileOffset = fileOffset; } - flowAnalysis.propertyGet( - originalPropertyGet, originalReceiver, originalName.text, calleeType); + flowAnalysis.propertyGet(originalPropertyGet, originalReceiver, + originalName.text, originalTarget, calleeType); Expression propertyGet = originalPropertyGet; if (receiver is! ThisExpression && calleeType is! DynamicType && @@ -3518,11 +3511,8 @@ class TypeInferrerImpl implements TypeInferrer { // } // TODO(paulberry): would it be better to report NullableMethodCallError // in this scenario? - List context = getWhyNotPromotedContext( - receiver, - whyNotPromoted(), - invocationResult.expression, - (type) => !type.isPotentiallyNullable); + List context = getWhyNotPromotedContext(whyNotPromoted(), + invocationResult.expression, (type) => !type.isPotentiallyNullable); invocationResult = wrapExpressionInferenceResultInProblem( invocationResult, templateNullableExpressionCallError.withArguments( @@ -3853,7 +3843,7 @@ class TypeInferrerImpl implements TypeInferrer { return instantiateTearOff(inferredType, typeContext, expression); } flowAnalysis.thisOrSuperPropertyGet( - expression, expression.name.name, inferredType); + expression, expression.name.name, member, inferredType); return new ExpressionInferenceResult(inferredType, expression); } @@ -4644,6 +4634,17 @@ class WrapInProblemInferenceResult implements InvocationInferenceResult { } } +/// The result of inference of a property get expression. +class PropertyGetInferenceResult { + /// The main inference result. + final ExpressionInferenceResult expressionInferenceResult; + + /// The property that was looked up, or `null` if no property was found. + final Member member; + + PropertyGetInferenceResult(this.expressionInferenceResult, this.member); +} + /// The result of an expression inference. class ExpressionInferenceResult { /// The inferred type of the expression. @@ -5134,13 +5135,11 @@ class _WhyNotPromotedVisitor DartType> { final TypeInferrerImpl inferrer; - final Expression receiver; - Member propertyReference; DartType propertyType; - _WhyNotPromotedVisitor(this.inferrer, this.receiver); + _WhyNotPromotedVisitor(this.inferrer); @override LocatedMessage visitDemoteViaExplicitWrite( @@ -5158,26 +5157,16 @@ class _WhyNotPromotedVisitor @override LocatedMessage visitPropertyNotPromoted(PropertyNotPromoted reason) { - Member member; - Expression receiver = this.receiver; - if (receiver is InstanceGet) { - member = receiver.interfaceTarget; - } else if (receiver is SuperPropertyGet) { - member = receiver.interfaceTarget; - } else if (receiver is StaticInvocation) { - member = receiver.target; - } else if (receiver is PropertyGet) { - member = receiver.interfaceTarget; - } else { - assert(false, 'Unrecognized receiver: ${receiver.runtimeType}'); - } - if (member != null) { + Object member = reason.propertyMember; + if (member is Member) { propertyReference = member; propertyType = reason.staticType; return templateFieldNotPromoted .withArguments(reason.propertyName, reason.documentationLink) .withLocation(member.fileUri, member.fileOffset, noLength); } else { + assert(member == null, + 'Unrecognized property member: ${member.runtimeType}'); return null; } }