mirror of
https://github.com/dart-lang/sdk
synced 2024-09-18 21:11:19 +00:00
Update shared analysis of object patterns to match spec.
In
ce01d330d7
,
the patterns spec was changed so that if an object pattern's type
resolves to `dynamic` or `Never`, no getters are looked up during
static analysis, and the getter type is simply presumed to be
`dynamic` or `Never`, respectively.
Also, the parameter `requiredType` of `analyzeObjectPattern` is
removed (is was not needed, and the caller always passed `null`).
Finally, the test artifact `ObjectPatternRequiredType` is removed in
favor of just using a PrimaryType directly. This makes the tests a
little bit more compact.
Change-Id: I6fcef8dab8250905e1d37308bbdc82a4fd65f52c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/270982
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
This commit is contained in:
parent
2d2a15af8f
commit
ac1ad9f393
|
@ -697,16 +697,23 @@ mixin TypeAnalyzer<
|
|||
Type matchedType,
|
||||
MatchContext<Node, Expression, Pattern, Type, Variable> context,
|
||||
Pattern node, {
|
||||
required Type? requiredType,
|
||||
required List<RecordPatternField<Node, Pattern>> fields,
|
||||
}) {
|
||||
_reportDuplicateRecordPatternFields(fields);
|
||||
|
||||
requiredType ??= downwardInferObjectPatternRequiredType(
|
||||
Type requiredType = downwardInferObjectPatternRequiredType(
|
||||
matchedType: matchedType,
|
||||
pattern: node,
|
||||
);
|
||||
|
||||
// If the required type is `dynamic` or `Never`, then every getter is
|
||||
// treated as having the same type.
|
||||
Type? overridePropertyGetType;
|
||||
if (typeOperations.isDynamic(requiredType) ||
|
||||
typeOperations.isNever(requiredType)) {
|
||||
overridePropertyGetType = requiredType;
|
||||
}
|
||||
|
||||
Node? irrefutableContext = context.irrefutableContext;
|
||||
if (irrefutableContext != null &&
|
||||
!typeOperations.isAssignableTo(matchedType, requiredType)) {
|
||||
|
@ -720,10 +727,11 @@ mixin TypeAnalyzer<
|
|||
|
||||
// Stack: ()
|
||||
for (RecordPatternField<Node, Pattern> field in fields) {
|
||||
Type propertyType = resolveObjectPatternPropertyGet(
|
||||
receiverType: requiredType,
|
||||
field: field,
|
||||
);
|
||||
Type propertyType = overridePropertyGetType ??
|
||||
resolveObjectPatternPropertyGet(
|
||||
receiverType: requiredType,
|
||||
field: field,
|
||||
);
|
||||
dispatchPattern(propertyType, context, field.pattern);
|
||||
}
|
||||
// Stack: (n * Pattern) where n = fields.length
|
||||
|
|
|
@ -265,11 +265,15 @@ Statement match(Pattern pattern, Expression initializer,
|
|||
isLate: isLate, isFinal: isFinal, location: computeLocation());
|
||||
|
||||
Pattern objectPattern({
|
||||
required ObjectPatternRequiredType requiredType,
|
||||
required String requiredType,
|
||||
required List<RecordPatternField> fields,
|
||||
}) {
|
||||
var parsedType = Type(requiredType);
|
||||
if (parsedType is! PrimaryType) {
|
||||
fail('Expected a primary type, got $parsedType');
|
||||
}
|
||||
return _ObjectPattern(
|
||||
requiredType: requiredType,
|
||||
requiredType: parsedType,
|
||||
fields: fields,
|
||||
location: computeLocation(),
|
||||
);
|
||||
|
@ -754,6 +758,7 @@ class MiniAstOperations
|
|||
'int? <: Object': false,
|
||||
'int? <: Object?': true,
|
||||
'List<int> <: Object': true,
|
||||
'Never <: Object': true,
|
||||
'Never <: Object?': true,
|
||||
'Null <: double?': true,
|
||||
'Null <: int': false,
|
||||
|
@ -881,7 +886,11 @@ class MiniAstOperations
|
|||
};
|
||||
|
||||
static final Map<String, Type> _coreDownwardInferenceResults = {
|
||||
'dynamic <: int': Type('dynamic'),
|
||||
'int <: num': Type('int'),
|
||||
'List <: Iterable<int>': Type('List<int>'),
|
||||
'Never <: int': Type('Never'),
|
||||
'num <: int': Type('num'),
|
||||
};
|
||||
|
||||
static final Map<String, Type> _coreNormalizeResults = {
|
||||
|
@ -1155,27 +1164,6 @@ class Node {
|
|||
String toString() => 'Node#$id';
|
||||
}
|
||||
|
||||
/// Either the type, or the name of a type constructor.
|
||||
class ObjectPatternRequiredType {
|
||||
final Type? type;
|
||||
final String? name;
|
||||
|
||||
ObjectPatternRequiredType.name(this.name) : type = null;
|
||||
|
||||
ObjectPatternRequiredType.type(String type)
|
||||
: type = Type(type),
|
||||
name = null;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
if (type != null) {
|
||||
return '(type: $type)';
|
||||
} else {
|
||||
return '(name: $name)';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract class Pattern extends Node
|
||||
with PossiblyGuardedPattern
|
||||
implements ListPatternElement {
|
||||
|
@ -3239,11 +3227,12 @@ class _MiniAstTypeAnalyzer
|
|||
required Type matchedType,
|
||||
required covariant _ObjectPattern pattern,
|
||||
}) {
|
||||
var name = pattern.requiredType.name;
|
||||
if (name == null) {
|
||||
fail('Expected type constructor name at ${pattern.location}');
|
||||
var requiredType = pattern.requiredType;
|
||||
if (requiredType.args.isNotEmpty) {
|
||||
return requiredType;
|
||||
} else {
|
||||
return typeOperations.downwardInfer(requiredType.name, matchedType);
|
||||
}
|
||||
return typeOperations.downwardInfer(name, matchedType);
|
||||
}
|
||||
|
||||
void finish() {
|
||||
|
@ -3675,7 +3664,7 @@ class _NullLiteral extends Expression {
|
|||
}
|
||||
|
||||
class _ObjectPattern extends Pattern {
|
||||
final ObjectPatternRequiredType requiredType;
|
||||
final PrimaryType requiredType;
|
||||
final List<RecordPatternField> fields;
|
||||
|
||||
_ObjectPattern({
|
||||
|
@ -3686,7 +3675,7 @@ class _ObjectPattern extends Pattern {
|
|||
|
||||
@override
|
||||
Type computeSchema(Harness h) {
|
||||
return h.typeAnalyzer.analyzeObjectPatternSchema(requiredType.type!);
|
||||
return h.typeAnalyzer.analyzeObjectPatternSchema(requiredType);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -3705,9 +3694,8 @@ class _ObjectPattern extends Pattern {
|
|||
Type matchedType,
|
||||
SharedMatchContext context,
|
||||
) {
|
||||
var requiredType = h.typeAnalyzer.analyzeObjectPattern(
|
||||
matchedType, context, this,
|
||||
requiredType: this.requiredType.type, fields: fields);
|
||||
var requiredType = h.typeAnalyzer
|
||||
.analyzeObjectPattern(matchedType, context, this, fields: fields);
|
||||
h.irBuilder.atom(matchedType.type, Kind.type, location: location);
|
||||
h.irBuilder.atom(requiredType.type, Kind.type, location: location);
|
||||
h.irBuilder.apply(
|
||||
|
|
|
@ -2090,7 +2090,7 @@ main() {
|
|||
ifCase(
|
||||
expr('A<int>').checkContext('?'),
|
||||
objectPattern(
|
||||
requiredType: ObjectPatternRequiredType.name('B'),
|
||||
requiredType: 'B',
|
||||
fields: [
|
||||
Var('foo', errorId: 'foo').pattern().recordField('foo'),
|
||||
],
|
||||
|
@ -2100,13 +2100,46 @@ main() {
|
|||
'requiredType: B<int>), variables(foo), true, block(), noop)'),
|
||||
]);
|
||||
});
|
||||
|
||||
test('dynamic type', () {
|
||||
h.run([
|
||||
ifCase(
|
||||
expr('int').checkContext('?'),
|
||||
objectPattern(
|
||||
requiredType: 'dynamic',
|
||||
fields: [
|
||||
Var('foo', errorId: 'foo').pattern().recordField('foo'),
|
||||
],
|
||||
),
|
||||
).checkIr('ifCase(expr(int), objectPattern(varPattern(foo, '
|
||||
'matchedType: dynamic, staticType: dynamic), matchedType: int, '
|
||||
'requiredType: dynamic), variables(foo), true, block(), noop)'),
|
||||
]);
|
||||
});
|
||||
|
||||
test('Never type', () {
|
||||
h.run([
|
||||
ifCase(
|
||||
expr('int').checkContext('?'),
|
||||
objectPattern(
|
||||
requiredType: 'Never',
|
||||
fields: [
|
||||
Var('foo', errorId: 'foo').pattern().recordField('foo'),
|
||||
],
|
||||
),
|
||||
).checkIr('ifCase(expr(int), objectPattern(varPattern(foo, '
|
||||
'matchedType: Never, staticType: Never), matchedType: int, '
|
||||
'requiredType: Never), variables(foo), true, block(), noop)'),
|
||||
]);
|
||||
});
|
||||
|
||||
test('duplicate field name', () {
|
||||
h.addMember('A<int>', 'foo', 'int');
|
||||
h.run([
|
||||
ifCase(
|
||||
expr('A<int>'),
|
||||
objectPattern(
|
||||
requiredType: ObjectPatternRequiredType.type('A<int>'),
|
||||
requiredType: 'A<int>',
|
||||
fields: [
|
||||
Var('a', errorId: 'a').pattern().recordField('foo')
|
||||
..errorId = 'ORIGINAL',
|
||||
|
@ -2128,7 +2161,7 @@ main() {
|
|||
h.run([
|
||||
match(
|
||||
objectPattern(
|
||||
requiredType: ObjectPatternRequiredType.type('num'),
|
||||
requiredType: 'num',
|
||||
fields: [
|
||||
Var('foo').pattern().recordField('foo'),
|
||||
],
|
||||
|
@ -2145,7 +2178,7 @@ main() {
|
|||
h.run([
|
||||
(match(
|
||||
objectPattern(
|
||||
requiredType: ObjectPatternRequiredType.type('int'),
|
||||
requiredType: 'int',
|
||||
fields: [
|
||||
Var('foo').pattern().recordField('foo'),
|
||||
],
|
||||
|
|
|
@ -9452,7 +9452,6 @@ class ObjectPatternImpl extends DartPatternImpl implements ObjectPattern {
|
|||
matchedType,
|
||||
context,
|
||||
this,
|
||||
requiredType: null,
|
||||
fields: resolverVisitor.buildSharedRecordPatternFields(fields),
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue