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 <paulberry@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
Paul Berry
2021-04-06 06:55:28 +00:00
committed by commit-bot@chromium.org
parent a15e9bc3d2
commit bc6cdf54fd
13 changed files with 121 additions and 121 deletions
@@ -736,8 +736,13 @@ abstract class FlowAnalysis<Node extends Object, Statement extends Node,
/// expression to the left hand side of the `.`, and [propertyName] should be
/// the identifier to the right hand side of the `.`. [staticType] should be
/// the static type of the value returned by the property get.
///
/// [propertyMember] should be whatever data structure the client uses to keep
/// track of the field or property being accessed. In the event of
/// non-promotion of a property get, this value can be retrieved from
/// [PropertyNotPromoted.propertyMember].
void propertyGet(Expression wholeExpression, Expression target,
String propertyName, Type staticType);
String propertyName, Object? propertyMember, Type staticType);
/// Retrieves the SSA node associated with [variable], or `null` if [variable]
/// is not associated with an SSA node because it is write captured. For
@@ -788,8 +793,13 @@ abstract class FlowAnalysis<Node extends Object, Statement extends Node,
/// the whole property get, and [propertyName] should be the name of the
/// property being read. [staticType] should be the static type of the value
/// returned by the property get.
void thisOrSuperPropertyGet(
Expression expression, String propertyName, Type staticType);
///
/// [propertyMember] should be whatever data structure the client uses to keep
/// track of the field or property being accessed. In the event of
/// non-promotion of a property get, this value can be retrieved from
/// [PropertyNotPromoted.propertyMember].
void thisOrSuperPropertyGet(Expression expression, String propertyName,
Object? propertyMember, Type staticType);
/// Call this method just before visiting the body of a "try/catch" statement.
///
@@ -1339,11 +1349,12 @@ class FlowAnalysisDebug<Node extends Object, Statement extends Node,
@override
void propertyGet(Expression wholeExpression, Expression target,
String propertyName, Type staticType) {
String propertyName, Object? propertyMember, Type staticType) {
_wrap(
'propertyGet($wholeExpression, $target, $propertyName, $staticType)',
'propertyGet($wholeExpression, $target, $propertyName, '
'$propertyMember, $staticType)',
() => _wrapped.propertyGet(
wholeExpression, target, propertyName, staticType));
wholeExpression, target, propertyName, propertyMember, staticType));
}
@override
@@ -1378,12 +1389,13 @@ class FlowAnalysisDebug<Node extends Object, Statement extends Node,
}
@override
void thisOrSuperPropertyGet(
Expression expression, String propertyName, Type staticType) {
void thisOrSuperPropertyGet(Expression expression, String propertyName,
Object? propertyMember, Type staticType) {
_wrap(
'thisOrSuperPropertyGet($expression, $propertyName, $staticType)',
'thisOrSuperPropertyGet($expression, $propertyName, $propertyMember, '
'$staticType)',
() => _wrapped.thisOrSuperPropertyGet(
expression, propertyName, staticType));
expression, propertyName, propertyMember, staticType));
}
@override
@@ -2334,12 +2346,17 @@ class PropertyNotPromoted<Type extends Object> 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<Variable extends Object, Type extends Object> {
/// Creates a reference representing a get of a property called [propertyName]
/// on the reference represented by `this`.
Reference<Variable, Type> propertyGet(String propertyName) =>
new _PropertyGetReference<Variable, Type>(this, propertyName);
Reference<Variable, Type> propertyGet(
String propertyName, Object? propertyMember) =>
new _PropertyGetReference<Variable, Type>(
this, propertyName, propertyMember);
/// Stores info for this reference in [variableInfo].
void storeInfo(Map<Variable?, VariableModel<Variable, Type>> variableInfo,
@@ -3952,14 +3971,14 @@ class _FlowAnalysisImpl<Node extends Object, Statement extends Node,
@override
void propertyGet(Expression wholeExpression, Expression target,
String propertyName, Type staticType) {
String propertyName, Object? propertyMember, Type staticType) {
Reference<Variable, Type>? reference =
_getExpressionReference(target)?.reference;
if (reference != null) {
_storeExpressionReference(
wholeExpression,
new ReferenceWithType<Variable, Type>(
reference.propertyGet(propertyName), staticType));
reference.propertyGet(propertyName, propertyMember), staticType));
}
}
@@ -4016,12 +4035,13 @@ class _FlowAnalysisImpl<Node extends Object, Statement extends Node,
}
@override
void thisOrSuperPropertyGet(
Expression expression, String propertyName, Type staticType) {
void thisOrSuperPropertyGet(Expression expression, String propertyName,
Object? propertyMember, Type staticType) {
_storeExpressionReference(
expression,
new ReferenceWithType<Variable, Type>(
new _ThisReference<Variable, Type>().propertyGet(propertyName),
new _ThisReference<Variable, Type>()
.propertyGet(propertyName, propertyMember),
staticType));
}
@@ -4686,7 +4706,7 @@ class _LegacyTypePromotion<Node extends Object, Statement extends Node,
@override
void propertyGet(Expression wholeExpression, Expression target,
String propertyName, Type staticType) {}
String propertyName, Object? propertyMember, Type staticType) {}
@override
SsaNode<Variable, Type>? ssaNodeForTesting(Variable variable) {
@@ -4706,8 +4726,8 @@ class _LegacyTypePromotion<Node extends Object, Statement extends Node,
void thisOrSuper(Expression expression, Type staticType) {}
@override
void thisOrSuperPropertyGet(
Expression expression, String propertyName, Type staticType) {}
void thisOrSuperPropertyGet(Expression expression, String propertyName,
Object? propertyMember, Type staticType) {}
@override
void tryCatchStatement_bodyBegin() {}
@@ -4908,7 +4928,12 @@ class _PropertyGetReference<Variable extends Object, Type extends Object>
/// 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<Type, NonPromotionReason> Function() getNonPromotionReasons(
@@ -4920,7 +4945,8 @@ class _PropertyGetReference<Variable extends Object, Type extends Object>
return () {
Map<Type, NonPromotionReason> result = <Type, NonPromotionReason>{};
for (Type type in promotedTypes) {
result[type] = new PropertyNotPromoted(propertyName, staticType);
result[type] =
new PropertyNotPromoted(propertyName, propertyMember, staticType);
}
return result;
};
+2 -2
View File
@@ -1510,7 +1510,7 @@ class _Property extends LValue {
Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> 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<Node, Statement, Expression, Var, Type> flow) {
flow.thisOrSuperPropertyGet(this, propertyName, type);
flow.thisOrSuperPropertyGet(this, propertyName, propertyName, type);
return type;
}
}
@@ -121,8 +121,7 @@ class AssignmentExpressionResolver {
CompileTimeErrorCode.INVALID_ASSIGNMENT,
right,
[rightType, writeType],
_resolver.computeWhyNotPromotedMessages(
right, right, whyNotPromoted?.call()),
_resolver.computeWhyNotPromotedMessages(right, whyNotPromoted?.call()),
);
}
@@ -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;
}
@@ -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);
}
@@ -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)());
}
}
@@ -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);
}
@@ -76,8 +76,8 @@ class NullableDereferenceVerifier {
List<DiagnosticMessage>? 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;
@@ -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<DiagnosticMessage> computeWhyNotPromotedMessages(
Expression? expression,
SyntacticEntity errorEntity,
Map<DartType, NonPromotionReason>? whyNotPromoted);
@@ -313,8 +312,7 @@ mixin ErrorDetectionHelpers {
errorCode,
getErrorNode(expression),
[actualStaticType, expectedStaticType],
computeWhyNotPromotedMessages(
expression, expression, whyNotPromoted?.call()),
computeWhyNotPromotedMessages(expression, whyNotPromoted?.call()),
);
return false;
}
@@ -312,7 +312,6 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
@override
List<DiagnosticMessage> computeWhyNotPromotedMessages(
Expression? expression,
SyntacticEntity errorEntity,
Map<DartType, NonPromotionReason>? whyNotPromoted) {
return [];
+3 -23
View File
@@ -533,17 +533,13 @@ class ResolverVisitor extends ScopedVisitor with ErrorDetectionHelpers {
@override
List<DiagnosticMessage> computeWhyNotPromotedMessages(
Expression? expression,
SyntacticEntity errorEntity,
Map<DartType, NonPromotionReason>? whyNotPromoted) {
if (expression is NamedExpression) {
expression = expression.expression;
}
List<DiagnosticMessage> 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<DartType> 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;
@@ -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);
@@ -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<LocatedMessage> getWhyNotPromotedContext(
Expression receiver,
Map<DartType, NonPromotionReason> whyNotPromoted,
TreeNode node,
bool Function(DartType) typeFilter) {
List<LocatedMessage> context;
if (whyNotPromoted != null && whyNotPromoted.isNotEmpty) {
_WhyNotPromotedVisitor whyNotPromotedVisitor =
new _WhyNotPromotedVisitor(this, receiver);
new _WhyNotPromotedVisitor(this);
for (core.MapEntry<DartType, NonPromotionReason> 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<LocatedMessage> 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<LocatedMessage> 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<LocatedMessage> 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<LocatedMessage> context = getWhyNotPromotedContext(
receiver,
flowAnalysis?.whyNotPromoted(receiver)(),
expression,
(type) => !type.isPotentiallyNullable);
@@ -3308,7 +3302,6 @@ class TypeInferrerImpl implements TypeInferrer {
// void Function() get foo => () {};
// }
List<LocatedMessage> 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<LocatedMessage> context = getWhyNotPromotedContext(
receiver,
whyNotPromoted(),
invocationResult.expression,
(type) => !type.isPotentiallyNullable);
List<LocatedMessage> 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;
}
}