Version 3.12.0-60.0.dev
Merge 81c62ce1ddf07c0b68d07bd9de9f492038a504e3 into dev
diff --git a/DEPS b/DEPS
index 241be4d..dfa08e2 100644
--- a/DEPS
+++ b/DEPS
@@ -147,7 +147,7 @@
"material_color_utilities_rev": "799b6ba2f3f1c28c67cc7e0b4f18e0c7d7f3c03e",
"native_rev": "2f33e1af716668ab79346fdded6fa3f05ffd827b", # rolled manually while record_use is experimental
"protobuf_rev": "9e30258e0aa6a6430ee36c84b75308a9702fde42",
- "pub_rev": "b21ac685bc64f6e81050ec0093aa83543d66e2fd", # rolled manually
+ "pub_rev": "db5c3c06b21098fcf7e9e5acb8a9e6f5dd15b2fe", # rolled manually
"shelf_rev": "dd830a0338b31bee92fe7ebc20b9bb963403b6b0",
"sync_http_rev": "6666fff944221891182e1f80bf56569338164d72",
"tar_rev": "13479f7c2a18f499e840ad470cfcca8c579f6909",
diff --git a/docs/gsoc/Dart-GSoC-2026-Project-Ideas.md b/docs/gsoc/Dart-GSoC-2026-Project-Ideas.md
index da4526c..4d75721 100644
--- a/docs/gsoc/Dart-GSoC-2026-Project-Ideas.md
+++ b/docs/gsoc/Dart-GSoC-2026-Project-Ideas.md
@@ -1,5 +1,5 @@
> [!info]
-> **Google Summer of Code 2026 is currently accepting applications until April 8, 2026.**
+> **Google Summer of Code 2026 is currently accepting applications until March 31st, 2026.**
The list of accepted projects will be announced on [summerofcode.withgoogle.com](https://summerofcode.withgoogle.com/organizations/).
@@ -31,7 +31,7 @@
Applications can be submitted through the [summerofcode.withgoogle.com](https://summerofcode.withgoogle.com/) website. Applicants are encouraged to submit draft proposals, linking to Google Docs with permission for mentors to comment. See also the [contributor guide](https://google.github.io/gsocguides/student/writing-a-proposal) on writing a proposal.
-**IMPORTANT**: Remember to submit _final proposals_ before [the April 8th deadline](https://developers.google.com/open-source/gsoc/timeline).
+**IMPORTANT**: Remember to submit _final proposals_ before [the March 31st deadline](https://developers.google.com/open-source/gsoc/timeline).
## TODO: More ideas as they come!
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 e54ded5..ee44075 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
@@ -311,7 +311,9 @@
void assignMatchedPatternVariable(Variable variable, int promotionKey);
/// Call this method when visiting a boolean literal expression.
- void booleanLiteral(Expression expression, bool value);
+ ///
+ /// Returns the expression info for the boolean literal.
+ ExpressionInfo booleanLiteral(bool value);
/// Call this method just after visiting the target of a cascade expression.
///
@@ -366,13 +368,13 @@
/// Call this method when finishing the visit of a conditional expression
/// ("?:").
///
- /// [elseExpression] should be the expression following the ":", and
- /// [conditionalExpression] should be the whole conditional expression.
+ /// [elseExpression] should be the expression following the ":".
/// [elseType] should be the static type of the expression following the ":",
/// and [conditionalExpressionType] should be the static type of the whole
/// conditional expression.
- void conditional_end(
- Expression conditionalExpression,
+ ///
+ /// Returns the expression info for the whole conditional expression.
+ ExpressionInfo conditional_end(
SharedTypeView conditionalExpressionType,
Expression elseExpression,
SharedTypeView elseType,
@@ -482,8 +484,9 @@
/// [equalityOperand_end] for the left and right operands. [leftOperandType]
/// and [rightOperandType] should be the static types of the left and right
/// operands.
- void equalityOperation_end(
- Expression wholeExpression,
+ ///
+ /// Returns the expression info for the `==` or `!=` expression.
+ ExpressionInfo? equalityOperation_end(
ExpressionInfo? leftOperandInfo,
SharedTypeView leftOperandType,
ExpressionInfo? rightOperandInfo,
@@ -769,13 +772,13 @@
/// Call this method after visiting the LHS of an "is" expression.
///
- /// [isExpression] should be the complete expression. [subExpression] should
- /// be the expression to which the "is" check was applied, and
- /// [subExpressionType] should be its static type. [isNot] should be a
- /// boolean indicating whether this is an "is" or an "is!" expression.
+ /// [subExpression] should be the expression to which the "is" check was
+ /// applied, and [subExpressionType] should be its static type. [isNot] should
+ /// be a boolean indicating whether this is an "is" or an "is!" expression.
/// [checkedType] should be the type being checked.
- void isExpression_end(
- Expression isExpression,
+ ///
+ /// Returns the expression info for the complete "is" expression.
+ ExpressionInfo? isExpression_end(
Expression subExpression,
bool isNot, {
required SharedTypeView subExpressionType,
@@ -806,11 +809,11 @@
/// Call this method after visiting the RHS of a logical binary operation
/// ("||" or "&&").
///
- /// [wholeExpression] should be the whole logical binary expression.
/// [rightOperand] should be the RHS. [isAnd] should indicate whether the
/// logical operator is "&&" or "||".
- void logicalBinaryOp_end(
- Expression wholeExpression,
+ ///
+ /// Returns the expression info for the whole logical binary expression.
+ ExpressionInfo logicalBinaryOp_end(
Expression rightOperand, {
required bool isAnd,
});
@@ -884,7 +887,9 @@
/// Call this method when encountering an expression that is a `null` literal.
///
/// [type] should be the static type of the literal (i.e. the type `Null`).
- void nullLiteral(Expression expression, SharedTypeView type);
+ ///
+ /// Returns the expression info for the null literal.
+ ExpressionInfo nullLiteral(SharedTypeView type);
/// Call this method just after visiting a parenthesized expression.
///
@@ -938,7 +943,14 @@
/// Call this method when writing to the [variable] with type [writtenType] in
/// a postfix increment or decrement operation.
- void postIncDec(Node node, Variable variable, SharedTypeView writtenType);
+ ///
+ /// Returns the expression info for the full post increment or decrement
+ /// expression.
+ ExpressionInfo? postIncDec(
+ Node node,
+ Variable variable,
+ SharedTypeView writtenType,
+ );
/// The type that a property named [propertyName] is promoted to, if
/// the property is currently promoted.
@@ -1214,13 +1226,13 @@
/// pseudo-expression `super`, in the case of the analyzer, which represents
/// `super.x` as a property get whose target is `super`).
///
- /// [expression] should be the `this` or `super` expression. [staticType]
- /// should be the static type of `this`.
+ /// [staticType] should be the static type of `this`.
///
/// [isSuper] indicates whether the expression that was visited was the
/// pseudo-expression `super`.
- void thisOrSuper(
- Expression expression,
+ ///
+ /// Returns the expression info for the `this` or `super` expression.
+ ExpressionInfo thisOrSuper(
SharedTypeView staticType, {
required bool isSuper,
});
@@ -1327,9 +1339,12 @@
/// Call this method when encountering an expression that reads the value of
/// a variable.
///
- /// If the variable's type is currently promoted, the promoted type is
- /// returned. Otherwise `null` is returned.
- SharedTypeView? variableRead(Expression expression, Variable variable);
+ /// Returns a pair:
+ /// - If the variable's type is currently promoted, the first element of the
+ /// pair is the promoted type. Otherwise it is `null`.
+ /// - The second element of the pair is the expression info for the variable
+ /// read.
+ (SharedTypeView?, ExpressionInfo) variableRead(Variable variable);
/// Call this method after visiting the condition part of a "while" statement.
///
@@ -1415,9 +1430,11 @@
/// source code (this happens, for example, with compound assignments and with
/// for-each loops).
///
+ /// Returns the expression info for the full assignment expression.
+ ///
/// This method should not be used for the implicit write to a non-final
/// variable in its initializer; in that case, use [initialize] instead.
- void write(
+ ExpressionInfo? write(
Node node,
Variable variable,
SharedTypeView writtenType,
@@ -1526,10 +1543,12 @@
}
@override
- void booleanLiteral(Expression expression, bool value) {
- _wrap(
- 'booleanLiteral($expression, $value)',
- () => _wrapped.booleanLiteral(expression, value),
+ ExpressionInfo booleanLiteral(bool value) {
+ return _wrap(
+ 'booleanLiteral($value)',
+ () => _wrapped.booleanLiteral(value),
+ isQuery: true,
+ isPure: false,
);
}
@@ -1582,21 +1601,21 @@
}
@override
- void conditional_end(
- Expression conditionalExpression,
+ ExpressionInfo conditional_end(
SharedTypeView conditionalExpressionType,
Expression elseExpression,
SharedTypeView elseType,
) {
- _wrap(
- 'conditional_end($conditionalExpression, $conditionalExpressionType, '
+ return _wrap(
+ 'conditional_end($conditionalExpressionType, '
'$elseExpression, $elseType)',
() => _wrapped.conditional_end(
- conditionalExpression,
conditionalExpressionType,
elseExpression,
elseType,
),
+ isQuery: true,
+ isPure: false,
);
}
@@ -1711,26 +1730,26 @@
);
@override
- void equalityOperation_end(
- Expression wholeExpression,
+ ExpressionInfo? equalityOperation_end(
ExpressionInfo? leftOperandInfo,
SharedTypeView leftOperandType,
ExpressionInfo? rightOperandInfo,
SharedTypeView rightOperandType, {
bool notEqual = false,
}) {
- _wrap(
- 'equalityOperation_end($wholeExpression, $leftOperandInfo, '
+ return _wrap(
+ 'equalityOperation_end($leftOperandInfo, '
'$leftOperandType, $rightOperandInfo, $rightOperandType, notEqual: '
'$notEqual)',
() => _wrapped.equalityOperation_end(
- wholeExpression,
leftOperandInfo,
leftOperandType,
rightOperandInfo,
rightOperandType,
notEqual: notEqual,
),
+ isQuery: true,
+ isPure: false,
);
}
@@ -1968,23 +1987,23 @@
}
@override
- void isExpression_end(
- Expression isExpression,
+ ExpressionInfo? isExpression_end(
Expression subExpression,
bool isNot, {
required SharedTypeView subExpressionType,
required SharedTypeView checkedType,
}) {
- _wrap(
- 'isExpression_end($isExpression, $subExpression, $isNot, '
+ return _wrap(
+ 'isExpression_end($subExpression, $isNot, '
'subExpressionType: $subExpressionType, checkedType: $checkedType)',
() => _wrapped.isExpression_end(
- isExpression,
subExpression,
isNot,
subExpressionType: subExpressionType,
checkedType: checkedType,
),
+ isQuery: true,
+ isPure: false,
);
}
@@ -2032,18 +2051,15 @@
}
@override
- void logicalBinaryOp_end(
- Expression wholeExpression,
+ ExpressionInfo logicalBinaryOp_end(
Expression rightOperand, {
required bool isAnd,
}) {
- _wrap(
- 'logicalBinaryOp_end($wholeExpression, $rightOperand, isAnd: $isAnd)',
- () => _wrapped.logicalBinaryOp_end(
- wholeExpression,
- rightOperand,
- isAnd: isAnd,
- ),
+ return _wrap(
+ 'logicalBinaryOp_end($rightOperand, isAnd: $isAnd)',
+ () => _wrapped.logicalBinaryOp_end(rightOperand, isAnd: isAnd),
+ isQuery: true,
+ isPure: false,
);
}
@@ -2117,7 +2133,7 @@
@override
void nullAwareAccess_rightBegin(
- Expression? target,
+ Expression target,
SharedTypeView targetType, {
Variable? guardVariable,
}) {
@@ -2183,10 +2199,12 @@
}
@override
- void nullLiteral(Expression expression, SharedTypeView type) {
- _wrap(
- 'nullLiteral($expression, $type)',
- () => _wrapped.nullLiteral(expression, type),
+ ExpressionInfo nullLiteral(SharedTypeView type) {
+ return _wrap(
+ 'nullLiteral($type)',
+ () => _wrapped.nullLiteral(type),
+ isQuery: true,
+ isPure: false,
);
}
@@ -2261,10 +2279,16 @@
}
@override
- void postIncDec(Node node, Variable variable, SharedTypeView writtenType) {
- _wrap(
+ ExpressionInfo? postIncDec(
+ Node node,
+ Variable variable,
+ SharedTypeView writtenType,
+ ) {
+ return _wrap(
'postIncDec()',
() => _wrapped.postIncDec(node, variable, writtenType),
+ isQuery: true,
+ isPure: false,
);
}
@@ -2487,14 +2511,15 @@
}
@override
- void thisOrSuper(
- Expression expression,
+ ExpressionInfo thisOrSuper(
SharedTypeView staticType, {
required bool isSuper,
}) {
return _wrap(
- 'thisOrSuper($expression, $staticType, isSuper: $isSuper)',
- () => _wrapped.thisOrSuper(expression, staticType, isSuper: isSuper),
+ 'thisOrSuper($staticType, isSuper: $isSuper)',
+ () => _wrapped.thisOrSuper(staticType, isSuper: isSuper),
+ isQuery: true,
+ isPure: false,
);
}
@@ -2578,10 +2603,10 @@
}
@override
- SharedTypeView? variableRead(Expression expression, Variable variable) {
+ (SharedTypeView?, ExpressionInfo) variableRead(Variable variable) {
return _wrap(
- 'variableRead($expression, $variable)',
- () => _wrapped.variableRead(expression, variable),
+ 'variableRead($variable)',
+ () => _wrapped.variableRead(variable),
isQuery: true,
isPure: false,
);
@@ -2635,15 +2660,17 @@
}
@override
- void write(
+ ExpressionInfo? write(
Node node,
Variable variable,
SharedTypeView writtenType,
Expression? writtenExpression,
) {
- _wrap(
+ return _wrap(
'write($node, $variable, $writtenType, $writtenExpression)',
() => _wrapped.write(node, variable, writtenType, writtenExpression),
+ isQuery: true,
+ isPure: false,
);
}
@@ -2736,7 +2763,7 @@
/// be called once upon reaching each `?.`, but [nullAwareAccess_end] should
/// not be called until after processing the method call to `z(x)`.
void nullAwareAccess_rightBegin(
- Expression? target,
+ Expression target,
SharedTypeView targetType, {
Variable? guardVariable,
});
@@ -5207,22 +5234,21 @@
}
@override
- void booleanLiteral(Expression expression, bool value) {
+ ExpressionInfo booleanLiteral(bool value) {
FlowModel unreachable = _current.setUnreachable();
- _storeExpressionInfo(
- expression,
- value
- ? new ExpressionInfo(
- type: boolType,
- ifTrue: _current,
- ifFalse: unreachable,
- )
- : new ExpressionInfo(
- type: boolType,
- ifTrue: unreachable,
- ifFalse: _current,
- ),
- );
+ if (value) {
+ return new ExpressionInfo(
+ type: boolType,
+ ifTrue: _current,
+ ifFalse: unreachable,
+ );
+ } else {
+ return new ExpressionInfo(
+ type: boolType,
+ ifTrue: unreachable,
+ ifFalse: _current,
+ );
+ }
}
@override
@@ -5258,20 +5284,14 @@
_cascadeTargetStack.add(
_makeTemporaryReference(ssaNode, promotedTargetType),
);
- // Calling `_getExpressionReference` had the effect of clearing
- // `_expressionReference` (because normally the caller doesn't pass the same
- // expression to flow analysis twice, so the expression reference isn't
- // needed anymore). However, in the case of null-aware cascades, this call
- // will be followed by a call to [nullAwareAccess_rightBegin], and the
- // expression reference will be needed again. So store it back.
- if (expressionReference != null) {
- _storeExpressionInfo(target, expressionReference);
- }
if (isNullAware) {
- _nullAwareAccess_rightBegin(
+ _storeExpressionInfo(
target,
- targetType,
- guardVariable: guardVariable,
+ _nullAwareAccess_rightBegin(
+ expressionReference,
+ targetType,
+ guardVariable: guardVariable,
+ ),
);
}
return promotedTargetType;
@@ -5311,8 +5331,7 @@
}
@override
- void conditional_end(
- Expression conditionalExpression,
+ ExpressionInfo conditional_end(
SharedTypeView conditionalExpressionType,
Expression elseExpression,
SharedTypeView elseType,
@@ -5325,13 +5344,10 @@
_makeTrivialExpressionInfo(elseType);
FlowModel elseModel = _current;
_current = _join(thenModel, elseModel).unsplit();
- _storeExpressionInfo(
- conditionalExpression,
- new ExpressionInfo(
- type: conditionalExpressionType,
- ifTrue: _join(thenInfo.ifTrue, elseInfo.ifTrue).unsplit(),
- ifFalse: _join(thenInfo.ifFalse, elseInfo.ifFalse).unsplit(),
- ),
+ return new ExpressionInfo(
+ type: conditionalExpressionType,
+ ifTrue: _join(thenInfo.ifTrue, elseInfo.ifTrue).unsplit(),
+ ifFalse: _join(thenInfo.ifFalse, elseInfo.ifFalse).unsplit(),
);
}
@@ -5462,8 +5478,7 @@
_getExpressionInfo(operand);
@override
- void equalityOperation_end(
- Expression wholeExpression,
+ ExpressionInfo? equalityOperation_end(
ExpressionInfo? leftOperandInfo,
SharedTypeView leftOperandType,
ExpressionInfo? rightOperandInfo,
@@ -5485,12 +5500,12 @@
// Both operands are known by flow analysis to compare equal, so the
// whole expression behaves equivalently to a boolean (either `true` or
// `false` depending whether the check uses the `!=` operator).
- booleanLiteral(wholeExpression, !notEqual);
+ return booleanLiteral(!notEqual);
case _GuaranteedNotEqual():
// Both operands are known by flow analysis to compare unequal, so the
// whole expression behaves equivalently to a boolean (either `true` or
// `false` depending whether the check uses the `!=` operator).
- booleanLiteral(wholeExpression, notEqual);
+ return booleanLiteral(notEqual);
// SAFETY: we can assume `reference` is a `_Reference<Type>` because we
// require clients not to mix data obtained from different
@@ -5499,7 +5514,7 @@
if (reference == null) {
// One side of the equality check is `null`, but the other side is not
// a promotable reference. So there's no promotion to do.
- return;
+ return null;
}
// The equality check is a null check of something potentially
// promotable (e.g. a local variable). Record the necessary information
@@ -5509,19 +5524,15 @@
this,
reference,
);
- _storeExpressionInfo(
- wholeExpression,
- notEqual ? equalityInfo : equalityInfo._invert(),
- );
+ return notEqual ? equalityInfo : equalityInfo._invert();
case _NoEqualityInformation():
- // Since flow analysis can't garner any information from this equality
- // check, nothing needs to be done; by not calling `_storeExpressionInfo`,
- // we ensure that if `_getExpressionInfo` is later called on this
- // expression, `null` will be returned. That means that if this
- // expression winds up being used for a conditional branch, flow analysis
- // will consider both code paths reachable and won't perform any
- // promotions on either path.
+ // Since flow analysis can't garner any information from this equality
+ // check, nothing needs to be done; by not returning any expression
+ // info, we ensure that if this expression winds up being used for a
+ // conditional branch, flow analysis will consider both code paths
+ // reachable and won't perform any promotions on either path.
+ return null;
}
}
@@ -5812,8 +5823,7 @@
}
@override
- void isExpression_end(
- Expression isExpression,
+ ExpressionInfo? isExpression_end(
Expression subExpression,
bool isNot, {
required SharedTypeView subExpressionType,
@@ -5824,7 +5834,7 @@
staticType: subExpressionType,
checkedType: checkedType,
)) {
- booleanLiteral(isExpression, isNot);
+ return booleanLiteral(isNot);
} else {
_Reference? subExpressionReference = _getExpressionReference(
_getExpressionInfo(subExpression),
@@ -5835,15 +5845,14 @@
subExpressionReference,
checkedType,
);
- _storeExpressionInfo(
- isExpression,
- isNot ? expressionInfo._invert() : expressionInfo,
- );
+ return isNot ? expressionInfo._invert() : expressionInfo;
} else if (_isTypeCheckGuaranteedToSucceedWithSoundNullSafety(
staticType: subExpressionType,
checkedType: checkedType,
)) {
- booleanLiteral(isExpression, !isNot);
+ return booleanLiteral(!isNot);
+ } else {
+ return null;
}
}
}
@@ -5927,8 +5936,7 @@
}
@override
- void logicalBinaryOp_end(
- Expression wholeExpression,
+ ExpressionInfo logicalBinaryOp_end(
Expression rightOperand, {
required bool isAnd,
}) {
@@ -5947,13 +5955,10 @@
falseResult = rhsInfo.ifFalse;
}
_current = _join(trueResult, falseResult).unsplit();
- _storeExpressionInfo(
- wholeExpression,
- new ExpressionInfo(
- type: boolType,
- ifTrue: trueResult.unsplit(),
- ifFalse: falseResult.unsplit(),
- ),
+ return new ExpressionInfo(
+ type: boolType,
+ ifTrue: trueResult.unsplit(),
+ ifFalse: falseResult.unsplit(),
);
}
@@ -6043,14 +6048,17 @@
@override
void nullAwareAccess_rightBegin(
- Expression? target,
+ Expression target,
SharedTypeView targetType, {
Variable? guardVariable,
}) {
- _nullAwareAccess_rightBegin(
+ _storeExpressionInfo(
target,
- targetType,
- guardVariable: guardVariable,
+ _nullAwareAccess_rightBegin(
+ _getExpressionInfo(target),
+ targetType,
+ guardVariable: guardVariable,
+ ),
);
}
@@ -6136,11 +6144,8 @@
void nullCheckOrAssertPattern_end() {}
@override
- void nullLiteral(Expression expression, SharedTypeView type) {
- _storeExpressionInfo(
- expression,
- new _NullInfo(model: _current, type: type),
- );
+ ExpressionInfo nullLiteral(SharedTypeView type) {
+ return new _NullInfo(model: _current, type: type);
}
@override
@@ -6209,8 +6214,12 @@
}
@override
- void postIncDec(Node node, Variable variable, SharedTypeView writtenType) {
- _write(node, variable, writtenType, null, isPostfixIncDec: true);
+ ExpressionInfo? postIncDec(
+ Node node,
+ Variable variable,
+ SharedTypeView writtenType,
+ ) {
+ return _write(node, variable, writtenType, null, isPostfixIncDec: true);
}
@override
@@ -6608,16 +6617,11 @@
}
@override
- void thisOrSuper(
- Expression expression,
+ ExpressionInfo thisOrSuper(
SharedTypeView staticType, {
required bool isSuper,
}) {
- TrivialVariableReference reference = _thisOrSuperReference(
- staticType,
- isSuper: isSuper,
- );
- _storeExpressionInfo(expression, reference);
+ return _thisOrSuperReference(staticType, isSuper: isSuper);
}
@override
@@ -6742,7 +6746,7 @@
const [];
@override
- SharedTypeView? variableRead(Expression expression, Variable variable) {
+ (SharedTypeView?, ExpressionInfo) variableRead(Variable variable) {
SharedTypeView unpromotedType = operations.variableType(variable);
int variableKey = promotionKeyStore.keyForVariable(variable);
PromotionModel? promotionModel = _current.promotionInfo?.get(
@@ -6763,8 +6767,7 @@
this,
_current,
);
- _storeExpressionInfo(expression, expressionInfo);
- return promotionModel.promotedTypes.lastOrNull;
+ return (promotionModel.promotedTypes.lastOrNull, expressionInfo);
}
@override
@@ -6832,13 +6835,18 @@
}
@override
- void write(
+ ExpressionInfo? write(
Node node,
Variable variable,
SharedTypeView writtenType,
Expression? writtenExpression,
) {
- _write(node, variable, writtenType, _getExpressionInfo(writtenExpression));
+ return _write(
+ node,
+ variable,
+ writtenType,
+ _getExpressionInfo(writtenExpression),
+ );
}
/// Computes a [FlowModel] representing the state of execution after the
@@ -7542,16 +7550,14 @@
ExpressionInfo _makeTrivialExpressionInfo(SharedTypeView type) =>
new ExpressionInfo.trivial(model: _current, type: type);
- void _nullAwareAccess_rightBegin(
- Expression? target,
+ ExpressionInfo? _nullAwareAccess_rightBegin(
+ ExpressionInfo? targetInfo,
SharedTypeView targetType, {
required Variable? guardVariable,
}) {
_current = _current.split();
FlowModel shortcutControlPath = _current;
- _Reference? targetReference = _getExpressionReference(
- _getExpressionInfo(target),
- );
+ _Reference? targetReference = _getExpressionReference(targetInfo);
if (targetReference != null) {
_current = _current.tryMarkNonNullable(this, targetReference).ifTrue;
}
@@ -7571,6 +7577,7 @@
}
_stack.add(new _NullAwareAccessContext(shortcutControlPath));
SsaNode? targetSsaNode;
+ ExpressionInfo? nullAwareExpressionInfo = targetReference;
if (typeAnalyzerOptions.soundFlowAnalysisEnabled) {
// Pick up the target SSA node so that it can be used for field promotion.
targetSsaNode = targetReference?.ssaNode;
@@ -7578,7 +7585,7 @@
// Field promotion was broken for null-aware field accesses prior to the
// implementation of sound flow analysis. So to replicate the bug, destroy
// the target reference so that it can't be used for field promotion.
- if (target != null) _storeExpressionInfo(target, null);
+ nullAwareExpressionInfo = null;
}
if (guardVariable != null) {
// Promote the guard variable as well.
@@ -7596,6 +7603,7 @@
),
);
}
+ return nullAwareExpressionInfo;
}
/// Computes an updated flow model representing the result of a null check
@@ -7749,7 +7757,7 @@
///
/// If [isPostfixIncDec] is `true`, the [node] is a postfix expression and we
/// won't store information about [variable].
- void _write(
+ ExpressionInfo? _write(
Node node,
Variable variable,
SharedTypeView writtenType,
@@ -7774,12 +7782,13 @@
);
// Update the type of the variable for looking up the write expression.
+ TrivialVariableReference? reference;
if (typeAnalyzerOptions.inferenceUpdate4Enabled &&
node is Expression &&
!isPostfixIncDec) {
- _Reference reference = _variableReference(variableKey, unpromotedType);
- _storeExpressionInfo(node, reference);
+ reference = _variableReference(variableKey, unpromotedType);
}
+ return reference;
}
}
diff --git a/pkg/_fe_analyzer_shared/test/mini_ast.dart b/pkg/_fe_analyzer_shared/test/mini_ast.dart
index 7d354f0..c2d33d4 100644
--- a/pkg/_fe_analyzer_shared/test/mini_ast.dart
+++ b/pkg/_fe_analyzer_shared/test/mini_ast.dart
@@ -5888,10 +5888,13 @@
Expression postIncDecExpression,
Type writtenType,
) {
- h.flow.postIncDec(
+ h.flow.storeExpressionInfo(
postIncDecExpression,
- variable,
- SharedTypeView(writtenType),
+ h.flow.postIncDec(
+ postIncDecExpression,
+ variable,
+ SharedTypeView(writtenType),
+ ),
);
}
@@ -5902,11 +5905,14 @@
Type writtenType,
Expression? rhs,
) {
- h.flow.write(
+ h.flow.storeExpressionInfo(
assignmentExpression,
- variable,
- SharedTypeView(writtenType),
- rhs,
+ h.flow.write(
+ assignmentExpression,
+ variable,
+ SharedTypeView(writtenType),
+ rhs,
+ ),
);
}
}
@@ -6507,16 +6513,21 @@
}
var rightType = analyzeExpression(rhs, operations.unknownType).type;
if (isEquals) {
- flow.equalityOperation_end(
+ flow.storeExpressionInfo(
node,
- leftInfo,
- leftType,
- flow.equalityOperand_end(rhs),
- rightType,
- notEqual: isNot,
+ flow.equalityOperation_end(
+ leftInfo,
+ leftType,
+ flow.equalityOperand_end(rhs),
+ rightType,
+ notEqual: isNot,
+ ),
);
} else if (isLogical) {
- flow.logicalBinaryOp_end(node, rhs, isAnd: isAnd);
+ flow.storeExpressionInfo(
+ node,
+ flow.logicalBinaryOp_end(rhs, isAnd: isAnd),
+ );
}
return new ExpressionTypeAnalysisResult(type: operations.boolType);
}
@@ -6528,7 +6539,7 @@
}
Type analyzeBoolLiteral(Expression node, bool value) {
- flow.booleanLiteral(node, value);
+ flow.storeExpressionInfo(node, flow.booleanLiteral(value));
return operations.boolType.unwrapTypeView();
}
@@ -6549,7 +6560,10 @@
flow.conditional_elseBegin(ifTrue, ifTrueType);
var ifFalseType = analyzeExpression(ifFalse, operations.unknownType).type;
var lubType = operations.lub(ifTrueType, ifFalseType);
- flow.conditional_end(node, lubType, ifFalse, ifFalseType);
+ flow.storeExpressionInfo(
+ node,
+ flow.conditional_end(lubType, ifFalse, ifFalseType),
+ );
return new ExpressionTypeAnalysisResult(type: lubType);
}
@@ -6697,7 +6711,7 @@
}
ExpressionTypeAnalysisResult analyzeNullLiteral(Expression node) {
- flow.nullLiteral(node, SharedTypeView(nullType));
+ flow.storeExpressionInfo(node, flow.nullLiteral(SharedTypeView(nullType)));
return new ExpressionTypeAnalysisResult(type: SharedTypeView(nullType));
}
@@ -6743,7 +6757,10 @@
ExpressionTypeAnalysisResult analyzeThis(Expression node) {
var thisType = this.thisType;
- flow.thisOrSuper(node, SharedTypeView(thisType), isSuper: false);
+ flow.storeExpressionInfo(
+ node,
+ flow.thisOrSuper(SharedTypeView(thisType), isSuper: false),
+ );
return new ExpressionTypeAnalysisResult(type: SharedTypeView(thisType));
}
@@ -6841,12 +6858,14 @@
expression,
operations.unknownType,
).type;
- flow.isExpression_end(
+ flow.storeExpressionInfo(
node,
- expression,
- isInverted,
- subExpressionType: subExpressionType,
- checkedType: SharedTypeView(type),
+ flow.isExpression_end(
+ expression,
+ isInverted,
+ subExpressionType: subExpressionType,
+ checkedType: SharedTypeView(type),
+ ),
);
return new ExpressionTypeAnalysisResult(type: operations.boolType);
}
@@ -6856,7 +6875,8 @@
Var variable,
void Function(Type?)? callback,
) {
- var promotedType = flow.variableRead(node, variable);
+ var (promotedType, expressionInfo) = flow.variableRead(variable);
+ flow.storeExpressionInfo(node, expressionInfo);
callback?.call(promotedType?.unwrapTypeView());
return new ExpressionTypeAnalysisResult(
type: promotedType ?? SharedTypeView(variable.type),
diff --git a/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart b/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart
index 1708d81..c02e74d 100644
--- a/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart
+++ b/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart
@@ -268,9 +268,6 @@
Name name,
) {
var interface = getInterface(element);
- if (element is ExtensionTypeElementImpl) {
- return interface.redeclared[name];
- }
return interface.overridden[name];
}
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 4e52587..29f9aaf 100644
--- a/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
@@ -106,11 +106,14 @@
if (flow != null) {
if (writeElement2 is PromotableElementImpl) {
- flow.write(
+ flow.storeExpressionInfo(
node,
- writeElement2,
- SharedTypeView(node.typeOrThrow),
- hasRead ? null : right,
+ flow.write(
+ node,
+ writeElement2,
+ SharedTypeView(node.typeOrThrow),
+ hasRead ? null : right,
+ ),
);
}
if (isIfNull) {
diff --git a/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
index 596bf48..f553976 100644
--- a/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
@@ -124,13 +124,15 @@
var whyNotPromoted = flowAnalysis.flow?.whyNotPromoted(right);
if (!leftExtensionOverride) {
- flow?.equalityOperation_end(
+ flow?.storeExpressionInfo(
node,
- leftInfo,
- SharedTypeView(left.typeOrThrow),
- flow.equalityOperand_end(right),
- SharedTypeView(right.typeOrThrow),
- notEqual: notEqual,
+ flow.equalityOperation_end(
+ leftInfo,
+ SharedTypeView(left.typeOrThrow),
+ flow.equalityOperand_end(right),
+ SharedTypeView(right.typeOrThrow),
+ notEqual: notEqual,
+ ),
);
}
@@ -272,7 +274,10 @@
);
_resolver.nullSafetyDeadCodeVerifier.flowEnd(right);
- flow?.logicalBinaryOp_end(node, right, isAnd: true);
+ flow?.storeExpressionInfo(
+ node,
+ flow.logicalBinaryOp_end(right, isAnd: true),
+ );
_checkNonBoolOperand(left, '&&', whyNotPromoted: leftWhyNotPromoted);
_checkNonBoolOperand(right, '&&', whyNotPromoted: rightWhyNotPromoted);
@@ -306,7 +311,10 @@
);
_resolver.nullSafetyDeadCodeVerifier.flowEnd(right);
- flow?.logicalBinaryOp_end(node, right, isAnd: false);
+ flow?.storeExpressionInfo(
+ node,
+ flow.logicalBinaryOp_end(right, isAnd: false),
+ );
_checkNonBoolOperand(left, '||', whyNotPromoted: leftWhyNotPromoted);
_checkNonBoolOperand(right, '||', whyNotPromoted: rightWhyNotPromoted);
diff --git a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
index 579ac43..d5f24df 100644
--- a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
@@ -296,12 +296,14 @@
var expression = node.expression;
var typeAnnotation = node.type;
- flow!.isExpression_end(
+ flow!.storeExpressionInfo(
node,
- expression,
- node.notOperator != null,
- subExpressionType: SharedTypeView(expression.typeOrThrow),
- checkedType: SharedTypeView(typeAnnotation.typeOrThrow),
+ flow!.isExpression_end(
+ expression,
+ node.notOperator != null,
+ subExpressionType: SharedTypeView(expression.typeOrThrow),
+ checkedType: SharedTypeView(typeAnnotation.typeOrThrow),
+ ),
);
}
@@ -1307,10 +1309,16 @@
@override
TypeImpl getType(SimpleIdentifierImpl node, {required bool isRead}) {
var variable = node.element as InternalVariableElement;
- if (variable is PromotableElementImpl) {
- var promotedType = isRead
- ? _manager.flow?.variableRead(node, variable)
- : _manager.flow?.promotedType(variable);
+ var flow = _manager.flow;
+ if (variable is PromotableElementImpl && flow != null) {
+ SharedTypeView? promotedType;
+ if (isRead) {
+ ExpressionInfo expressionInfo;
+ (promotedType, expressionInfo) = flow.variableRead(variable);
+ flow.storeExpressionInfo(node, expressionInfo);
+ } else {
+ promotedType = flow.promotedType(variable);
+ }
if (promotedType != null) {
return promotedType.unwrapTypeView<TypeImpl>();
}
diff --git a/pkg/analyzer/lib/src/dart/resolver/invocation_inferrer.dart b/pkg/analyzer/lib/src/dart/resolver/invocation_inferrer.dart
index e53af67..cd36042 100644
--- a/pkg/analyzer/lib/src/dart/resolver/invocation_inferrer.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/invocation_inferrer.dart
@@ -570,12 +570,14 @@
if (identicalArgumentInfo != null) {
var leftOperandInfo = identicalArgumentInfo[0]!;
var rightOperandInfo = identicalArgumentInfo[1]!;
- flow?.equalityOperation_end(
+ flow?.storeExpressionInfo(
argumentList.parent as ExpressionImpl,
- leftOperandInfo.expressionInfo,
- SharedTypeView(leftOperandInfo.staticType),
- rightOperandInfo.expressionInfo,
- SharedTypeView(rightOperandInfo.staticType),
+ flow.equalityOperation_end(
+ leftOperandInfo.expressionInfo,
+ SharedTypeView(leftOperandInfo.staticType),
+ rightOperandInfo.expressionInfo,
+ SharedTypeView(rightOperandInfo.staticType),
+ ),
);
}
}
diff --git a/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart
index ca5be97..61426f4 100644
--- a/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart
@@ -186,17 +186,23 @@
if (_resolver.definingLibrary.featureSet.isEnabled(
Feature.inference_update_4,
)) {
- _resolver.flowAnalysis.flow?.postIncDec(
+ _resolver.flowAnalysis.flow?.storeExpressionInfo(
node,
- element,
- SharedTypeView(operatorReturnType),
+ _resolver.flowAnalysis.flow?.postIncDec(
+ node,
+ element,
+ SharedTypeView(operatorReturnType),
+ ),
);
} else {
- _resolver.flowAnalysis.flow?.write(
+ _resolver.flowAnalysis.flow?.storeExpressionInfo(
node,
- element,
- SharedTypeView(operatorReturnType),
- null,
+ _resolver.flowAnalysis.flow?.write(
+ node,
+ element,
+ SharedTypeView(operatorReturnType),
+ null,
+ ),
);
}
}
diff --git a/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
index d35abc8..e2afb29 100644
--- a/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
@@ -243,11 +243,14 @@
if (operand is SimpleIdentifier) {
var element = operand.element;
if (element is PromotableElementImpl) {
- _resolver.flowAnalysis.flow?.write(
+ _resolver.flowAnalysis.flow?.storeExpressionInfo(
node,
- element,
- SharedTypeView(staticType),
- null,
+ _resolver.flowAnalysis.flow?.write(
+ node,
+ element,
+ SharedTypeView(staticType),
+ null,
+ ),
);
}
}
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 1c19433..264cc6b 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -2027,7 +2027,10 @@
TypeImpl contextType = UnknownInferredType.instance,
}) {
inferenceLogWriter?.enterExpression(node, contextType);
- flowAnalysis.flow?.booleanLiteral(node, node.value);
+ flowAnalysis.flow?.storeExpressionInfo(
+ node,
+ flowAnalysis.flow?.booleanLiteral(node.value),
+ );
checkUnreachableNode(node);
node.visitChildren(this);
typeAnalyzer.visitBooleanLiteral(node);
@@ -2207,11 +2210,13 @@
typeAnalyzer.visitConditionalExpression(node, contextType: contextType);
if (flow != null) {
- flow.conditional_end(
+ flow.storeExpressionInfo(
node,
- SharedTypeView(node.typeOrThrow),
- elseExpression,
- SharedTypeView(elseExpression.typeOrThrow),
+ flow.conditional_end(
+ SharedTypeView(node.typeOrThrow),
+ elseExpression,
+ SharedTypeView(elseExpression.typeOrThrow),
+ ),
);
nullSafetyDeadCodeVerifier.flowEnd(elseExpression);
}
@@ -3493,7 +3498,10 @@
inferenceLogWriter?.enterExpression(node, contextType);
node.visitChildren(this);
typeAnalyzer.visitNullLiteral(node as NullLiteralImpl);
- flowAnalysis.flow?.nullLiteral(node, SharedTypeView(node.typeOrThrow));
+ flowAnalysis.flow?.storeExpressionInfo(
+ node,
+ flowAnalysis.flow?.nullLiteral(SharedTypeView(node.typeOrThrow)),
+ );
checkUnreachableNode(node);
inferenceLogWriter?.exitExpression(node);
}
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 365170d..f43af10 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -255,10 +255,12 @@
void visitSuperExpression(covariant SuperExpressionImpl node) {
var thisType = _resolver.thisType;
- _resolver.flowAnalysis.flow?.thisOrSuper(
+ _resolver.flowAnalysis.flow?.storeExpressionInfo(
node,
- SharedTypeView(thisType ?? _dynamicType),
- isSuper: true,
+ _resolver.flowAnalysis.flow?.thisOrSuper(
+ SharedTypeView(thisType ?? _dynamicType),
+ isSuper: true,
+ ),
);
if (thisType == null ||
node.thisOrAncestorOfType<ExtensionDeclaration>() != null) {
@@ -278,10 +280,12 @@
/// interface of the immediately enclosing class.</blockquote>
void visitThisExpression(covariant ThisExpressionImpl node) {
var thisType = _resolver.thisType;
- _resolver.flowAnalysis.flow?.thisOrSuper(
+ _resolver.flowAnalysis.flow?.storeExpressionInfo(
node,
- SharedTypeView(thisType ?? _dynamicType),
- isSuper: false,
+ _resolver.flowAnalysis.flow?.thisOrSuper(
+ SharedTypeView(thisType ?? _dynamicType),
+ isSuper: false,
+ ),
);
if (thisType == null) {
// TODO(brianwilkerson): Report this error if it hasn't already been
diff --git a/pkg/analyzer/test/src/dart/element/inheritance_manager3_test.dart b/pkg/analyzer/test/src/dart/element/inheritance_manager3_test.dart
index 222cc25..9f7606d 100644
--- a/pkg/analyzer/test/src/dart/element/inheritance_manager3_test.dart
+++ b/pkg/analyzer/test/src/dart/element/inheritance_manager3_test.dart
@@ -2341,7 +2341,7 @@
var element = library.getExtensionType('B')!;
_assertGetOverridden(element, 'foo', r'''
-A.foo: void Function()
+<null>
''');
}
diff --git a/pkg/analyzer/test/src/summary/elements/extension_type_test.dart b/pkg/analyzer/test/src/summary/elements/extension_type_test.dart
index cedf284..d73950b7 100644
--- a/pkg/analyzer/test/src/summary/elements/extension_type_test.dart
+++ b/pkg/analyzer/test/src/summary/elements/extension_type_test.dart
@@ -5418,105 +5418,6 @@
''');
}
- test_primaryConstructor_formalParameters_kind_requiredPositional_type_fromField_fromImplemented() async {
- var library = await buildLibrary(r'''
-class A {
- int get it => 0;
-}
-
-extension type E(it) implements A {}
-''');
-
- checkElementText(library, r'''
-library
- reference: <testLibrary>
- fragments
- #F0 <testLibraryFragment>
- element: <testLibrary>
- classes
- #F1 class A (nameOffset:6) (firstTokenOffset:0) (offset:6)
- element: <testLibrary>::@class::A
- fields
- #F2 synthetic isOriginGetterSetter it (nameOffset:<null>) (firstTokenOffset:<null>) (offset:6)
- element: <testLibrary>::@class::A::@field::it
- constructors
- #F3 synthetic isOriginImplicitDefault new (nameOffset:<null>) (firstTokenOffset:<null>) (offset:6)
- element: <testLibrary>::@class::A::@constructor::new
- typeName: A
- getters
- #F4 isOriginDeclaration it (nameOffset:20) (firstTokenOffset:12) (offset:20)
- element: <testLibrary>::@class::A::@getter::it
- extensionTypes
- #F5 extension type E (nameOffset:47) (firstTokenOffset:32) (offset:47)
- element: <testLibrary>::@extensionType::E
- fields
- #F6 isOriginDeclaringFormalParameter it (nameOffset:<null>) (firstTokenOffset:<null>) (offset:47)
- element: <testLibrary>::@extensionType::E::@field::it
- constructors
- #F7 isOriginDeclaration isPrimary new (nameOffset:<null>) (firstTokenOffset:47) (offset:47)
- element: <testLibrary>::@extensionType::E::@constructor::new
- typeName: E
- typeNameOffset: 47
- formalParameters
- #F8 requiredPositional final this.it (nameOffset:49) (firstTokenOffset:49) (offset:49)
- element: <testLibrary>::@extensionType::E::@constructor::new::@formalParameter::it
- getters
- #F9 synthetic isOriginVariable it (nameOffset:<null>) (firstTokenOffset:<null>) (offset:47)
- element: <testLibrary>::@extensionType::E::@getter::it
- classes
- class A
- reference: <testLibrary>::@class::A
- firstFragment: #F1
- fields
- synthetic isOriginGetterSetter it
- reference: <testLibrary>::@class::A::@field::it
- firstFragment: #F2
- type: int
- getter: <testLibrary>::@class::A::@getter::it
- constructors
- synthetic isOriginImplicitDefault new
- reference: <testLibrary>::@class::A::@constructor::new
- firstFragment: #F3
- getters
- isOriginDeclaration it
- reference: <testLibrary>::@class::A::@getter::it
- firstFragment: #F4
- returnType: int
- variable: <testLibrary>::@class::A::@field::it
- extensionTypes
- extension type E
- reference: <testLibrary>::@extensionType::E
- firstFragment: #F5
- representation: <testLibrary>::@extensionType::E::@field::it
- primaryConstructor: <testLibrary>::@extensionType::E::@constructor::new
- typeErasure: int
- interfaces
- A
- fields
- final hasImplicitType isOriginDeclaringFormalParameter it
- reference: <testLibrary>::@extensionType::E::@field::it
- firstFragment: #F6
- type: int
- getter: <testLibrary>::@extensionType::E::@getter::it
- declaringFormalParameter: <testLibrary>::@extensionType::E::@constructor::new::@formalParameter::it
- constructors
- declaring isExtensionTypeMember isOriginDeclaration isPrimary new
- reference: <testLibrary>::@extensionType::E::@constructor::new
- firstFragment: #F7
- formalParameters
- #E0 requiredPositional final hasImplicitType declaring this.it
- firstFragment: #F8
- type: int
- field: <testLibrary>::@extensionType::E::@field::it
- getters
- synthetic isExtensionTypeMember isOriginVariable it
- reference: <testLibrary>::@extensionType::E::@getter::it
- firstFragment: #F9
- returnType: int
- variable: <testLibrary>::@extensionType::E::@field::it
-''');
- }
-
test_primaryConstructor_formalParameters_memberWithClassName() async {
var library = await buildLibrary(r'''
extension type A(int A) {}
diff --git a/pkg/front_end/lib/src/type_inference/for_in.dart b/pkg/front_end/lib/src/type_inference/for_in.dart
index 86a3a04..ba85f40 100644
--- a/pkg/front_end/lib/src/type_inference/for_in.dart
+++ b/pkg/front_end/lib/src/type_inference/for_in.dart
@@ -71,11 +71,14 @@
);
variableSet.value = rhs..parent = variableSet;
- visitor.flowAnalysis.write(
+ visitor.flowAnalysis.storeExpressionInfo(
variableSet,
- variableSet.variable,
- new SharedTypeView(rhsType),
- null,
+ visitor.flowAnalysis.write(
+ variableSet,
+ variableSet.variable,
+ new SharedTypeView(rhsType),
+ null,
+ ),
);
return variableSet;
}
diff --git a/pkg/front_end/lib/src/type_inference/inference_visitor.dart b/pkg/front_end/lib/src/type_inference/inference_visitor.dart
index ce3fabd..7eefa4e 100644
--- a/pkg/front_end/lib/src/type_inference/inference_visitor.dart
+++ b/pkg/front_end/lib/src/type_inference/inference_visitor.dart
@@ -1258,7 +1258,10 @@
BoolLiteral node,
DartType typeContext,
) {
- flowAnalysis.booleanLiteral(node, node.value);
+ flowAnalysis.storeExpressionInfo(
+ node,
+ flowAnalysis.booleanLiteral(node.value),
+ );
return new ExpressionInferenceResult(
coreTypes.boolRawType(Nullability.nonNullable),
node,
@@ -1458,11 +1461,13 @@
inferredType = t;
}
- flowAnalysis.conditional_end(
+ flowAnalysis.storeExpressionInfo(
node,
- new SharedTypeView(inferredType),
- node.otherwise,
- new SharedTypeView(otherwiseResult.inferredType),
+ flowAnalysis.conditional_end(
+ new SharedTypeView(inferredType),
+ node.otherwise,
+ new SharedTypeView(otherwiseResult.inferredType),
+ ),
);
node.staticType = inferredType;
return new ExpressionInferenceResult(inferredType, node);
@@ -4065,12 +4070,14 @@
isVoidAllowed: false,
);
node.operand = operandResult.expression..parent = node;
- flowAnalysis.isExpression_end(
+ flowAnalysis.storeExpressionInfo(
node,
- node.operand,
- /*isNot:*/ false,
- subExpressionType: new SharedTypeView(operandResult.inferredType),
- checkedType: new SharedTypeView(node.type),
+ flowAnalysis.isExpression_end(
+ node.operand,
+ /*isNot:*/ false,
+ subExpressionType: new SharedTypeView(operandResult.inferredType),
+ checkedType: new SharedTypeView(node.type),
+ ),
);
return new ExpressionInferenceResult(
coreTypes.boolRawType(Nullability.nonNullable),
@@ -4983,10 +4990,12 @@
);
Expression right = ensureAssignableResult(boolType, rightResult).expression;
node.right = right..parent = node;
- flowAnalysis.logicalBinaryOp_end(
+ flowAnalysis.storeExpressionInfo(
node,
- node.right,
- isAnd: node.operatorEnum == LogicalExpressionOperator.AND,
+ flowAnalysis.logicalBinaryOp_end(
+ node.right,
+ isAnd: node.operatorEnum == LogicalExpressionOperator.AND,
+ ),
);
return new ExpressionInferenceResult(boolType, node);
}
@@ -10516,13 +10525,15 @@
if (isNot) {
equals = new Not(equals)..fileOffset = fileOffset;
}
- flowAnalysis.equalityOperation_end(
+ flowAnalysis.storeExpressionInfo(
equals,
- equalityInfo,
- new SharedTypeView(leftType),
- flowAnalysis.equalityOperand_end(rightResult.expression),
- new SharedTypeView(rightResult.inferredType),
- notEqual: isNot,
+ flowAnalysis.equalityOperation_end(
+ equalityInfo,
+ new SharedTypeView(leftType),
+ flowAnalysis.equalityOperand_end(rightResult.expression),
+ new SharedTypeView(rightResult.inferredType),
+ notEqual: isNot,
+ ),
);
return new ExpressionInferenceResult(
coreTypes.boolRawType(Nullability.nonNullable),
@@ -10571,13 +10582,15 @@
equals = new Not(equals)..fileOffset = fileOffset;
}
- flowAnalysis.equalityOperation_end(
+ flowAnalysis.storeExpressionInfo(
equals,
- equalityInfo,
- new SharedTypeView(leftType),
- flowAnalysis.equalityOperand_end(right),
- new SharedTypeView(rightResult.inferredType),
- notEqual: isNot,
+ flowAnalysis.equalityOperation_end(
+ equalityInfo,
+ new SharedTypeView(leftType),
+ flowAnalysis.equalityOperand_end(right),
+ new SharedTypeView(rightResult.inferredType),
+ notEqual: isNot,
+ ),
);
return new ExpressionInferenceResult(
equalsTarget.isNever
@@ -12136,7 +12149,10 @@
DartType typeContext,
) {
const NullType nullType = const NullType();
- flowAnalysis.nullLiteral(node, new SharedTypeView(nullType));
+ flowAnalysis.storeExpressionInfo(
+ node,
+ flowAnalysis.nullLiteral(new SharedTypeView(nullType)),
+ );
return new ExpressionInferenceResult(nullType, node);
}
@@ -13436,10 +13452,9 @@
ThisExpression node,
DartType typeContext,
) {
- flowAnalysis.thisOrSuper(
+ flowAnalysis.storeExpressionInfo(
node,
- new SharedTypeView(thisType!),
- isSuper: false,
+ flowAnalysis.thisOrSuper(new SharedTypeView(thisType!), isSuper: false),
);
return new ExpressionInferenceResult(thisType!, node);
}
diff --git a/pkg/front_end/lib/src/type_inference/inference_visitor_base.dart b/pkg/front_end/lib/src/type_inference/inference_visitor_base.dart
index f03ac94..47f4fdc 100644
--- a/pkg/front_end/lib/src/type_inference/inference_visitor_base.dart
+++ b/pkg/front_end/lib/src/type_inference/inference_visitor_base.dart
@@ -1967,12 +1967,14 @@
}
if (isIdenticalCall) {
- flowAnalysis.equalityOperation_end(
+ flowAnalysis.storeExpressionInfo(
actualArguments.parent as Expression,
- argumentsInfo[0].identicalInfo,
- new SharedTypeView(argumentsInfo[0].actualType),
- argumentsInfo[1].identicalInfo,
- new SharedTypeView(argumentsInfo[1].actualType),
+ flowAnalysis.equalityOperation_end(
+ argumentsInfo[0].identicalInfo,
+ new SharedTypeView(argumentsInfo[0].actualType),
+ argumentsInfo[1].identicalInfo,
+ new SharedTypeView(argumentsInfo[1].actualType),
+ ),
);
}
@@ -4275,18 +4277,21 @@
node ??= new VariableGet(variable.astVariable)..fileOffset = nameOffset;
DartType? promotedType;
DartType declaredOrInferredType = variable.lateType ?? variable.type;
+ ExpressionInfo? expressionInfo;
if (isExtensionThis(variable.astVariable)) {
- flowAnalysis.thisOrSuper(
- node,
+ expressionInfo = flowAnalysis.thisOrSuper(
new SharedTypeView(variable.type),
isSuper: true,
);
} else if (!variable.isLocalFunction) {
// Don't promote local functions.
- promotedType = flowAnalysis
- .variableRead(node, variable.astVariable)
- ?.unwrapTypeView();
+ SharedTypeView? wrappedPromotedType;
+ (wrappedPromotedType, expressionInfo) = flowAnalysis.variableRead(
+ variable.astVariable,
+ );
+ promotedType = wrappedPromotedType?.unwrapTypeView();
}
+ flowAnalysis.storeExpressionInfo(node, expressionInfo);
node.promotedType = promotedType;
DartType resultType = promotedType ?? declaredOrInferredType;
Expression resultExpression;
@@ -4419,11 +4424,14 @@
Expression rhs = rhsResult.expression;
node ??= new VariableSet(variable.astVariable, rhs)
..fileOffset = nameOffset;
- flowAnalysis.write(
+ flowAnalysis.storeExpressionInfo(
node,
- variable.astVariable,
- new SharedTypeView(rhsResult.inferredType),
- rhsResult.expression,
+ flowAnalysis.write(
+ node,
+ variable.astVariable,
+ new SharedTypeView(rhsResult.inferredType),
+ rhsResult.expression,
+ ),
);
DartType resultType = rhsResult.inferredType;
Expression resultExpression;
diff --git a/tests/language/extension_type/no_inheritance_inference_test.dart b/tests/language/extension_type/no_inheritance_inference_test.dart
new file mode 100644
index 0000000..0fce2cf
--- /dev/null
+++ b/tests/language/extension_type/no_inheritance_inference_test.dart
@@ -0,0 +1,52 @@
+// Copyright (c) 2026, 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.
+
+import 'package:expect/static_type_helper.dart';
+
+class A {
+ A get x => this;
+ set x(A _) {}
+ A method(A value) => value;
+}
+
+const Object? d = _D();
+
+class _D {
+ const _D();
+ // Can only be called if receiver has type `_D` or `dynamic`,
+ // and nothing has type `_D`.
+ void expectDynamicType() {}
+}
+
+extension type E(A _) {
+ A get x2 => _;
+ set x2(A _) {}
+ A method2(A value) => value;
+}
+
+// Extension type declarations with missing types *do not* inherit from
+// superinterface members.
+extension type SE(A _) implements A, E {
+ get x => d;
+ set x(_) {}
+ method(_) {}
+ get x2 => d;
+ set x2(_) {}
+ method2(_) {}
+}
+
+void main() {
+ var se = SE(A());
+ se.x.expectDynamicType();
+ se.x = expr(d)..expectDynamicType();
+ se.method.expectStaticType<Exactly<dynamic Function(dynamic)>>();
+ se.x2.expectDynamicType();
+ se.x2 = expr(d)..expectDynamicType();
+ se.method2.expectStaticType<Exactly<dynamic Function(dynamic)>>();
+}
+
+/// Expression with type [T].
+///
+/// Inferred to have same type as context type if no type parameter provided.
+T expr<T>([Object? value]) => value as T;
diff --git a/tools/VERSION b/tools/VERSION
index b8f3a2b..aaaf7d7 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 3
MINOR 12
PATCH 0
-PRERELEASE 59
+PRERELEASE 60
PRERELEASE_PATCH 0