mirror of
https://github.com/dart-lang/sdk
synced 2024-10-06 13:57:58 +00:00
Integrate shared type analysis of switch statements with analyzer.
This change replaces ResolverVisitor.visitSwitchStatement with a call to the new shared type analyzer, and implements the necessary callbacks to allow analysis to work end-to-end. Additionally, it changes the convention context types in resolver methods so that UnknownInferredType is now consistently used to represent the unknown type (`?`). Previously `null` was sometimes used instead. Change-Id: Idb81a7dc888dfbf460c78b93a99367c0c9263610 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/256960 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Paul Berry <paulberry@google.com> Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
parent
18a73f7591
commit
3fdc3c2588
|
@ -160,6 +160,7 @@ class LibraryAnalyzer {
|
|||
var canResolveNode = resolverVisitor.prepareForResolving(nodeToResolve);
|
||||
if (canResolveNode) {
|
||||
nodeToResolve.accept(resolverVisitor);
|
||||
resolverVisitor.checkIdle();
|
||||
return AnalysisForCompletionResult(
|
||||
parsedUnit: parsedUnit,
|
||||
resolvedNodes: [nodeToResolve],
|
||||
|
|
|
@ -61,7 +61,7 @@ class AdjacentStringsImpl extends StringLiteralImpl implements AdjacentStrings {
|
|||
E? accept<E>(AstVisitor<E> visitor) => visitor.visitAdjacentStrings(this);
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitAdjacentStrings(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -483,7 +483,7 @@ class AsExpressionImpl extends ExpressionImpl implements AsExpression {
|
|||
E? accept<E>(AstVisitor<E> visitor) => visitor.visitAsExpression(this);
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitAsExpression(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -752,7 +752,7 @@ class AssignmentExpressionImpl extends ExpressionImpl
|
|||
visitor.visitAssignmentExpression(this);
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitAssignmentExpression(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -984,7 +984,7 @@ class AwaitExpressionImpl extends ExpressionImpl implements AwaitExpression {
|
|||
E? accept<E>(AstVisitor<E> visitor) => visitor.visitAwaitExpression(this);
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitAwaitExpression(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -1062,7 +1062,7 @@ class BinaryExpressionImpl extends ExpressionImpl implements BinaryExpression {
|
|||
E? accept<E>(AstVisitor<E> visitor) => visitor.visitBinaryExpression(this);
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitBinaryExpression(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -1280,7 +1280,7 @@ class BooleanLiteralImpl extends LiteralImpl implements BooleanLiteral {
|
|||
E? accept<E>(AstVisitor<E> visitor) => visitor.visitBooleanLiteral(this);
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitBooleanLiteral(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -1423,7 +1423,7 @@ class CascadeExpressionImpl extends ExpressionImpl
|
|||
E? accept<E>(AstVisitor<E> visitor) => visitor.visitCascadeExpression(this);
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitCascadeExpression(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -2572,7 +2572,7 @@ class ConditionalExpressionImpl extends ExpressionImpl
|
|||
visitor.visitConditionalExpression(this);
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitConditionalExpression(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -3135,7 +3135,7 @@ class ConstructorReferenceImpl extends CommentReferableExpressionImpl
|
|||
visitor.visitConstructorReference(this);
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitConstructorReference(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -3666,7 +3666,7 @@ class DoubleLiteralImpl extends LiteralImpl implements DoubleLiteral {
|
|||
E? accept<E>(AstVisitor<E> visitor) => visitor.visitDoubleLiteral(this);
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitDoubleLiteral(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -4236,7 +4236,7 @@ abstract class ExpressionImpl extends AstNodeImpl
|
|||
/// Note: most code shouldn't call this method directly, but should instead
|
||||
/// call [ResolverVisitor.analyzeExpression], which has some special logic for
|
||||
/// handling dynamic contexts.
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType);
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType);
|
||||
}
|
||||
|
||||
/// An expression used as a statement.
|
||||
|
@ -4561,7 +4561,7 @@ class ExtensionOverrideImpl extends ExpressionImpl
|
|||
}
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitExtensionOverride(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -5091,6 +5091,7 @@ class ForElementImpl extends CollectionElementImpl implements ForElement {
|
|||
void resolveElement(
|
||||
ResolverVisitor resolver, CollectionLiteralContext? context) {
|
||||
resolver.visitForElement(this, context: context);
|
||||
resolver.pushRewrite(null);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -5814,7 +5815,7 @@ class FunctionExpressionImpl extends ExpressionImpl
|
|||
E? accept<E>(AstVisitor<E> visitor) => visitor.visitFunctionExpression(this);
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitFunctionExpression(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -5883,7 +5884,7 @@ class FunctionExpressionInvocationImpl extends InvocationExpressionImpl
|
|||
visitor.visitFunctionExpressionInvocation(this);
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitFunctionExpressionInvocation(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -5952,7 +5953,7 @@ class FunctionReferenceImpl extends CommentReferableExpressionImpl
|
|||
E? accept<E>(AstVisitor<E> visitor) => visitor.visitFunctionReference(this);
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitFunctionReference(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -6554,6 +6555,7 @@ class IfElementImpl extends CollectionElementImpl implements IfElement {
|
|||
void resolveElement(
|
||||
ResolverVisitor resolver, CollectionLiteralContext? context) {
|
||||
resolver.visitIfElement(this, context: context);
|
||||
resolver.pushRewrite(null);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -6775,7 +6777,7 @@ class ImplicitCallReferenceImpl extends ExpressionImpl
|
|||
}
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitImplicitCallReference(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -7098,7 +7100,7 @@ class IndexExpressionImpl extends ExpressionImpl
|
|||
}
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitIndexExpression(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -7212,7 +7214,7 @@ class InstanceCreationExpressionImpl extends ExpressionImpl
|
|||
visitor.visitInstanceCreationExpression(this);
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitInstanceCreationExpression(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -7277,7 +7279,7 @@ class IntegerLiteralImpl extends LiteralImpl implements IntegerLiteral {
|
|||
E? accept<E>(AstVisitor<E> visitor) => visitor.visitIntegerLiteral(this);
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitIntegerLiteral(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -7560,7 +7562,7 @@ class IsExpressionImpl extends ExpressionImpl implements IsExpression {
|
|||
E? accept<E>(AstVisitor<E> visitor) => visitor.visitIsExpression(this);
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitIsExpression(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -7831,7 +7833,7 @@ class LibraryIdentifierImpl extends IdentifierImpl
|
|||
E? accept<E>(AstVisitor<E> visitor) => visitor.visitLibraryIdentifier(this);
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitLibraryIdentifier(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -7901,7 +7903,7 @@ class ListLiteralImpl extends TypedLiteralImpl implements ListLiteral {
|
|||
E? accept<E>(AstVisitor<E> visitor) => visitor.visitListLiteral(this);
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitListLiteral(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -8052,6 +8054,7 @@ class MapLiteralEntryImpl extends CollectionElementImpl
|
|||
void resolveElement(
|
||||
ResolverVisitor resolver, CollectionLiteralContext? context) {
|
||||
resolver.visitMapLiteralEntry(this, context: context);
|
||||
resolver.pushRewrite(null);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -8472,7 +8475,7 @@ class MethodInvocationImpl extends InvocationExpressionImpl
|
|||
E? accept<E>(AstVisitor<E> visitor) => visitor.visitMethodInvocation(this);
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitMethodInvocation(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -8693,7 +8696,7 @@ class NamedExpressionImpl extends ExpressionImpl implements NamedExpression {
|
|||
E? accept<E>(AstVisitor<E> visitor) => visitor.visitNamedExpression(this);
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitNamedExpression(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -9170,7 +9173,7 @@ class NullLiteralImpl extends LiteralImpl implements NullLiteral {
|
|||
E? accept<E>(AstVisitor<E> visitor) => visitor.visitNullLiteral(this);
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitNullLiteral(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -9311,7 +9314,7 @@ class ParenthesizedExpressionImpl extends ExpressionImpl
|
|||
visitor.visitParenthesizedExpression(this);
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitParenthesizedExpression(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -9747,7 +9750,7 @@ class PostfixExpressionImpl extends ExpressionImpl
|
|||
E? accept<E>(AstVisitor<E> visitor) => visitor.visitPostfixExpression(this);
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitPostfixExpression(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -9874,7 +9877,7 @@ class PrefixedIdentifierImpl extends IdentifierImpl
|
|||
E? accept<E>(AstVisitor<E> visitor) => visitor.visitPrefixedIdentifier(this);
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitPrefixedIdentifier(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -9953,7 +9956,7 @@ class PrefixExpressionImpl extends ExpressionImpl
|
|||
E? accept<E>(AstVisitor<E> visitor) => visitor.visitPrefixExpression(this);
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitPrefixExpression(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -10072,7 +10075,7 @@ class PropertyAccessImpl extends CommentReferableExpressionImpl
|
|||
E? accept<E>(AstVisitor<E> visitor) => visitor.visitPropertyAccess(this);
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitPropertyAccess(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -10133,7 +10136,7 @@ class RecordLiteralImpl extends LiteralImpl implements RecordLiteral {
|
|||
E? accept<E>(AstVisitor<E> visitor) => visitor.visitRecordLiteral(this);
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitRecordLiteral(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -10575,7 +10578,7 @@ class RethrowExpressionImpl extends ExpressionImpl
|
|||
E? accept<E>(AstVisitor<E> visitor) => visitor.visitRethrowExpression(this);
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitRethrowExpression(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -10755,7 +10758,7 @@ class SetOrMapLiteralImpl extends TypedLiteralImpl implements SetOrMapLiteral {
|
|||
}
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitSetOrMapLiteral(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -11171,7 +11174,7 @@ class SimpleIdentifierImpl extends IdentifierImpl implements SimpleIdentifier {
|
|||
}
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitSimpleIdentifier(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -11250,7 +11253,7 @@ class SimpleStringLiteralImpl extends SingleStringLiteralImpl
|
|||
E? accept<E>(AstVisitor<E> visitor) => visitor.visitSimpleStringLiteral(this);
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitSimpleStringLiteral(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -11315,6 +11318,7 @@ class SpreadElementImpl extends AstNodeImpl
|
|||
void resolveElement(
|
||||
ResolverVisitor resolver, CollectionLiteralContext? context) {
|
||||
resolver.visitSpreadElement(this, context: context);
|
||||
resolver.pushRewrite(null);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -11427,7 +11431,7 @@ class StringInterpolationImpl extends SingleStringLiteralImpl
|
|||
E? accept<E>(AstVisitor<E> visitor) => visitor.visitStringInterpolation(this);
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitStringInterpolation(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -11661,7 +11665,7 @@ class SuperExpressionImpl extends ExpressionImpl implements SuperExpression {
|
|||
E? accept<E>(AstVisitor<E> visitor) => visitor.visitSuperExpression(this);
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitSuperExpression(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -12273,7 +12277,7 @@ class SymbolLiteralImpl extends LiteralImpl implements SymbolLiteral {
|
|||
E? accept<E>(AstVisitor<E> visitor) => visitor.visitSymbolLiteral(this);
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitSymbolLiteral(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -12312,7 +12316,7 @@ class ThisExpressionImpl extends ExpressionImpl implements ThisExpression {
|
|||
E? accept<E>(AstVisitor<E> visitor) => visitor.visitThisExpression(this);
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitThisExpression(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -12366,7 +12370,7 @@ class ThrowExpressionImpl extends ExpressionImpl implements ThrowExpression {
|
|||
E? accept<E>(AstVisitor<E> visitor) => visitor.visitThrowExpression(this);
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitThrowExpression(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
@ -12706,7 +12710,7 @@ class TypeLiteralImpl extends CommentReferableExpressionImpl
|
|||
E? accept<E>(AstVisitor<E> visitor) => visitor.visitTypeLiteral(this);
|
||||
|
||||
@override
|
||||
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
|
||||
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
|
||||
resolver.visitTypeLiteral(this, contextType: contextType);
|
||||
}
|
||||
|
||||
|
|
|
@ -1876,7 +1876,7 @@ class NodeReplacer extends ThrowingAstVisitor<bool> {
|
|||
|
||||
/// Initialize a newly created node locator to replace the [_oldNode] with the
|
||||
/// [_newNode].
|
||||
NodeReplacer(this._oldNode, this._newNode);
|
||||
NodeReplacer._(this._oldNode, this._newNode);
|
||||
|
||||
@override
|
||||
bool visitAdjacentStrings(covariant AdjacentStringsImpl node) {
|
||||
|
@ -3393,7 +3393,7 @@ class NodeReplacer extends ThrowingAstVisitor<bool> {
|
|||
if (parent == null) {
|
||||
throw ArgumentError("The old node is not a child of another node");
|
||||
}
|
||||
NodeReplacer replacer = NodeReplacer(oldNode, newNode);
|
||||
NodeReplacer replacer = NodeReplacer._(oldNode, newNode);
|
||||
return parent.accept(replacer)!;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -664,7 +664,6 @@ class ConstantVerifier extends RecursiveAstVisitor<void> {
|
|||
}
|
||||
|
||||
void _validateSwitchStatement_nullSafety(SwitchStatement node) {
|
||||
var switchType = node.expression.typeOrThrow;
|
||||
for (var switchMember in node.members) {
|
||||
if (switchMember is SwitchCase) {
|
||||
Expression expression = switchMember.expression;
|
||||
|
@ -692,15 +691,6 @@ class ConstantVerifier extends RecursiveAstVisitor<void> {
|
|||
[expressionType],
|
||||
);
|
||||
}
|
||||
|
||||
if (!_typeSystem.isSubtypeOf(expressionType, switchType)) {
|
||||
_errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode
|
||||
.CASE_EXPRESSION_TYPE_IS_NOT_SWITCH_EXPRESSION_SUBTYPE,
|
||||
expression,
|
||||
[expressionType, switchType],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,7 +94,7 @@ class AssignmentExpressionResolver {
|
|||
}
|
||||
|
||||
_resolver.analyzeExpression(right, rhsContext);
|
||||
right = node.rightHandSide;
|
||||
right = _resolver.popRewrite()!;
|
||||
var whyNotPromoted = flow?.whyNotPromoted(right);
|
||||
|
||||
_resolveTypes(node,
|
||||
|
|
|
@ -150,7 +150,7 @@ class BinaryExpressionResolver {
|
|||
}
|
||||
|
||||
_resolver.analyzeExpression(left, leftContextType);
|
||||
left = node.leftOperand;
|
||||
left = _resolver.popRewrite()!;
|
||||
var leftType = left.typeOrThrow;
|
||||
|
||||
var rightContextType = contextType;
|
||||
|
@ -160,7 +160,7 @@ class BinaryExpressionResolver {
|
|||
|
||||
flow?.ifNullExpression_rightBegin(left, leftType);
|
||||
_resolver.analyzeExpression(right, rightContextType);
|
||||
right = node.rightOperand;
|
||||
right = _resolver.popRewrite()!;
|
||||
flow?.ifNullExpression_end();
|
||||
|
||||
var rightType = right.typeOrThrow;
|
||||
|
@ -183,14 +183,14 @@ class BinaryExpressionResolver {
|
|||
|
||||
flow?.logicalBinaryOp_begin();
|
||||
_resolver.analyzeExpression(left, _typeProvider.boolType);
|
||||
left = node.leftOperand;
|
||||
left = _resolver.popRewrite()!;
|
||||
var leftWhyNotPromoted = _resolver.flowAnalysis.flow?.whyNotPromoted(left);
|
||||
|
||||
flow?.logicalBinaryOp_rightBegin(left, node, isAnd: true);
|
||||
_resolver.checkUnreachableNode(right);
|
||||
|
||||
_resolver.analyzeExpression(right, _typeProvider.boolType);
|
||||
right = node.rightOperand;
|
||||
right = _resolver.popRewrite()!;
|
||||
var rightWhyNotPromoted =
|
||||
_resolver.flowAnalysis.flow?.whyNotPromoted(right);
|
||||
|
||||
|
@ -212,14 +212,14 @@ class BinaryExpressionResolver {
|
|||
|
||||
flow?.logicalBinaryOp_begin();
|
||||
_resolver.analyzeExpression(left, _typeProvider.boolType);
|
||||
left = node.leftOperand;
|
||||
left = _resolver.popRewrite()!;
|
||||
var leftWhyNotPromoted = _resolver.flowAnalysis.flow?.whyNotPromoted(left);
|
||||
|
||||
flow?.logicalBinaryOp_rightBegin(left, node, isAnd: false);
|
||||
_resolver.checkUnreachableNode(right);
|
||||
|
||||
_resolver.analyzeExpression(right, _typeProvider.boolType);
|
||||
right = node.rightOperand;
|
||||
right = _resolver.popRewrite()!;
|
||||
var rightWhyNotPromoted =
|
||||
_resolver.flowAnalysis.flow?.whyNotPromoted(right);
|
||||
|
||||
|
@ -263,7 +263,7 @@ class BinaryExpressionResolver {
|
|||
}
|
||||
|
||||
_resolver.analyzeExpression(right, rightContextType);
|
||||
right = node.rightOperand;
|
||||
right = _resolver.popRewrite()!;
|
||||
var whyNotPromoted = _resolver.flowAnalysis.flow?.whyNotPromoted(right);
|
||||
|
||||
_resolveUserDefinableType(node, contextType: contextType);
|
||||
|
|
|
@ -61,7 +61,7 @@ class FlowAnalysisDataForTesting {
|
|||
/// be extracted.
|
||||
class FlowAnalysisHelper {
|
||||
/// The reused instance for creating new [FlowAnalysis] instances.
|
||||
final TypeSystemOperations _typeOperations;
|
||||
final TypeSystemOperations typeOperations;
|
||||
|
||||
/// Precomputed sets of potentially assigned variables.
|
||||
AssignedVariables<AstNode, PromotableElement>? assignedVariables;
|
||||
|
@ -90,7 +90,7 @@ class FlowAnalysisHelper {
|
|||
respectImplicitlyTypedVarInitializers:
|
||||
featureSet.isEnabled(Feature.constructor_tearoffs));
|
||||
|
||||
FlowAnalysisHelper._(this._typeOperations, this.dataForTesting,
|
||||
FlowAnalysisHelper._(this.typeOperations, this.dataForTesting,
|
||||
{required this.isNonNullableByDefault,
|
||||
required this.respectImplicitlyTypedVarInitializers});
|
||||
|
||||
|
@ -246,11 +246,11 @@ class FlowAnalysisHelper {
|
|||
}
|
||||
flow = isNonNullableByDefault
|
||||
? FlowAnalysis<AstNode, Statement, Expression, PromotableElement,
|
||||
DartType>(_typeOperations, assignedVariables!,
|
||||
DartType>(typeOperations, assignedVariables!,
|
||||
respectImplicitlyTypedVarInitializers:
|
||||
respectImplicitlyTypedVarInitializers)
|
||||
: FlowAnalysis<AstNode, Statement, Expression, PromotableElement,
|
||||
DartType>.legacy(_typeOperations, assignedVariables!);
|
||||
DartType>.legacy(typeOperations, assignedVariables!);
|
||||
}
|
||||
|
||||
void topLevelDeclaration_exit() {
|
||||
|
@ -378,7 +378,7 @@ class FlowAnalysisHelperForMigration extends FlowAnalysisHelper {
|
|||
}
|
||||
|
||||
class TypeSystemOperations
|
||||
with TypeOperations<DartType>
|
||||
with TypeOperations<DartType>, TypeOperations2<DartType>
|
||||
implements Operations<PromotableElement, DartType> {
|
||||
final TypeSystemImpl typeSystem;
|
||||
|
||||
|
@ -400,6 +400,19 @@ class TypeSystemOperations
|
|||
return typeSystem.factor(from, what);
|
||||
}
|
||||
|
||||
@override
|
||||
DartType glb(DartType type1, DartType type2) {
|
||||
throw UnimplementedError('TODO(paulberry)');
|
||||
}
|
||||
|
||||
@override
|
||||
bool isAssignableTo(DartType fromType, DartType toType) {
|
||||
return typeSystem.isAssignableTo(fromType, toType);
|
||||
}
|
||||
|
||||
@override
|
||||
bool isDynamic(DartType type) => type.isDynamic;
|
||||
|
||||
@override
|
||||
bool isNever(DartType type) {
|
||||
return typeSystem.isBottom(type);
|
||||
|
@ -418,6 +431,21 @@ class TypeSystemOperations
|
|||
@override
|
||||
bool isTypeParameterType(DartType type) => type is TypeParameterType;
|
||||
|
||||
@override
|
||||
DartType lub(DartType type1, DartType type2) {
|
||||
throw UnimplementedError('TODO(paulberry)');
|
||||
}
|
||||
|
||||
@override
|
||||
DartType makeNullable(DartType type) {
|
||||
throw UnimplementedError('TODO(paulberry)');
|
||||
}
|
||||
|
||||
@override
|
||||
DartType? matchListType(DartType type) {
|
||||
throw UnimplementedError('TODO(paulberry)');
|
||||
}
|
||||
|
||||
@override
|
||||
DartType promoteToNonNull(DartType type) {
|
||||
return typeSystem.promoteToNonNull(type);
|
||||
|
|
|
@ -29,6 +29,7 @@ class ForResolver {
|
|||
var forLoopParts = node.forLoopParts;
|
||||
void visitBody() {
|
||||
node.body.resolveElement(_resolver, context);
|
||||
_resolver.popRewrite();
|
||||
}
|
||||
|
||||
if (forLoopParts is ForPartsImpl) {
|
||||
|
@ -119,7 +120,7 @@ class ForResolver {
|
|||
}
|
||||
|
||||
_resolver.analyzeExpression(iterable, targetType);
|
||||
iterable = forEachParts.iterable;
|
||||
iterable = _resolver.popRewrite()!;
|
||||
|
||||
_resolver.nullableDereferenceVerifier.expression(
|
||||
CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_AS_ITERATOR,
|
||||
|
@ -165,7 +166,7 @@ class ForResolver {
|
|||
var condition = forParts.condition;
|
||||
if (condition != null) {
|
||||
_resolver.analyzeExpression(condition, _resolver.typeProvider.boolType);
|
||||
condition = forParts.condition!;
|
||||
condition = _resolver.popRewrite()!;
|
||||
var whyNotPromoted =
|
||||
_resolver.flowAnalysis.flow?.whyNotPromoted(condition);
|
||||
_resolver.boolExpressionVerifier
|
||||
|
|
|
@ -11,7 +11,6 @@ import 'package:analyzer/error/listener.dart';
|
|||
import 'package:analyzer/src/dart/ast/ast.dart';
|
||||
import 'package:analyzer/src/dart/ast/ast_factory.dart';
|
||||
import 'package:analyzer/src/dart/ast/extensions.dart';
|
||||
import 'package:analyzer/src/dart/ast/utilities.dart';
|
||||
import 'package:analyzer/src/dart/element/type.dart';
|
||||
import 'package:analyzer/src/dart/resolver/extension_member_resolver.dart';
|
||||
import 'package:analyzer/src/error/codes.dart';
|
||||
|
@ -291,7 +290,7 @@ class FunctionReferenceResolver {
|
|||
typeArguments: node.typeArguments,
|
||||
typeArgumentTypes: typeArgumentTypes,
|
||||
);
|
||||
NodeReplacer.replace(node, callReference);
|
||||
_resolver.replaceExpression(node, callReference);
|
||||
var instantiatedType = callMethodType.instantiate(typeArgumentTypes);
|
||||
callReference.staticType = instantiatedType;
|
||||
}
|
||||
|
@ -826,7 +825,7 @@ class FunctionReferenceResolver {
|
|||
typeName.name.staticType = instantiatedType;
|
||||
var typeLiteral = astFactory.typeLiteral(typeName: typeName);
|
||||
typeLiteral.staticType = _typeType;
|
||||
NodeReplacer.replace(node, typeLiteral);
|
||||
_resolver.replaceExpression(node, typeLiteral);
|
||||
}
|
||||
|
||||
/// Resolves [name] as a property on [receiver].
|
||||
|
|
|
@ -461,8 +461,7 @@ class InvocationInferrer<Node extends AstNodeImpl> {
|
|||
}
|
||||
var argument = arguments[deferredArgument.index];
|
||||
resolver.analyzeExpression(argument, parameterContextType);
|
||||
// In case of rewrites, we need to grab the argument again.
|
||||
argument = arguments[deferredArgument.index];
|
||||
argument = resolver.popRewrite()!;
|
||||
if (flow != null) {
|
||||
identicalInfo?[deferredArgument.index] =
|
||||
flow.equalityOperand_end(argument, argument.typeOrThrow);
|
||||
|
@ -521,8 +520,7 @@ class InvocationInferrer<Node extends AstNodeImpl> {
|
|||
parameterContextType = _computeContextForArgument(parameterType);
|
||||
}
|
||||
resolver.analyzeExpression(argument, parameterContextType);
|
||||
// In case of rewrites, we need to grab the argument again.
|
||||
argument = arguments[i];
|
||||
argument = resolver.popRewrite()!;
|
||||
if (flow != null) {
|
||||
identicalInfo
|
||||
?.add(flow.equalityOperand_end(argument, argument.typeOrThrow));
|
||||
|
|
|
@ -9,7 +9,6 @@ import 'package:analyzer/error/listener.dart';
|
|||
import 'package:analyzer/src/dart/ast/ast.dart';
|
||||
import 'package:analyzer/src/dart/ast/ast_factory.dart';
|
||||
import 'package:analyzer/src/dart/ast/extensions.dart';
|
||||
import 'package:analyzer/src/dart/ast/utilities.dart';
|
||||
import 'package:analyzer/src/dart/element/element.dart';
|
||||
import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
|
||||
import 'package:analyzer/src/dart/element/type.dart';
|
||||
|
@ -906,7 +905,7 @@ class MethodInvocationResolver with ScopeHelpers {
|
|||
typeArguments: node.typeArguments,
|
||||
argumentList: node.argumentList,
|
||||
);
|
||||
NodeReplacer.replace(node, invocation);
|
||||
_resolver.replaceExpression(node, invocation);
|
||||
node.setProperty(_rewriteResultKey, invocation);
|
||||
_resolver.flowAnalysis.transferTestData(node, invocation);
|
||||
}
|
||||
|
|
|
@ -208,7 +208,7 @@ class PostfixExpressionResolver {
|
|||
}
|
||||
|
||||
_resolver.analyzeExpression(operand, contextType);
|
||||
operand = node.operand;
|
||||
operand = _resolver.popRewrite()!;
|
||||
|
||||
var operandType = operand.typeOrThrow;
|
||||
|
||||
|
|
|
@ -74,6 +74,7 @@ class PrefixExpressionResolver {
|
|||
innerContextType = contextType;
|
||||
}
|
||||
_resolver.analyzeExpression(operand, innerContextType);
|
||||
_resolver.popRewrite();
|
||||
}
|
||||
|
||||
_resolve1(node);
|
||||
|
@ -226,7 +227,7 @@ class PrefixExpressionResolver {
|
|||
var operand = node.operand;
|
||||
|
||||
_resolver.analyzeExpression(operand, _typeProvider.boolType);
|
||||
operand = node.operand;
|
||||
operand = _resolver.popRewrite()!;
|
||||
var whyNotPromoted = _resolver.flowAnalysis.flow?.whyNotPromoted(operand);
|
||||
|
||||
_resolver.boolExpressionVerifier.checkForNonBoolNegationExpression(operand,
|
||||
|
|
|
@ -6,7 +6,6 @@ import 'package:analyzer/dart/ast/ast.dart';
|
|||
import 'package:analyzer/dart/element/element.dart';
|
||||
import 'package:analyzer/dart/element/type.dart';
|
||||
import 'package:analyzer/src/dart/ast/ast.dart';
|
||||
import 'package:analyzer/src/dart/ast/utilities.dart';
|
||||
import 'package:analyzer/src/dart/element/element.dart';
|
||||
import 'package:analyzer/src/dart/element/type.dart';
|
||||
import 'package:analyzer/src/dart/element/type_provider.dart';
|
||||
|
@ -43,7 +42,7 @@ class PrefixedIdentifierResolver {
|
|||
node.period,
|
||||
node.identifier,
|
||||
);
|
||||
NodeReplacer.replace(node, propertyAccess);
|
||||
_resolver.replaceExpression(node, propertyAccess);
|
||||
return propertyAccess;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -116,6 +116,7 @@ class RecordLiteralResolver {
|
|||
|
||||
void _resolveField(Expression field, DartType? contextType) {
|
||||
_resolver.analyzeExpression(field, contextType);
|
||||
_resolver.popRewrite();
|
||||
}
|
||||
|
||||
void _resolveFields(RecordLiteralImpl node, DartType? contextType) {
|
||||
|
|
105
pkg/analyzer/lib/src/dart/resolver/shared_type_analyzer.dart
Normal file
105
pkg/analyzer/lib/src/dart/resolver/shared_type_analyzer.dart
Normal file
|
@ -0,0 +1,105 @@
|
|||
// Copyright (c) 2022, 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:_fe_analyzer_shared/src/type_inference/type_analyzer.dart';
|
||||
import 'package:analyzer/dart/ast/ast.dart';
|
||||
import 'package:analyzer/dart/element/element.dart';
|
||||
import 'package:analyzer/dart/element/type.dart';
|
||||
import 'package:analyzer/error/listener.dart';
|
||||
import 'package:analyzer/src/error/codes.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
|
||||
/// Implementation of [TypeAnalyzerErrors] that reports errors using the
|
||||
/// analyzer's [ErrorReporter] class.
|
||||
class SharedTypeAnalyzerErrors
|
||||
implements
|
||||
TypeAnalyzerErrors<AstNode, Statement, Expression, PromotableElement,
|
||||
DartType> {
|
||||
final ErrorReporter _errorReporter;
|
||||
|
||||
SharedTypeAnalyzerErrors(this._errorReporter);
|
||||
|
||||
@override
|
||||
void assertInErrorRecovery() {
|
||||
throw UnimplementedError('TODO(paulberry)');
|
||||
}
|
||||
|
||||
@override
|
||||
void caseExpressionTypeMismatch(
|
||||
{required Expression scrutinee,
|
||||
required Expression caseExpression,
|
||||
required scrutineeType,
|
||||
required caseExpressionType,
|
||||
required bool nullSafetyEnabled}) {
|
||||
if (nullSafetyEnabled) {
|
||||
_errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode
|
||||
.CASE_EXPRESSION_TYPE_IS_NOT_SWITCH_EXPRESSION_SUBTYPE,
|
||||
caseExpression,
|
||||
[caseExpressionType, scrutineeType]);
|
||||
} else {
|
||||
// We only report the error if it occurs on the first case; otherwise
|
||||
// separate logic will report that different cases have different types.
|
||||
var switchStatement = scrutinee.parent as SwitchStatement;
|
||||
if (identical(
|
||||
switchStatement.members
|
||||
.whereType<SwitchCase>()
|
||||
.firstOrNull
|
||||
?.expression,
|
||||
caseExpression)) {
|
||||
_errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.SWITCH_EXPRESSION_NOT_ASSIGNABLE,
|
||||
scrutinee,
|
||||
[scrutineeType, caseExpressionType]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void inconsistentMatchVar(
|
||||
{required AstNode pattern,
|
||||
required DartType type,
|
||||
required AstNode previousPattern,
|
||||
required DartType previousType}) {
|
||||
throw UnimplementedError('TODO(paulberry)');
|
||||
}
|
||||
|
||||
@override
|
||||
void inconsistentMatchVarExplicitness(
|
||||
{required AstNode pattern, required AstNode previousPattern}) {
|
||||
throw UnimplementedError('TODO(paulberry)');
|
||||
}
|
||||
|
||||
@override
|
||||
void nonBooleanCondition(Expression node) {
|
||||
throw UnimplementedError('TODO(paulberry)');
|
||||
}
|
||||
|
||||
@override
|
||||
void patternDoesNotAllowLate(AstNode pattern) {
|
||||
throw UnimplementedError('TODO(paulberry)');
|
||||
}
|
||||
|
||||
@override
|
||||
void patternTypeMismatchInIrrefutableContext(
|
||||
{required AstNode pattern,
|
||||
required AstNode context,
|
||||
required DartType matchedType,
|
||||
required DartType requiredType}) {
|
||||
throw UnimplementedError('TODO(paulberry)');
|
||||
}
|
||||
|
||||
@override
|
||||
void refutablePatternInIrrefutableContext(AstNode pattern, AstNode context) {
|
||||
throw UnimplementedError('TODO(paulberry)');
|
||||
}
|
||||
|
||||
@override
|
||||
void switchCaseCompletesNormally(
|
||||
covariant SwitchStatement node, int caseIndex, int numHeads) {
|
||||
_errorReporter.reportErrorForToken(
|
||||
CompileTimeErrorCode.SWITCH_CASE_COMPLETES_NORMALLY,
|
||||
node.members[caseIndex + numHeads - 1].keyword);
|
||||
}
|
||||
}
|
|
@ -14,6 +14,7 @@ import 'package:analyzer/src/dart/element/element.dart';
|
|||
import 'package:analyzer/src/dart/element/generic_inferrer.dart';
|
||||
import 'package:analyzer/src/dart/element/type.dart';
|
||||
import 'package:analyzer/src/dart/element/type_provider.dart';
|
||||
import 'package:analyzer/src/dart/element/type_schema.dart';
|
||||
import 'package:analyzer/src/dart/element/type_system.dart';
|
||||
import 'package:analyzer/src/error/codes.dart';
|
||||
import 'package:analyzer/src/generated/engine.dart';
|
||||
|
@ -92,7 +93,7 @@ class TypedLiteralResolver {
|
|||
}
|
||||
|
||||
void resolveListLiteral(ListLiteralImpl node,
|
||||
{required DartType? contextType}) {
|
||||
{required DartType contextType}) {
|
||||
InterfaceType? listType;
|
||||
GenericInferrer? inferrer;
|
||||
|
||||
|
@ -106,7 +107,7 @@ class TypedLiteralResolver {
|
|||
}
|
||||
} else {
|
||||
inferrer = _inferListTypeDownwards(node, contextType: contextType);
|
||||
if (contextType != null) {
|
||||
if (contextType is! UnknownInferredType) {
|
||||
var typeArguments = inferrer.partialInfer();
|
||||
listType = _typeProvider.listElement.instantiate(
|
||||
typeArguments: typeArguments, nullabilitySuffix: _noneOrStarSuffix);
|
||||
|
@ -126,7 +127,7 @@ class TypedLiteralResolver {
|
|||
}
|
||||
|
||||
void resolveSetOrMapLiteral(SetOrMapLiteral node,
|
||||
{required DartType? contextType}) {
|
||||
{required DartType contextType}) {
|
||||
(node as SetOrMapLiteralImpl).becomeUnresolved();
|
||||
var typeArguments = node.typeArguments?.arguments;
|
||||
|
||||
|
@ -472,7 +473,7 @@ class TypedLiteralResolver {
|
|||
|
||||
InterfaceType? _inferListTypeUpwards(
|
||||
GenericInferrer inferrer, ListLiteral node,
|
||||
{required DartType? contextType}) {
|
||||
{required DartType contextType}) {
|
||||
var element = _typeProvider.listElement;
|
||||
var typeParameters = element.typeParameters;
|
||||
var genericElementType = typeParameters[0].instantiate(
|
||||
|
@ -486,7 +487,9 @@ class TypedLiteralResolver {
|
|||
'element', genericElementType, ParameterKind.POSITIONAL);
|
||||
List<ParameterElement> parameters =
|
||||
List.filled(elementTypes.length, syntheticParameter);
|
||||
if (_strictInference && parameters.isEmpty && contextType == null) {
|
||||
if (_strictInference &&
|
||||
parameters.isEmpty &&
|
||||
contextType is UnknownInferredType) {
|
||||
// We cannot infer the type of a collection literal with no elements, and
|
||||
// no context type. If there are any elements, inference has not failed,
|
||||
// as the types of those elements are considered resolved.
|
||||
|
@ -606,11 +609,12 @@ class TypedLiteralResolver {
|
|||
List<CollectionElement> elements, CollectionLiteralContext? context) {
|
||||
for (var element in elements) {
|
||||
(element as CollectionElementImpl).resolveElement(_resolver, context);
|
||||
_resolver.popRewrite();
|
||||
}
|
||||
}
|
||||
|
||||
void _resolveListLiteral2(GenericInferrer? inferrer, ListLiteralImpl node,
|
||||
{required DartType? contextType}) {
|
||||
{required DartType contextType}) {
|
||||
var typeArguments = node.typeArguments?.arguments;
|
||||
|
||||
// If we have explicit arguments, use them.
|
||||
|
@ -645,7 +649,7 @@ class TypedLiteralResolver {
|
|||
|
||||
void _resolveSetOrMapLiteral2(GenericInferrer? inferrer,
|
||||
_LiteralResolution literalResolution, SetOrMapLiteralImpl node,
|
||||
{required DartType? contextType}) {
|
||||
{required DartType contextType}) {
|
||||
var typeArguments = node.typeArguments?.arguments;
|
||||
|
||||
// If we have type arguments, use them.
|
||||
|
@ -688,7 +692,7 @@ class TypedLiteralResolver {
|
|||
}
|
||||
if (_strictInference &&
|
||||
_getSetOrMapElements(node).isEmpty &&
|
||||
contextType == null) {
|
||||
contextType is UnknownInferredType) {
|
||||
// We cannot infer the type of a collection literal with no elements, and
|
||||
// no context type. If there are any elements, inference has not failed,
|
||||
// as the types of those elements are considered resolved.
|
||||
|
|
|
@ -50,7 +50,7 @@ class VariableDeclarationResolver {
|
|||
}
|
||||
|
||||
_resolver.analyzeExpression(initializer, element.type);
|
||||
initializer = node.initializer!;
|
||||
initializer = _resolver.popRewrite()!;
|
||||
var whyNotPromoted =
|
||||
_resolver.flowAnalysis.flow?.whyNotPromoted(initializer);
|
||||
|
||||
|
|
|
@ -157,6 +157,7 @@ class YieldStatementResolver {
|
|||
) {
|
||||
_resolver.analyzeExpression(
|
||||
node.expression, _computeContextType(bodyContext, node));
|
||||
_resolver.popRewrite();
|
||||
|
||||
if (node.star != null) {
|
||||
_resolver.nullableDereferenceVerifier.expression(
|
||||
|
|
|
@ -48,7 +48,6 @@ import 'package:analyzer/src/generated/this_access_tracker.dart';
|
|||
import 'package:analyzer/src/summary2/macro_application_error.dart';
|
||||
import 'package:analyzer/src/utilities/extensions/object.dart';
|
||||
import 'package:analyzer/src/utilities/extensions/string.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
|
||||
class EnclosingExecutableContext {
|
||||
final ExecutableElement? element;
|
||||
|
@ -4243,30 +4242,7 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
|
|||
return;
|
||||
}
|
||||
|
||||
Expression expression = statement.expression;
|
||||
if (checkForUseOfVoidResult(expression)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// prepare 'switch' expression type
|
||||
DartType expressionType = expression.typeOrThrow;
|
||||
|
||||
// compare with type of the first non-default 'case'
|
||||
var switchCase = statement.members.whereType<SwitchCase>().firstOrNull;
|
||||
if (switchCase == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Expression caseExpression = switchCase.expression;
|
||||
DartType caseType = caseExpression.typeOrThrow;
|
||||
|
||||
// check types
|
||||
if (!typeSystem.isAssignableTo(expressionType, caseType)) {
|
||||
errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.SWITCH_EXPRESSION_NOT_ASSIGNABLE,
|
||||
expression,
|
||||
[expressionType, caseType]);
|
||||
}
|
||||
checkForUseOfVoidResult(statement.expression);
|
||||
}
|
||||
|
||||
void _checkForThrowOfInvalidType(ThrowExpression node) {
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
import 'dart:collection';
|
||||
|
||||
import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis.dart';
|
||||
import 'package:_fe_analyzer_shared/src/type_inference/type_analysis_result.dart';
|
||||
import 'package:_fe_analyzer_shared/src/type_inference/type_analyzer.dart';
|
||||
import 'package:_fe_analyzer_shared/src/type_inference/type_operations.dart';
|
||||
import 'package:analyzer/dart/analysis/features.dart';
|
||||
import 'package:analyzer/dart/ast/ast.dart';
|
||||
import 'package:analyzer/dart/ast/syntactic_entity.dart';
|
||||
|
@ -29,6 +32,7 @@ import 'package:analyzer/src/dart/element/nullability_eliminator.dart';
|
|||
import 'package:analyzer/src/dart/element/scope.dart';
|
||||
import 'package:analyzer/src/dart/element/type.dart';
|
||||
import 'package:analyzer/src/dart/element/type_provider.dart';
|
||||
import 'package:analyzer/src/dart/element/type_schema.dart';
|
||||
import 'package:analyzer/src/dart/element/type_system.dart';
|
||||
import 'package:analyzer/src/dart/resolver/annotation_resolver.dart';
|
||||
import 'package:analyzer/src/dart/resolver/assignment_expression_resolver.dart';
|
||||
|
@ -52,6 +56,7 @@ import 'package:analyzer/src/dart/resolver/prefixed_identifier_resolver.dart';
|
|||
import 'package:analyzer/src/dart/resolver/property_element_resolver.dart';
|
||||
import 'package:analyzer/src/dart/resolver/record_literal_resolver.dart';
|
||||
import 'package:analyzer/src/dart/resolver/scope.dart';
|
||||
import 'package:analyzer/src/dart/resolver/shared_type_analyzer.dart';
|
||||
import 'package:analyzer/src/dart/resolver/simple_identifier_resolver.dart';
|
||||
import 'package:analyzer/src/dart/resolver/this_lookup.dart';
|
||||
import 'package:analyzer/src/dart/resolver/type_property_resolver.dart';
|
||||
|
@ -129,10 +134,31 @@ class InferenceContext {
|
|||
/// Instances of the class `ResolverVisitor` are used to resolve the nodes
|
||||
/// within a single compilation unit.
|
||||
class ResolverVisitor extends ThrowingAstVisitor<void>
|
||||
with ErrorDetectionHelpers {
|
||||
with
|
||||
ErrorDetectionHelpers,
|
||||
TypeAnalyzer<AstNode, Statement, Expression, PromotableElement,
|
||||
DartType> {
|
||||
/// Debug-only: if `true`, manipulations of [_rewriteStack] performed by
|
||||
/// [popRewrite], [pushRewrite], and [replaceExpression] will be printed.
|
||||
static const bool _debugRewriteStack = false;
|
||||
|
||||
/// The element for the library containing the compilation unit being visited.
|
||||
final LibraryElementImpl definingLibrary;
|
||||
|
||||
/// If the resolver visitor is visiting a switch statement, the tracker that
|
||||
/// determines whether the switch is exhaustive.
|
||||
///
|
||||
/// TODO(paulberry): move exhaustiveness computation into the shared
|
||||
/// [TypeAnalyzer].
|
||||
SwitchExhaustiveness? switchExhaustiveness;
|
||||
|
||||
@override
|
||||
final TypeAnalyzerOptions options;
|
||||
|
||||
@override
|
||||
late final SharedTypeAnalyzerErrors errors =
|
||||
SharedTypeAnalyzerErrors(errorReporter);
|
||||
|
||||
/// The source representing the compilation unit being visited.
|
||||
final Source source;
|
||||
|
||||
|
@ -226,10 +252,6 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
/// be built and the comment resolved.
|
||||
bool resolveOnlyCommentInFunctionBody = false;
|
||||
|
||||
/// The type of the expression of the immediately enclosing [SwitchStatement],
|
||||
/// or `null` if not in a [SwitchStatement].
|
||||
DartType? _enclosingSwitchStatementExpressionType;
|
||||
|
||||
/// Stack of expressions which we have not yet finished visiting, that should
|
||||
/// terminate a null-shorting expression.
|
||||
///
|
||||
|
@ -256,6 +278,22 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
|
||||
final bool genericMetadataIsEnabled;
|
||||
|
||||
/// Stack for obtaining rewritten expressions. Prior to visiting an
|
||||
/// expression, a caller may push the expression on this stack; if
|
||||
/// [replaceExpression] is later called, it will update the top of the stack
|
||||
/// to point to the rewritten expression.
|
||||
///
|
||||
/// The stack sometimes contains `null`s. These account for situations where
|
||||
/// it's necessary to push a value onto the stack to balance a later pop, but
|
||||
/// there is no suitable expression to push.
|
||||
final List<ExpressionImpl?> _rewriteStack = [];
|
||||
|
||||
/// Debug-only expando mapping AST nodes to the nodes they were replaced with
|
||||
/// by [replaceExpression]. This is used by [dispatchExpression] as a sanity
|
||||
/// check to make sure the expression it pops off the [_rewriteStack] is
|
||||
/// actually correct.
|
||||
late final Expando<AstNode> _replacements = Expando();
|
||||
|
||||
/// Initialize a newly created visitor to resolve the nodes in an AST node.
|
||||
///
|
||||
/// The [definingLibrary] is the element for the library containing the node
|
||||
|
@ -306,7 +344,12 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
),
|
||||
_featureSet = featureSet,
|
||||
genericMetadataIsEnabled =
|
||||
definingLibrary.featureSet.isEnabled(Feature.generic_metadata) {
|
||||
definingLibrary.featureSet.isEnabled(Feature.generic_metadata),
|
||||
options = TypeAnalyzerOptions(
|
||||
nullSafetyEnabled: definingLibrary.isNonNullableByDefault,
|
||||
// TODO(paulberry): set `patternsEnabled` correctly once we have an
|
||||
// experiment flag for patterns.
|
||||
patternsEnabled: false) {
|
||||
var analysisOptions =
|
||||
definingLibrary.context.analysisOptions as AnalysisOptionsImpl;
|
||||
|
||||
|
@ -375,12 +418,28 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
FunctionReferenceResolver(this, _isNonNullableByDefault);
|
||||
}
|
||||
|
||||
@override
|
||||
DartType get boolType => throw UnimplementedError('TODO(paulberry)');
|
||||
|
||||
@override
|
||||
DartType get doubleType => throw UnimplementedError('TODO(paulberry)');
|
||||
|
||||
@override
|
||||
DartType get dynamicType => throw UnimplementedError('TODO(paulberry)');
|
||||
|
||||
/// Return the element representing the function containing the current node,
|
||||
/// or `null` if the current node is not contained in a function.
|
||||
///
|
||||
/// @return the element representing the function containing the current node
|
||||
ExecutableElement? get enclosingFunction => _enclosingFunction;
|
||||
|
||||
@override
|
||||
FlowAnalysis<AstNode, Statement, Expression, PromotableElement, DartType>?
|
||||
get flow => flowAnalysis.flow;
|
||||
|
||||
@override
|
||||
DartType get intType => throw UnimplementedError('TODO(paulberry)');
|
||||
|
||||
bool get isConstructorTearoffsEnabled =>
|
||||
_featureSet.isEnabled(Feature.constructor_tearoffs);
|
||||
|
||||
|
@ -398,6 +457,14 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
: NullabilitySuffix.star;
|
||||
}
|
||||
|
||||
@override
|
||||
DartType get objectQuestionType =>
|
||||
throw UnimplementedError('TODO(paulberry)');
|
||||
|
||||
/// Gets the current depth of the [_rewriteStack]. This may be used in
|
||||
/// assertions to verify that pushes and pops are properly balanced.
|
||||
int get rewriteStackDepth => _rewriteStack.length;
|
||||
|
||||
/// If a class, or mixin, is being resolved, the type of the class.
|
||||
///
|
||||
/// If an extension is being resolved, the type of `this`, the declared
|
||||
|
@ -408,17 +475,16 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
return _thisType;
|
||||
}
|
||||
|
||||
@override
|
||||
TypeOperations2<DartType> get typeOperations => flowAnalysis.typeOperations;
|
||||
|
||||
@override
|
||||
DartType get unknownType => UnknownInferredType.instance;
|
||||
|
||||
/// Return `true` if NNBD is enabled for this compilation unit.
|
||||
bool get _isNonNullableByDefault =>
|
||||
_featureSet.isEnabled(Feature.non_nullable);
|
||||
|
||||
void analyzeExpression(Expression expression, DartType? contextType) {
|
||||
if (contextType != null && contextType.isDynamic) {
|
||||
contextType = null;
|
||||
}
|
||||
(expression as ExpressionImpl).resolveExpression(this, contextType);
|
||||
}
|
||||
|
||||
/// Verify that the arguments in the given [argumentList] can be assigned to
|
||||
/// their corresponding parameters.
|
||||
///
|
||||
|
@ -513,6 +579,13 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
}
|
||||
}
|
||||
|
||||
/// The client of the resolver should call this method after asking the
|
||||
/// resolver to visit an AST node. This performs assertions to make sure that
|
||||
/// temporary resolver state has been properly cleaned up.
|
||||
void checkIdle() {
|
||||
assert(_rewriteStack.isEmpty);
|
||||
}
|
||||
|
||||
void checkReadOfNotAssignedLocalVariable(
|
||||
SimpleIdentifier node,
|
||||
Element? element,
|
||||
|
@ -609,6 +682,51 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
return messages;
|
||||
}
|
||||
|
||||
@override
|
||||
ExpressionTypeAnalysisResult<DartType> dispatchExpression(
|
||||
covariant ExpressionImpl expression, DartType context) {
|
||||
int? stackDepth;
|
||||
assert(() {
|
||||
stackDepth = rewriteStackDepth;
|
||||
return true;
|
||||
}());
|
||||
// TODO(paulberry): implement null shorting
|
||||
// Stack: ()
|
||||
pushRewrite(expression);
|
||||
// Stack: (Expression)
|
||||
expression.resolveExpression(this, context);
|
||||
assert(rewriteStackDepth == stackDepth! + 1);
|
||||
var replacementExpression = peekRewrite()!;
|
||||
assert(identical(
|
||||
_replacements[expression] ?? expression, replacementExpression));
|
||||
var staticType = replacementExpression.staticType;
|
||||
if (staticType == null) {
|
||||
assert(replacementExpression is ExtensionOverride);
|
||||
staticType = unknownType;
|
||||
}
|
||||
return SimpleTypeAnalysisResult<DartType>(type: staticType);
|
||||
}
|
||||
|
||||
@override
|
||||
PatternDispatchResult<AstNode, Expression, PromotableElement, DartType>
|
||||
dispatchPattern(AstNode pattern) {
|
||||
if (pattern is Expression) {
|
||||
return analyzeConstantPattern(pattern, pattern);
|
||||
} else {
|
||||
throw UnimplementedError('TODO(paulberry): ${pattern.runtimeType}');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispatchStatement(Statement statement) {
|
||||
statement.accept(this);
|
||||
}
|
||||
|
||||
@override
|
||||
void finishExpressionCase(Expression node, int caseIndex) {
|
||||
throw UnimplementedError('TODO(paulberry)');
|
||||
}
|
||||
|
||||
/// Return the static element associated with the given expression whose type
|
||||
/// can be overridden, or `null` if there is no element whose type can be
|
||||
/// overridden.
|
||||
|
@ -630,6 +748,110 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
SwitchExpressionMemberInfo<AstNode, Expression> getSwitchExpressionMemberInfo(
|
||||
Expression node, int index) {
|
||||
throw UnimplementedError('TODO(paulberry)');
|
||||
}
|
||||
|
||||
@override
|
||||
SwitchStatementMemberInfo<AstNode, Statement, Expression>
|
||||
getSwitchStatementMemberInfo(covariant SwitchStatement node, int index) {
|
||||
var member = node.members[index];
|
||||
Expression? pattern;
|
||||
if (member is SwitchCase) {
|
||||
pattern = member.expression;
|
||||
}
|
||||
return SwitchStatementMemberInfo(
|
||||
[CaseHeadOrDefaultInfo(pattern: pattern)], member.statements,
|
||||
labels: member.labels);
|
||||
}
|
||||
|
||||
@override
|
||||
void handleCase_afterCaseHeads(AstNode node, int caseIndex, int numHeads) {}
|
||||
|
||||
@override
|
||||
void handleCaseHead(
|
||||
// TODO(paulberry): once we support switch expressions this type will
|
||||
// need to change.
|
||||
covariant SwitchStatement node,
|
||||
{required int caseIndex,
|
||||
required int subIndex}) {
|
||||
// Stack: (Expression)
|
||||
popRewrite(); // "when" expression
|
||||
// Stack: ()
|
||||
switchExhaustiveness!.visitSwitchMember(node.members[caseIndex]);
|
||||
}
|
||||
|
||||
@override
|
||||
void handleCastPattern(AstNode node,
|
||||
{required DartType matchedType, DartType? staticType}) {
|
||||
throw UnimplementedError('TODO(paulberry)');
|
||||
}
|
||||
|
||||
@override
|
||||
void handleConstantPattern(AstNode node, {required DartType matchedType}) {
|
||||
// Stack: (Expression)
|
||||
popRewrite();
|
||||
// Stack: ()
|
||||
}
|
||||
|
||||
@override
|
||||
void handleDefault(covariant SwitchStatement node, int caseIndex) {
|
||||
switchExhaustiveness!.visitSwitchMember(node.members[caseIndex]);
|
||||
}
|
||||
|
||||
@override
|
||||
void handleListPattern(AstNode node, int numElements,
|
||||
{required DartType matchedType, required DartType requiredType}) {
|
||||
throw UnimplementedError('TODO(paulberry)');
|
||||
}
|
||||
|
||||
@override
|
||||
void handleLogicalPattern(AstNode node,
|
||||
{required bool isAnd, required DartType matchedType}) {
|
||||
throw UnimplementedError('TODO(paulberry)');
|
||||
}
|
||||
|
||||
@override
|
||||
void handleMergedStatementCase(covariant SwitchStatement node,
|
||||
{required int caseIndex,
|
||||
required int executionPathIndex,
|
||||
required int numStatements}) {
|
||||
nullSafetyDeadCodeVerifier.flowEnd(node.members[caseIndex]);
|
||||
}
|
||||
|
||||
@override
|
||||
void handleNoGuard(AstNode node, int caseIndex) {
|
||||
// Stack: ()
|
||||
// We can push `null` here because there is no actual expression associated
|
||||
// with the lack of a guard, so there's nothing that will need rewriting.
|
||||
pushRewrite(null);
|
||||
// Stack: (Expression)
|
||||
}
|
||||
|
||||
@override
|
||||
void handleNoStatement(Statement node) {
|
||||
throw UnimplementedError('TODO(paulberry)');
|
||||
}
|
||||
|
||||
@override
|
||||
void handleNullCheckOrAssertPattern(AstNode node,
|
||||
{required DartType matchedType, required bool isAssert}) {
|
||||
throw UnimplementedError('TODO(paulberry)');
|
||||
}
|
||||
|
||||
@override
|
||||
void handleSwitchScrutinee(DartType type) {
|
||||
switchExhaustiveness = SwitchExhaustiveness(type);
|
||||
}
|
||||
|
||||
@override
|
||||
void handleVariablePattern(AstNode node,
|
||||
{required DartType matchedType, DartType? staticType}) {
|
||||
throw UnimplementedError('TODO(paulberry)');
|
||||
}
|
||||
|
||||
/// If generic function instantiation should be performed on `expression`,
|
||||
/// inserts a [FunctionReference] node which wraps [expression].
|
||||
///
|
||||
|
@ -678,8 +900,7 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
function: expression,
|
||||
typeArguments: null,
|
||||
);
|
||||
NodeReplacer.replace(expression, genericFunctionInstantiation,
|
||||
parent: parent);
|
||||
replaceExpression(expression, genericFunctionInstantiation, parent: parent);
|
||||
|
||||
genericFunctionInstantiation.typeArgumentTypes = typeArgumentTypes;
|
||||
genericFunctionInstantiation.staticType = staticType;
|
||||
|
@ -687,6 +908,15 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
return genericFunctionInstantiation;
|
||||
}
|
||||
|
||||
@override
|
||||
bool isSwitchExhaustive(AstNode node, DartType expressionType) =>
|
||||
switchExhaustiveness!.isExhaustive;
|
||||
|
||||
@override
|
||||
DartType listType(DartType elementType) {
|
||||
throw UnimplementedError('TODO(paulberry)');
|
||||
}
|
||||
|
||||
/// If we reached a null-shorting termination, and the [node] has null
|
||||
/// shorting, make the type of the [node] nullable.
|
||||
void nullShortingTermination(ExpressionImpl node,
|
||||
|
@ -718,6 +948,18 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
// TODO(brianwilkerson) Remove this method.
|
||||
}
|
||||
|
||||
/// Examines the top entry of [_rewriteStack] but does not pop it.
|
||||
ExpressionImpl? peekRewrite() => _rewriteStack.last;
|
||||
|
||||
/// Pops the top entry off of [_rewriteStack].
|
||||
ExpressionImpl? popRewrite() {
|
||||
var expression = _rewriteStack.removeLast();
|
||||
if (_debugRewriteStack) {
|
||||
assert(_debugPrint('POP ${expression.runtimeType} $expression'));
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
|
||||
/// Set information about enclosing declarations.
|
||||
void prepareEnclosingDeclarations({
|
||||
InterfaceElement? enclosingClassElement,
|
||||
|
@ -767,6 +1009,36 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
return false;
|
||||
}
|
||||
|
||||
/// Pushes an entry onto [_rewriteStack].
|
||||
void pushRewrite(ExpressionImpl? expression) {
|
||||
if (_debugRewriteStack) {
|
||||
assert(_debugPrint('PUSH ${expression.runtimeType} $expression'));
|
||||
}
|
||||
_rewriteStack.add(expression);
|
||||
}
|
||||
|
||||
/// Replaces the expression [oldNode] with [newNode], updating the node's
|
||||
/// parent as appropriate.
|
||||
///
|
||||
/// If [newNode] is the parent of [oldNode] already (because [newNode] became
|
||||
/// the parent of [oldNode] in its constructor), this action will loop
|
||||
/// infinitely; pass [oldNode]'s previous parent as [parent] to avoid this.
|
||||
void replaceExpression(Expression oldNode, ExpressionImpl newNode,
|
||||
{AstNode? parent}) {
|
||||
assert(() {
|
||||
assert(_replacements[oldNode] == null);
|
||||
_replacements[oldNode] = newNode;
|
||||
return true;
|
||||
}());
|
||||
if (_rewriteStack.isNotEmpty && identical(peekRewrite(), oldNode)) {
|
||||
if (_debugRewriteStack) {
|
||||
assert(_debugPrint('REPLACE ${newNode.runtimeType} $newNode'));
|
||||
}
|
||||
_rewriteStack.last = newNode;
|
||||
}
|
||||
NodeReplacer.replace(oldNode, newNode, parent: parent);
|
||||
}
|
||||
|
||||
/// Resolve LHS [node] of an assignment, an explicit [AssignmentExpression],
|
||||
/// or implicit [PrefixExpression] or [PostfixExpression].
|
||||
PropertyElementResolverResult resolveForWrite({
|
||||
|
@ -784,6 +1056,7 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
);
|
||||
|
||||
analyzeExpression(node.index, result.indexContextType);
|
||||
popRewrite();
|
||||
var whyNotPromoted = flowAnalysis.flow?.whyNotPromoted(node.index);
|
||||
checkIndexExpressionIndex(
|
||||
node.index,
|
||||
|
@ -884,6 +1157,11 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
_thisType = thisType;
|
||||
}
|
||||
|
||||
@override
|
||||
void setVariableType(PromotableElement variable, DartType type) {
|
||||
throw UnimplementedError('TODO(paulberry)');
|
||||
}
|
||||
|
||||
void setWriteElement(Expression node, Element? element) {
|
||||
DartType writeType = DynamicTypeImpl.instance;
|
||||
if (node is IndexExpression) {
|
||||
|
@ -980,6 +1258,11 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
return NullabilityEliminator.perform(typeProvider, type);
|
||||
}
|
||||
|
||||
@override
|
||||
DartType variableTypeFromInitializerType(DartType type) {
|
||||
throw UnimplementedError('TODO(paulberry)');
|
||||
}
|
||||
|
||||
@override
|
||||
void visitAdjacentStrings(AdjacentStrings node, {DartType? contextType}) {
|
||||
checkUnreachableNode(node);
|
||||
|
@ -1014,6 +1297,7 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
void visitAssertInitializer(AssertInitializer node) {
|
||||
flowAnalysis.flow?.assert_begin();
|
||||
analyzeExpression(node.condition, typeProvider.boolType);
|
||||
popRewrite();
|
||||
boolExpressionVerifier.checkForNonBoolExpression(
|
||||
node.condition,
|
||||
errorCode: CompileTimeErrorCode.NON_BOOL_EXPRESSION,
|
||||
|
@ -1028,6 +1312,7 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
void visitAssertStatement(AssertStatement node) {
|
||||
flowAnalysis.flow?.assert_begin();
|
||||
analyzeExpression(node.condition, typeProvider.boolType);
|
||||
popRewrite();
|
||||
boolExpressionVerifier.checkForNonBoolExpression(
|
||||
node.condition,
|
||||
errorCode: CompileTimeErrorCode.NON_BOOL_EXPRESSION,
|
||||
|
@ -1064,6 +1349,7 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
}
|
||||
checkUnreachableNode(node);
|
||||
analyzeExpression(node.expression, futureUnion);
|
||||
popRewrite();
|
||||
typeAnalyzer.visitAwaitExpression(node as AwaitExpressionImpl,
|
||||
contextType: contextType);
|
||||
_insertImplicitCallReference(
|
||||
|
@ -1128,6 +1414,7 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
void visitCascadeExpression(covariant CascadeExpressionImpl node,
|
||||
{DartType? contextType}) {
|
||||
analyzeExpression(node.target, contextType);
|
||||
popRewrite();
|
||||
|
||||
if (node.isNullAware) {
|
||||
flowAnalysis.flow!.nullAwareAccess_rightBegin(
|
||||
|
@ -1204,6 +1491,7 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
for (int i = 0; i < declarationCount; i++) {
|
||||
declarations[i].accept(this);
|
||||
}
|
||||
checkIdle();
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -1215,7 +1503,7 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
|
||||
// TODO(scheglov) Do we need these checks for null?
|
||||
analyzeExpression(node.condition, typeProvider.boolType);
|
||||
condition = node.condition;
|
||||
condition = popRewrite()!;
|
||||
var whyNotPromoted = flowAnalysis.flow?.whyNotPromoted(condition);
|
||||
boolExpressionVerifier.checkForNonBoolCondition(condition,
|
||||
whyNotPromoted: whyNotPromoted);
|
||||
|
@ -1225,6 +1513,7 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
checkUnreachableNode(node.thenExpression);
|
||||
}
|
||||
analyzeExpression(node.thenExpression, contextType);
|
||||
popRewrite();
|
||||
nullSafetyDeadCodeVerifier.flowEnd(node.thenExpression);
|
||||
|
||||
Expression elseExpression = node.elseExpression;
|
||||
|
@ -1238,7 +1527,7 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
} else {
|
||||
analyzeExpression(elseExpression, contextType);
|
||||
}
|
||||
elseExpression = node.elseExpression;
|
||||
elseExpression = popRewrite()!;
|
||||
|
||||
typeAnalyzer.visitConditionalExpression(node as ConditionalExpressionImpl,
|
||||
contextType: contextType);
|
||||
|
@ -1299,7 +1588,7 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
var fieldType = fieldElement?.type;
|
||||
var expression = node.expression;
|
||||
analyzeExpression(expression, fieldType);
|
||||
expression = node.expression;
|
||||
expression = popRewrite()!;
|
||||
var whyNotPromoted = flowAnalysis.flow?.whyNotPromoted(expression);
|
||||
elementResolver.visitConstructorFieldInitializer(
|
||||
node as ConstructorFieldInitializerImpl);
|
||||
|
@ -1354,6 +1643,7 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
var defaultValue = node.defaultValue;
|
||||
if (defaultValue != null) {
|
||||
analyzeExpression(defaultValue, node.declaredElement?.type);
|
||||
popRewrite();
|
||||
}
|
||||
ParameterElement element = node.declaredElement!;
|
||||
|
||||
|
@ -1373,7 +1663,7 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
|
||||
flowAnalysis.flow?.doStatement_conditionBegin();
|
||||
analyzeExpression(condition, typeProvider.boolType);
|
||||
condition = node.condition;
|
||||
condition = popRewrite()!;
|
||||
var whyNotPromoted = flowAnalysis.flow?.whyNotPromoted(condition);
|
||||
boolExpressionVerifier.checkForNonBoolCondition(condition,
|
||||
whyNotPromoted: whyNotPromoted);
|
||||
|
@ -1465,6 +1755,7 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
);
|
||||
for (var argument in argumentList.arguments) {
|
||||
analyzeExpression(argument, argument.staticParameterElement?.type);
|
||||
popRewrite();
|
||||
}
|
||||
arguments.typeArguments?.accept(this);
|
||||
|
||||
|
@ -1530,6 +1821,7 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
node.expression,
|
||||
inferenceContext.bodyContext!.contextType,
|
||||
);
|
||||
popRewrite();
|
||||
|
||||
flowAnalysis.flow?.handleExit();
|
||||
|
||||
|
@ -1661,6 +1953,7 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
node.metadata.accept(this);
|
||||
node.returnType?.accept(this);
|
||||
analyzeExpression(node.functionExpression, functionType);
|
||||
popRewrite();
|
||||
elementResolver.visitFunctionDeclaration(node);
|
||||
} finally {
|
||||
_enclosingFunction = outerFunction;
|
||||
|
@ -1758,7 +2051,7 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
flowAnalysis.flow?.ifStatement_conditionBegin();
|
||||
Expression condition = node.condition;
|
||||
analyzeExpression(condition, typeProvider.boolType);
|
||||
condition = node.condition;
|
||||
condition = popRewrite()!;
|
||||
var whyNotPromoted = flowAnalysis.flow?.whyNotPromoted(condition);
|
||||
|
||||
boolExpressionVerifier.checkForNonBoolCondition(condition,
|
||||
|
@ -1766,12 +2059,14 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
|
||||
flowAnalysis.flow?.ifStatement_thenBegin(condition, node);
|
||||
(node.thenElement as CollectionElementImpl).resolveElement(this, context);
|
||||
popRewrite();
|
||||
nullSafetyDeadCodeVerifier.flowEnd(node.thenElement);
|
||||
|
||||
var elseElement = node.elseElement;
|
||||
if (elseElement != null) {
|
||||
flowAnalysis.flow?.ifStatement_elseBegin();
|
||||
(elseElement as CollectionElementImpl).resolveElement(this, context);
|
||||
popRewrite();
|
||||
nullSafetyDeadCodeVerifier.flowEnd(elseElement);
|
||||
}
|
||||
|
||||
|
@ -1786,7 +2081,7 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
Expression condition = node.condition;
|
||||
|
||||
analyzeExpression(condition, typeProvider.boolType);
|
||||
condition = node.condition;
|
||||
condition = popRewrite()!;
|
||||
var whyNotPromoted = flowAnalysis.flow?.whyNotPromoted(condition);
|
||||
|
||||
boolExpressionVerifier.checkForNonBoolCondition(condition,
|
||||
|
@ -1817,6 +2112,7 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
{DartType? contextType}) {
|
||||
checkUnreachableNode(node);
|
||||
analyzeExpression(node.expression, null);
|
||||
popRewrite();
|
||||
node.typeArguments?.accept(this);
|
||||
}
|
||||
|
||||
|
@ -1843,6 +2139,7 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
node.staticElement = element as MethodElement?;
|
||||
|
||||
analyzeExpression(node.index, result.indexContextType);
|
||||
popRewrite();
|
||||
var whyNotPromoted = flowAnalysis.flow?.whyNotPromoted(node.index);
|
||||
checkIndexExpressionIndex(
|
||||
node.index,
|
||||
|
@ -1937,7 +2234,8 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
void visitListLiteral(covariant ListLiteralImpl node,
|
||||
{DartType? contextType}) {
|
||||
checkUnreachableNode(node);
|
||||
_typedLiteralResolver.resolveListLiteral(node, contextType: contextType);
|
||||
_typedLiteralResolver.resolveListLiteral(node,
|
||||
contextType: contextType ?? UnknownInferredType.instance);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -1945,7 +2243,9 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
{CollectionLiteralContext? context}) {
|
||||
checkUnreachableNode(node);
|
||||
analyzeExpression(node.key, context?.keyType);
|
||||
popRewrite();
|
||||
analyzeExpression(node.value, context?.valueType);
|
||||
popRewrite();
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -2048,6 +2348,7 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
checkUnreachableNode(node);
|
||||
node.name.accept(this);
|
||||
analyzeExpression(node.expression, contextType);
|
||||
popRewrite();
|
||||
typeAnalyzer.visitNamedExpression(node as NamedExpressionImpl,
|
||||
contextType: contextType);
|
||||
// Any "why not promoted" information that flow analysis had associated with
|
||||
|
@ -2099,6 +2400,7 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
{DartType? contextType}) {
|
||||
checkUnreachableNode(node);
|
||||
analyzeExpression(node.expression, contextType);
|
||||
popRewrite();
|
||||
typeAnalyzer.visitParenthesizedExpression(
|
||||
node as ParenthesizedExpressionImpl,
|
||||
contextType: contextType);
|
||||
|
@ -2281,7 +2583,7 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
inferenceContext.bodyContext?.contextType,
|
||||
);
|
||||
// Pick up the expression again in case it was rewritten.
|
||||
expression = node.expression;
|
||||
expression = popRewrite();
|
||||
}
|
||||
|
||||
inferenceContext.bodyContext?.addReturnExpression(expression);
|
||||
|
@ -2292,7 +2594,7 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
void visitSetOrMapLiteral(SetOrMapLiteral node, {DartType? contextType}) {
|
||||
checkUnreachableNode(node);
|
||||
_typedLiteralResolver.resolveSetOrMapLiteral(node,
|
||||
contextType: contextType);
|
||||
contextType: contextType ?? UnknownInferredType.instance);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -2332,6 +2634,7 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
}
|
||||
checkUnreachableNode(node);
|
||||
analyzeExpression(node.expression, iterableType);
|
||||
popRewrite();
|
||||
|
||||
if (!node.isNullAware) {
|
||||
nullableDereferenceVerifier.expression(
|
||||
|
@ -2386,72 +2689,17 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
node.visitChildren(this);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitSwitchCase(SwitchCase node) {
|
||||
checkUnreachableNode(node);
|
||||
|
||||
checkUnreachableNode(node);
|
||||
node.labels.accept(this);
|
||||
analyzeExpression(node.expression, _enclosingSwitchStatementExpressionType);
|
||||
node.statements.accept(this);
|
||||
|
||||
var flow = flowAnalysis.flow;
|
||||
if (flow != null && flow.isReachable && _isNonNullableByDefault) {
|
||||
var switchStatement = node.parent as SwitchStatement;
|
||||
if (switchStatement.members.last != node && node.statements.isNotEmpty) {
|
||||
errorReporter.reportErrorForToken(
|
||||
CompileTimeErrorCode.SWITCH_CASE_COMPLETES_NORMALLY,
|
||||
node.keyword,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
nullSafetyDeadCodeVerifier.flowEnd(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitSwitchDefault(SwitchDefault node) {
|
||||
checkUnreachableNode(node);
|
||||
node.visitChildren(this);
|
||||
nullSafetyDeadCodeVerifier.flowEnd(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitSwitchStatement(SwitchStatement node) {
|
||||
// Stack: ()
|
||||
checkUnreachableNode(node);
|
||||
|
||||
var previousExpressionType = _enclosingSwitchStatementExpressionType;
|
||||
try {
|
||||
var expression = node.expression;
|
||||
expression.accept(this);
|
||||
expression = node.expression;
|
||||
|
||||
_enclosingSwitchStatementExpressionType = expression.typeOrThrow;
|
||||
|
||||
var flow = flowAnalysis.flow!;
|
||||
|
||||
flow.switchStatement_expressionEnd(node);
|
||||
|
||||
var exhaustiveness = _SwitchExhaustiveness(
|
||||
_enclosingSwitchStatementExpressionType!,
|
||||
);
|
||||
|
||||
var members = node.members;
|
||||
for (var member in members) {
|
||||
flow.switchStatement_beginCase();
|
||||
flow.switchStatement_beginAlternatives();
|
||||
flow.switchStatement_endAlternative();
|
||||
flow.switchStatement_endAlternatives(node,
|
||||
hasLabels: member.labels.isNotEmpty);
|
||||
member.accept(this);
|
||||
|
||||
exhaustiveness.visitSwitchMember(member);
|
||||
}
|
||||
|
||||
flow.switchStatement_end(exhaustiveness.isExhaustive);
|
||||
} finally {
|
||||
_enclosingSwitchStatementExpressionType = previousExpressionType;
|
||||
}
|
||||
var previousExhaustiveness = switchExhaustiveness;
|
||||
analyzeSwitchStatement(node, node.expression, node.members.length);
|
||||
// Stack: (Expression)
|
||||
popRewrite();
|
||||
// Stack: ()
|
||||
switchExhaustiveness = previousExhaustiveness;
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -2601,7 +2849,7 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
|
||||
flowAnalysis.flow?.whileStatement_conditionBegin(node);
|
||||
analyzeExpression(condition, typeProvider.boolType);
|
||||
condition = node.condition;
|
||||
condition = popRewrite()!;
|
||||
var whyNotPromoted = flowAnalysis.flow?.whyNotPromoted(condition);
|
||||
|
||||
boolExpressionVerifier.checkForNonBoolCondition(node.condition,
|
||||
|
@ -2656,6 +2904,14 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
return typeProvider.futureOrType(type);
|
||||
}
|
||||
|
||||
/// Helper function used to print information to the console in debug mode.
|
||||
/// This method returns `true` so that it can be conveniently called inside of
|
||||
/// an `assert` statement.
|
||||
bool _debugPrint(String s) {
|
||||
print(s);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// If `expression` should be treated as `expression.call`, inserts an
|
||||
/// [ImplicitCallReference] node which wraps [expression].
|
||||
void _insertImplicitCallReference(ExpressionImpl expression,
|
||||
|
@ -2708,7 +2964,7 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
typeArguments: null,
|
||||
typeArgumentTypes: typeArgumentTypes,
|
||||
);
|
||||
NodeReplacer.replace(expression, callReference, parent: parent);
|
||||
replaceExpression(expression, callReference, parent: parent);
|
||||
|
||||
callReference.staticType = callMethodType;
|
||||
}
|
||||
|
@ -2956,6 +3212,7 @@ class ResolverVisitorForMigration extends ResolverVisitor {
|
|||
var element = conditionalKnownValue ? node.thenElement : node.elseElement;
|
||||
if (element != null) {
|
||||
(element as CollectionElementImpl).resolveElement(this, context);
|
||||
popRewrite();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3870,7 +4127,7 @@ class ScopeResolverVisitor extends UnifyingAstVisitor<void> {
|
|||
|
||||
/// Tracker for whether a `switch` statement has `default` or is on an
|
||||
/// enumeration, and all the enum constants are covered.
|
||||
class _SwitchExhaustiveness {
|
||||
class SwitchExhaustiveness {
|
||||
/// If the switch is on an enumeration, the set of enum constants to cover.
|
||||
/// Otherwise `null`.
|
||||
final Set<FieldElement>? _enumConstants;
|
||||
|
@ -3882,20 +4139,20 @@ class _SwitchExhaustiveness {
|
|||
|
||||
bool isExhaustive = false;
|
||||
|
||||
factory _SwitchExhaustiveness(DartType expressionType) {
|
||||
factory SwitchExhaustiveness(DartType expressionType) {
|
||||
if (expressionType is InterfaceType) {
|
||||
var enum_ = expressionType.element2;
|
||||
if (enum_ is EnumElementImpl) {
|
||||
return _SwitchExhaustiveness._(
|
||||
return SwitchExhaustiveness._(
|
||||
enum_.constants.toSet(),
|
||||
expressionType.nullabilitySuffix == NullabilitySuffix.none,
|
||||
);
|
||||
}
|
||||
}
|
||||
return _SwitchExhaustiveness._(null, false);
|
||||
return SwitchExhaustiveness._(null, false);
|
||||
}
|
||||
|
||||
_SwitchExhaustiveness._(this._enumConstants, this._isNullEnumValueCovered);
|
||||
SwitchExhaustiveness._(this._enumConstants, this._isNullEnumValueCovered);
|
||||
|
||||
void visitSwitchMember(SwitchMember node) {
|
||||
if (_enumConstants != null && node is SwitchCase) {
|
||||
|
|
|
@ -64,6 +64,7 @@ class AstResolver {
|
|||
_prepareEnclosingDeclarations();
|
||||
_flowAnalysis.topLevelDeclaration_enter(node, null);
|
||||
node.accept(_resolverVisitor);
|
||||
_resolverVisitor.checkIdle();
|
||||
_flowAnalysis.topLevelDeclaration_exit();
|
||||
}
|
||||
|
||||
|
@ -83,6 +84,7 @@ class AstResolver {
|
|||
_flowAnalysis.topLevelDeclaration_enter(node, node.parameters,
|
||||
visit: visit);
|
||||
visit(_resolverVisitor);
|
||||
_resolverVisitor.checkIdle();
|
||||
_flowAnalysis.topLevelDeclaration_exit();
|
||||
}
|
||||
|
||||
|
@ -98,6 +100,8 @@ class AstResolver {
|
|||
_prepareEnclosingDeclarations();
|
||||
_flowAnalysis.topLevelDeclaration_enter(node.parent!, null);
|
||||
_resolverVisitor.analyzeExpression(node, contextType);
|
||||
_resolverVisitor.popRewrite();
|
||||
_resolverVisitor.checkIdle();
|
||||
_flowAnalysis.topLevelDeclaration_exit();
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,23 @@ main() {
|
|||
@reflectiveTest
|
||||
class SwitchExpressionNotAssignableTest extends PubPackageResolutionTest
|
||||
with WithoutNullSafetyMixin {
|
||||
test_do_not_report_on_cases_after_the_first() async {
|
||||
await assertErrorsInCode('''
|
||||
f() {
|
||||
var x = 1;
|
||||
try {
|
||||
switch (x) {
|
||||
case 0:
|
||||
case 2:
|
||||
case "false":
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
''', [
|
||||
error(CompileTimeErrorCode.INCONSISTENT_CASE_EXPRESSION_TYPES, 83, 7),
|
||||
]);
|
||||
}
|
||||
|
||||
test_simple() async {
|
||||
await assertErrorsInCode('''
|
||||
f(int p) {
|
||||
|
|
Loading…
Reference in a new issue