Skip to content

Commit

Permalink
Version 2.19.0-413.0.dev
Browse files Browse the repository at this point in the history
Merge ae1ed9e into dev
  • Loading branch information
Dart CI committed Nov 21, 2022
2 parents 0c51d4b + ae1ed9e commit 68291f3
Show file tree
Hide file tree
Showing 31 changed files with 664 additions and 316 deletions.
2 changes: 1 addition & 1 deletion DEPS
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ vars = {

# co19 is a cipd package. Use update.sh in tests/co19[_2] to update these
# hashes.
"co19_rev": "19439c0d58a0df422c4acc4ae97a3deeb98d0f67",
"co19_rev": "2a9309cd36effe3b083df6a2761fea6b7213c670",
# This line prevents conflicts when both packages are rolled simultaneously.
"co19_2_rev": "cdab7e4e26f3dd534bcb297ff3f9e9aa5c7a04fb",

Expand Down
81 changes: 63 additions & 18 deletions pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -551,20 +551,33 @@ mixin TypeAnalyzer<
Pattern node,
{Type? elementType,
required List<Node> elements}) {
// Stack: ()
Type? matchedElementType = typeOperations.matchListType(matchedType);
if (matchedElementType == null) {
if (typeOperations.isDynamic(matchedType)) {
matchedElementType = dynamicType;
Type valueType;
if (elementType != null) {
valueType = elementType;
} else {
Type? listElementType = typeOperations.matchListType(matchedType);
if (listElementType != null) {
valueType = listElementType;
} else if (typeOperations.isDynamic(matchedType)) {
valueType = dynamicType;
} else {
matchedElementType = objectQuestionType;
valueType = objectQuestionType;
}
}
// Stack: ()
for (Node element in elements) {
dispatchPattern(matchedElementType, context, element);
if (isRestPatternElement(element)) {
Pattern? subPattern = getRestPatternElementPattern(element);
if (subPattern != null) {
dispatchPattern(listType(valueType), context, subPattern);
}
handleRestPatternElement(node, element);
} else {
dispatchPattern(valueType, context, element);
}
}
// Stack: (n * Pattern) where n = elements.length
Type requiredType = listType(elementType ?? matchedElementType);
Type requiredType = listType(valueType);
Node? irrefutableContext = context.irrefutableContext;
if (irrefutableContext != null &&
!typeOperations.isAssignableTo(matchedType, requiredType)) {
Expand All @@ -582,19 +595,40 @@ mixin TypeAnalyzer<
/// subpatterns.
///
/// Stack effect: none.
Type analyzeListPatternSchema(
{Type? elementType, required List<Node> elements}) {
if (elementType == null) {
if (elements.isEmpty) {
return objectQuestionType;
Type analyzeListPatternSchema({
required Type? elementType,
required List<Node> elements,
}) {
if (elementType != null) {
return listType(elementType);
}

if (elements.isEmpty) {
return listType(unknownType);
}

Type? currentGLB;
for (Node element in elements) {
Type? typeToAdd;
if (isRestPatternElement(element)) {
Pattern? subPattern = getRestPatternElementPattern(element);
if (subPattern != null) {
Type subPatternType = dispatchPatternSchema(subPattern);
typeToAdd = typeOperations.matchIterableType(subPatternType);
}
} else {
typeToAdd = dispatchPatternSchema(element);
}
elementType = dispatchPatternSchema(elements[0]);
for (int i = 1; i < elements.length; i++) {
elementType = typeOperations.glb(
elementType!, dispatchPatternSchema(elements[i]));
if (typeToAdd != null) {
if (currentGLB == null) {
currentGLB = typeToAdd;
} else {
currentGLB = typeOperations.glb(currentGLB, typeToAdd);
}
}
}
return listType(elementType!);
currentGLB ??= unknownType;
return listType(currentGLB);
}

/// Analyzes a logical-or or logical-and pattern. [node] is the pattern
Expand Down Expand Up @@ -1213,6 +1247,9 @@ mixin TypeAnalyzer<

List<Variable>? getJoinedVariableComponents(Variable variable);

/// If [node] is [isRestPatternElement], returns its optional pattern.
Pattern? getRestPatternElementPattern(Node node);

/// Returns an [ExpressionCaseInfo] object describing the [index]th `case` or
/// `default` clause in the switch expression [node].
///
Expand Down Expand Up @@ -1331,6 +1368,11 @@ mixin TypeAnalyzer<
/// Stack effect: pushes (Statement).
void handleNoStatement(Statement node);

/// Called after visiting a rest element in a list or map pattern.
///
/// Stack effect: pushes (Pattern).
void handleRestPatternElement(Pattern container, Node restElement);

/// Called after visiting the scrutinee part of a switch statement or switch
/// expression. This is a hook to allow the client to start exhaustiveness
/// analysis.
Expand All @@ -1343,6 +1385,9 @@ mixin TypeAnalyzer<
/// Stack effect: none.
void handleSwitchScrutinee(Type type);

/// Returns whether [node] is a rest element in a list or map pattern.
bool isRestPatternElement(Node node);

/// Queries whether the switch statement or expression represented by [node]
/// was exhaustive. [expressionType] is the static type of the scrutinee.
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ mixin TypeOperations<Type extends Object> {
/// of [type] and `Null`.
Type makeNullable(Type type);

/// If [type] is a subtype of the type `Iterable<T>` for some `T`, returns
/// the type `T`. Otherwise returns `null`.
Type? matchIterableType(Type type);

/// If [type] is a subtype of the type `List<T>` for some `T`, returns the
/// type `T`. Otherwise returns `null`.
Type? matchListType(Type type);
Expand Down
91 changes: 80 additions & 11 deletions pkg/_fe_analyzer_shared/test/mini_ast.dart
Original file line number Diff line number Diff line change
Expand Up @@ -247,10 +247,13 @@ Expression intLiteral(int value, {bool? expectConversionToDouble}) =>
expectConversionToDouble: expectConversionToDouble,
location: computeLocation());

Pattern listPattern(List<Pattern> elements, {String? elementType}) =>
Pattern listPattern(List<ListPatternElement> elements, {String? elementType}) =>
_ListPattern(elementType == null ? null : Type(elementType), elements,
location: computeLocation());

ListPatternElement listPatternRestElement([Pattern? pattern]) =>
_RestPatternElement(pattern, location: computeLocation());

Statement localFunction(List<Statement> body) {
var location = computeLocation();
return _LocalFunction(_Block(body, location: location), location: location);
Expand Down Expand Up @@ -685,6 +688,12 @@ class Label extends Node {
String toString() => _name;
}

abstract class ListPatternElement implements Node {
void preVisit(PreVisitor visitor, VariableBinder<Node, Var> variableBinder);

String _debugString({required bool needsKeywordOrType});
}

/// Representation of an expression that can appear on the left hand side of an
/// assignment (or as the target of `++` or `--`). Methods in this class may be
/// used to create more complex expressions based on this one.
Expand Down Expand Up @@ -775,7 +784,13 @@ class MiniAstOperations
'List <: int': false,
'List <: Iterable': true,
'List <: Object': true,
'List<dynamic> <: Object': true,
'List<Object?> <: Object': true,
'List<int> <: dynamic': true,
'List<int> <: Iterable<double>': false,
'List<int> <: Iterable<int>': true,
'List<int> <: List<num>': true,
'List<int> <: String': false,
'Never <: int': true,
'Never <: int?': true,
'Never <: Null': true,
Expand Down Expand Up @@ -847,6 +862,8 @@ class MiniAstOperations
};

static final Map<String, Type> _coreGlbs = {
'Object?, double': Type('double'),
'Object?, int': Type('int'),
'double, int': Type('Never'),
'double?, int?': Type('Null'),
'int?, num': Type('int'),
Expand Down Expand Up @@ -1029,12 +1046,22 @@ class MiniAstOperations
@override
Type makeNullable(Type type) => lub(type, Type('Null'));

@override
Type? matchIterableType(Type type) {
if (type is NonFunctionType &&
type.name == 'Iterable' &&
type.args.length == 1) {
return type.args[0];
}
return null;
}

@override
Type? matchListType(Type type) {
if (type is NonFunctionType) {
if (type.args.length == 1) {
return type.args[0];
}
if (type is NonFunctionType &&
type.name == 'List' &&
type.args.length == 1) {
return type.args[0];
}
return null;
}
Expand Down Expand Up @@ -1151,7 +1178,9 @@ class ObjectPatternRequiredType {
}
}

abstract class Pattern extends Node with PossiblyGuardedPattern {
abstract class Pattern extends Node
with PossiblyGuardedPattern
implements ListPatternElement {
Pattern._({required super.location}) : super._();

Pattern get nullAssert =>
Expand Down Expand Up @@ -1180,8 +1209,6 @@ abstract class Pattern extends Node with PossiblyGuardedPattern {
Pattern or(Pattern other) =>
_LogicalPattern(this, other, isAnd: false, location: computeLocation());

void preVisit(PreVisitor visitor, VariableBinder<Node, Var> variableBinder);

RecordPatternField recordField([String? name]) {
return RecordPatternField(
name: name,
Expand All @@ -1206,8 +1233,6 @@ abstract class Pattern extends Node with PossiblyGuardedPattern {
location: location,
);
}

String _debugString({required bool needsKeywordOrType});
}

class PatternVariableJoin extends Var {
Expand Down Expand Up @@ -2554,7 +2579,7 @@ class _LabeledStatement extends Statement {
class _ListPattern extends Pattern {
final Type? _elementType;

final List<Pattern> _elements;
final List<ListPatternElement> _elements;

_ListPattern(this._elementType, this._elements, {required super.location})
: super._();
Expand Down Expand Up @@ -3256,6 +3281,11 @@ class _MiniAstTypeAnalyzer
return null;
}

@override
Pattern? getRestPatternElementPattern(Node element) {
return element is _RestPatternElement ? element._pattern : null;
}

@override
SwitchExpressionMemberInfo<Node, Expression, Var>
getSwitchExpressionMemberInfo(
Expand Down Expand Up @@ -3400,6 +3430,19 @@ class _MiniAstTypeAnalyzer
_irBuilder.atom('noop', Kind.statement, location: node.location);
}

@override
void handleRestPatternElement(
Pattern container,
covariant _RestPatternElement restElement,
) {
if (restElement._pattern != null) {
_irBuilder.apply('...', [Kind.pattern], Kind.pattern,
location: restElement.location);
} else {
_irBuilder.atom('...', Kind.pattern, location: restElement.location);
}
}

@override
void handleSwitchScrutinee(Type type) {}

Expand All @@ -3418,6 +3461,11 @@ class _MiniAstTypeAnalyzer
}
}

@override
bool isRestPatternElement(Node element) {
return element is _RestPatternElement;
}

@override
bool isSwitchExhaustive(
covariant _SwitchStatement node, Type expressionType) {
Expand Down Expand Up @@ -3852,6 +3900,27 @@ class _RelationalPattern extends Pattern {
_debugString({required bool needsKeywordOrType}) => '$operator $operand';
}

class _RestPatternElement extends Node implements ListPatternElement {
final Pattern? _pattern;

_RestPatternElement(this._pattern, {required super.location}) : super._();

@override
void preVisit(PreVisitor visitor, VariableBinder<Node, Var> variableBinder) {
_pattern?.preVisit(visitor, variableBinder);
}

@override
String _debugString({required bool needsKeywordOrType}) {
var pattern = _pattern;
if (pattern == null) {
return '...';
} else {
return '...${pattern._debugString(needsKeywordOrType: false)}';
}
}
}

class _Return extends Statement {
_Return({required super.location});

Expand Down
Loading

0 comments on commit 68291f3

Please sign in to comment.