Skip to content

Commit 756f835

Browse files
author
Dart CI
committed
Version 2.19.0-414.0.dev
Merge ac1ad9f into dev
2 parents 68291f3 + ac1ad9f commit 756f835

File tree

7 files changed

+141
-116
lines changed

7 files changed

+141
-116
lines changed

pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer.dart

Lines changed: 57 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -484,49 +484,6 @@ mixin TypeAnalyzer<
484484
_analyzeIfCommon(node, ifTrue, ifFalse);
485485
}
486486

487-
/// Analyzes a variable declaration statement of the form
488-
/// `pattern = initializer;`.
489-
///
490-
/// [node] should be the AST node for the entire declaration, [pattern] for
491-
/// the pattern, and [initializer] for the initializer. [isFinal] and
492-
/// [isLate] indicate whether this is a final declaration and/or a late
493-
/// declaration, respectively.
494-
///
495-
/// Note that the only kind of pattern allowed in a late declaration is a
496-
/// variable pattern; [TypeAnalyzerErrors.patternDoesNotAllowLate] will be
497-
/// reported if any other kind of pattern is used.
498-
///
499-
/// Stack effect: pushes (Expression, Pattern).
500-
void analyzeInitializedVariableDeclaration(
501-
Node node, Pattern pattern, Expression initializer,
502-
{required bool isFinal, required bool isLate}) {
503-
// Stack: ()
504-
if (isLate && !isVariablePattern(pattern)) {
505-
errors?.patternDoesNotAllowLate(pattern);
506-
}
507-
if (isLate) {
508-
flow?.lateInitializer_begin(node);
509-
}
510-
Type initializerType =
511-
analyzeExpression(initializer, dispatchPatternSchema(pattern));
512-
// Stack: (Expression)
513-
if (isLate) {
514-
flow?.lateInitializer_end();
515-
}
516-
dispatchPattern(
517-
initializerType,
518-
new MatchContext<Node, Expression, Pattern, Type, Variable>(
519-
isFinal: isFinal,
520-
isLate: isLate,
521-
initializer: initializer,
522-
irrefutableContext: node,
523-
topPattern: pattern,
524-
),
525-
pattern,
526-
);
527-
// Stack: (Expression, Pattern)
528-
}
529-
530487
/// Analyzes an integer literal, given the type context [context].
531488
///
532489
/// Stack effect: none.
@@ -740,16 +697,23 @@ mixin TypeAnalyzer<
740697
Type matchedType,
741698
MatchContext<Node, Expression, Pattern, Type, Variable> context,
742699
Pattern node, {
743-
required Type? requiredType,
744700
required List<RecordPatternField<Node, Pattern>> fields,
745701
}) {
746702
_reportDuplicateRecordPatternFields(fields);
747703

748-
requiredType ??= downwardInferObjectPatternRequiredType(
704+
Type requiredType = downwardInferObjectPatternRequiredType(
749705
matchedType: matchedType,
750706
pattern: node,
751707
);
752708

709+
// If the required type is `dynamic` or `Never`, then every getter is
710+
// treated as having the same type.
711+
Type? overridePropertyGetType;
712+
if (typeOperations.isDynamic(requiredType) ||
713+
typeOperations.isNever(requiredType)) {
714+
overridePropertyGetType = requiredType;
715+
}
716+
753717
Node? irrefutableContext = context.irrefutableContext;
754718
if (irrefutableContext != null &&
755719
!typeOperations.isAssignableTo(matchedType, requiredType)) {
@@ -763,10 +727,11 @@ mixin TypeAnalyzer<
763727

764728
// Stack: ()
765729
for (RecordPatternField<Node, Pattern> field in fields) {
766-
Type propertyType = resolveObjectPatternPropertyGet(
767-
receiverType: requiredType,
768-
field: field,
769-
);
730+
Type propertyType = overridePropertyGetType ??
731+
resolveObjectPatternPropertyGet(
732+
receiverType: requiredType,
733+
field: field,
734+
);
770735
dispatchPattern(propertyType, context, field.pattern);
771736
}
772737
// Stack: (n * Pattern) where n = fields.length
@@ -782,6 +747,49 @@ mixin TypeAnalyzer<
782747
return type;
783748
}
784749

750+
/// Analyzes a patternVariableDeclaration statement of the form
751+
/// `var pattern = initializer;` or `final pattern = initializer;.
752+
///
753+
/// [node] should be the AST node for the entire declaration, [pattern] for
754+
/// the pattern, and [initializer] for the initializer. [isFinal] and
755+
/// [isLate] indicate whether this is a final declaration and/or a late
756+
/// declaration, respectively.
757+
///
758+
/// Note that the only kind of pattern allowed in a late declaration is a
759+
/// variable pattern; [TypeAnalyzerErrors.patternDoesNotAllowLate] will be
760+
/// reported if any other kind of pattern is used.
761+
///
762+
/// Stack effect: pushes (Expression, Pattern).
763+
void analyzePatternVariableDeclarationStatement(
764+
Node node, Pattern pattern, Expression initializer,
765+
{required bool isFinal, required bool isLate}) {
766+
// Stack: ()
767+
if (isLate && !isVariablePattern(pattern)) {
768+
errors?.patternDoesNotAllowLate(pattern);
769+
}
770+
if (isLate) {
771+
flow?.lateInitializer_begin(node);
772+
}
773+
Type initializerType =
774+
analyzeExpression(initializer, dispatchPatternSchema(pattern));
775+
// Stack: (Expression)
776+
if (isLate) {
777+
flow?.lateInitializer_end();
778+
}
779+
dispatchPattern(
780+
initializerType,
781+
new MatchContext<Node, Expression, Pattern, Type, Variable>(
782+
isFinal: isFinal,
783+
isLate: isLate,
784+
initializer: initializer,
785+
irrefutableContext: node,
786+
topPattern: pattern,
787+
),
788+
pattern,
789+
);
790+
// Stack: (Expression, Pattern)
791+
}
792+
785793
/// Analyzes a record pattern. [node] is the pattern itself, and [fields]
786794
/// is the list of subpatterns.
787795
///

pkg/_fe_analyzer_shared/test/mini_ast.dart

Lines changed: 25 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -265,11 +265,15 @@ Statement match(Pattern pattern, Expression initializer,
265265
isLate: isLate, isFinal: isFinal, location: computeLocation());
266266

267267
Pattern objectPattern({
268-
required ObjectPatternRequiredType requiredType,
268+
required String requiredType,
269269
required List<RecordPatternField> fields,
270270
}) {
271+
var parsedType = Type(requiredType);
272+
if (parsedType is! PrimaryType) {
273+
fail('Expected a primary type, got $parsedType');
274+
}
271275
return _ObjectPattern(
272-
requiredType: requiredType,
276+
requiredType: parsedType,
273277
fields: fields,
274278
location: computeLocation(),
275279
);
@@ -754,6 +758,7 @@ class MiniAstOperations
754758
'int? <: Object': false,
755759
'int? <: Object?': true,
756760
'List<int> <: Object': true,
761+
'Never <: Object': true,
757762
'Never <: Object?': true,
758763
'Null <: double?': true,
759764
'Null <: int': false,
@@ -881,7 +886,11 @@ class MiniAstOperations
881886
};
882887

883888
static final Map<String, Type> _coreDownwardInferenceResults = {
889+
'dynamic <: int': Type('dynamic'),
890+
'int <: num': Type('int'),
884891
'List <: Iterable<int>': Type('List<int>'),
892+
'Never <: int': Type('Never'),
893+
'num <: int': Type('num'),
885894
};
886895

887896
static final Map<String, Type> _coreNormalizeResults = {
@@ -1008,7 +1017,7 @@ class MiniAstOperations
10081017

10091018
@override
10101019
bool isDynamic(Type type) =>
1011-
type is NonFunctionType && type.name == 'dynamic' && type.args.isEmpty;
1020+
type is PrimaryType && type.name == 'dynamic' && type.args.isEmpty;
10121021

10131022
@override
10141023
bool isNever(Type type) {
@@ -1048,7 +1057,7 @@ class MiniAstOperations
10481057

10491058
@override
10501059
Type? matchIterableType(Type type) {
1051-
if (type is NonFunctionType &&
1060+
if (type is PrimaryType &&
10521061
type.name == 'Iterable' &&
10531062
type.args.length == 1) {
10541063
return type.args[0];
@@ -1058,9 +1067,7 @@ class MiniAstOperations
10581067

10591068
@override
10601069
Type? matchListType(Type type) {
1061-
if (type is NonFunctionType &&
1062-
type.name == 'List' &&
1063-
type.args.length == 1) {
1070+
if (type is PrimaryType && type.name == 'List' && type.args.length == 1) {
10641071
return type.args[0];
10651072
}
10661073
return null;
@@ -1157,27 +1164,6 @@ class Node {
11571164
String toString() => 'Node#$id';
11581165
}
11591166

1160-
/// Either the type, or the name of a type constructor.
1161-
class ObjectPatternRequiredType {
1162-
final Type? type;
1163-
final String? name;
1164-
1165-
ObjectPatternRequiredType.name(this.name) : type = null;
1166-
1167-
ObjectPatternRequiredType.type(String type)
1168-
: type = Type(type),
1169-
name = null;
1170-
1171-
@override
1172-
String toString() {
1173-
if (type != null) {
1174-
return '(type: $type)';
1175-
} else {
1176-
return '(name: $name)';
1177-
}
1178-
}
1179-
}
1180-
11811167
abstract class Pattern extends Node
11821168
with PossiblyGuardedPattern
11831169
implements ListPatternElement {
@@ -2018,7 +2004,7 @@ class _Declare extends Statement {
20182004
irName = 'declare';
20192005
argKinds = [Kind.pattern];
20202006
} else {
2021-
h.typeAnalyzer.analyzeInitializedVariableDeclaration(
2007+
h.typeAnalyzer.analyzePatternVariableDeclarationStatement(
20222008
this, pattern, initializer,
20232009
isFinal: isFinal, isLate: isLate);
20242010
irName = 'match';
@@ -3241,11 +3227,12 @@ class _MiniAstTypeAnalyzer
32413227
required Type matchedType,
32423228
required covariant _ObjectPattern pattern,
32433229
}) {
3244-
var name = pattern.requiredType.name;
3245-
if (name == null) {
3246-
fail('Expected type constructor name at ${pattern.location}');
3230+
var requiredType = pattern.requiredType;
3231+
if (requiredType.args.isNotEmpty) {
3232+
return requiredType;
3233+
} else {
3234+
return typeOperations.downwardInfer(requiredType.name, matchedType);
32473235
}
3248-
return typeOperations.downwardInfer(name, matchedType);
32493236
}
32503237

32513238
void finish() {
@@ -3483,8 +3470,7 @@ class _MiniAstTypeAnalyzer
34833470
Type leastUpperBound(Type t1, Type t2) => _harness._operations._lub(t1, t2);
34843471

34853472
@override
3486-
Type listType(Type elementType) =>
3487-
NonFunctionType('List', args: [elementType]);
3473+
Type listType(Type elementType) => PrimaryType('List', args: [elementType]);
34883474

34893475
_PropertyElement lookupInterfaceMember(
34903476
Node node, Type receiverType, String memberName) {
@@ -3678,7 +3664,7 @@ class _NullLiteral extends Expression {
36783664
}
36793665

36803666
class _ObjectPattern extends Pattern {
3681-
final ObjectPatternRequiredType requiredType;
3667+
final PrimaryType requiredType;
36823668
final List<RecordPatternField> fields;
36833669

36843670
_ObjectPattern({
@@ -3689,7 +3675,7 @@ class _ObjectPattern extends Pattern {
36893675

36903676
@override
36913677
Type computeSchema(Harness h) {
3692-
return h.typeAnalyzer.analyzeObjectPatternSchema(requiredType.type!);
3678+
return h.typeAnalyzer.analyzeObjectPatternSchema(requiredType);
36933679
}
36943680

36953681
@override
@@ -3708,9 +3694,8 @@ class _ObjectPattern extends Pattern {
37083694
Type matchedType,
37093695
SharedMatchContext context,
37103696
) {
3711-
var requiredType = h.typeAnalyzer.analyzeObjectPattern(
3712-
matchedType, context, this,
3713-
requiredType: this.requiredType.type, fields: fields);
3697+
var requiredType = h.typeAnalyzer
3698+
.analyzeObjectPattern(matchedType, context, this, fields: fields);
37143699
h.irBuilder.atom(matchedType.type, Kind.type, location: location);
37153700
h.irBuilder.atom(requiredType.type, Kind.type, location: location);
37163701
h.irBuilder.apply(

pkg/_fe_analyzer_shared/test/mini_types.dart

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -54,25 +54,35 @@ class NamedType {
5454
String toString() => '$type $name';
5555
}
5656

57-
/// Representation of a "simple" type suitable for unit testing of code in the
58-
/// `_fe_analyzer_shared` package. A "simple" type is either an interface type
57+
/// Exception thrown if a type fails to parse properly.
58+
class ParseError extends Error {
59+
final String message;
60+
61+
ParseError(this.message);
62+
63+
@override
64+
String toString() => message;
65+
}
66+
67+
/// Representation of a primary type suitable for unit testing of code in the
68+
/// `_fe_analyzer_shared` package. A primary type is either an interface type
5969
/// with zero or more type parameters (e.g. `double`, or `Map<int, String>`), a
6070
/// reference to a type parameter, or one of the special types whose name is a
6171
/// single word (e.g. `dynamic`).
62-
class NonFunctionType extends Type {
72+
class PrimaryType extends Type {
6373
/// The name of the type.
6474
final String name;
6575

6676
/// The type arguments, or `const []` if there are no type arguments.
6777
final List<Type> args;
6878

69-
NonFunctionType(this.name, {this.args = const []}) : super._();
79+
PrimaryType(this.name, {this.args = const []}) : super._();
7080

7181
@override
7282
Type? recursivelyDemote({required bool covariant}) {
7383
List<Type>? newArgs = args.recursivelyDemote(covariant: covariant);
7484
if (newArgs == null) return null;
75-
return NonFunctionType(name, args: newArgs);
85+
return PrimaryType(name, args: newArgs);
7686
}
7787

7888
@override
@@ -85,16 +95,6 @@ class NonFunctionType extends Type {
8595
}
8696
}
8797

88-
/// Exception thrown if a type fails to parse properly.
89-
class ParseError extends Error {
90-
final String message;
91-
92-
ParseError(this.message);
93-
94-
@override
95-
String toString() => message;
96-
}
97-
9898
/// Representation of a promoted type parameter type suitable for unit testing
9999
/// of code in the `_fe_analyzer_shared` package. A promoted type parameter is
100100
/// often written using the syntax `a&b`, where `a` is the type parameter and
@@ -109,7 +109,7 @@ class PromotedTypeVariableType extends Type {
109109

110110
@override
111111
Type? recursivelyDemote({required bool covariant}) =>
112-
covariant ? innerType : new NonFunctionType('Never');
112+
covariant ? innerType : new PrimaryType('Never');
113113

114114
@override
115115
String _toString({required bool allowSuffixes}) {
@@ -493,7 +493,7 @@ class _TypeParser {
493493
} else {
494494
typeArgs = const [];
495495
}
496-
return NonFunctionType(typeName, args: typeArgs);
496+
return PrimaryType(typeName, args: typeArgs);
497497
}
498498

499499
static Type parse(String typeStr) {

0 commit comments

Comments
 (0)