@@ -316,16 +316,31 @@ class ExhaustivenessCache<
316
316
mixin SpaceCreator <Pattern extends Object , Type extends Object > {
317
317
TypeOperations <Type > get typeOperations;
318
318
319
+ ObjectFieldLookup get objectFieldLookup;
320
+
319
321
/// Creates a [StaticType] for an unknown type.
320
322
///
321
323
/// This is used when the type of the pattern is unknown or can't be
322
324
/// represented as a [StaticType] . This type is unique and ensures that it
323
325
/// is neither matches anything nor is matched by anything.
324
326
StaticType createUnknownStaticType ();
325
327
326
- /// Creates the [StaticType] for [type] . If [nonNull] is `true` , the created
327
- /// type is non-nullable.
328
- StaticType createStaticType (Type type, {required bool nonNull});
328
+ /// Creates the [StaticType] for [type] .
329
+ StaticType createStaticType (Type type);
330
+
331
+ /// Creates the [StaticType] for [type] restricted by the [contextType] .
332
+ /// If [nonNull] is `true` , the created type is non-nullable.
333
+ StaticType _createStaticTypeWithContext (StaticType contextType, Type type,
334
+ {required bool nonNull}) {
335
+ StaticType staticType = createStaticType (type);
336
+ if (contextType.isSubtypeOf (staticType)) {
337
+ staticType = contextType;
338
+ }
339
+ if (nonNull && staticType is NullableStaticType ) {
340
+ staticType = staticType.underlying;
341
+ }
342
+ return staticType;
343
+ }
329
344
330
345
/// Creates the [StaticType] for the list [type] with the given [identity] .
331
346
StaticType createListType (Type type, ListTypeIdentity <Type > identity);
@@ -335,75 +350,100 @@ mixin SpaceCreator<Pattern extends Object, Type extends Object> {
335
350
336
351
/// Creates the [Space] for [pattern] at the given [path] .
337
352
///
353
+ /// The [contextType] is the [StaticType] in which the pattern match is
354
+ /// performed. This is used to the restrict type of the created [Space] to
355
+ /// the types allowed by the context. For instance `Object(:var hashCode)` is
356
+ /// in itself unrestricted and would yield the top space for matching
357
+ /// `var hashCode` . Using the [contextType] `int` , as given by the type of
358
+ /// the `Object.hashCode` , the created space is all `int` values rather than
359
+ /// all values.
360
+ ///
338
361
/// If [nonNull] is `true` , the space is implicitly non-nullable.
339
- Space dispatchPattern (Path path, Pattern pattern, {required bool nonNull});
362
+ Space dispatchPattern (Path path, StaticType contextType, Pattern pattern,
363
+ {required bool nonNull});
340
364
341
365
/// Creates the root space for [pattern] .
342
- Space createRootSpace (Pattern pattern, {required bool hasGuard}) {
366
+ Space createRootSpace (StaticType contextType, Pattern pattern,
367
+ {required bool hasGuard}) {
343
368
if (hasGuard) {
344
369
return createUnknownSpace (const Path .root ());
345
370
} else {
346
- return dispatchPattern (const Path .root (), pattern, nonNull: false );
371
+ return dispatchPattern (const Path .root (), contextType, pattern,
372
+ nonNull: false );
347
373
}
348
374
}
349
375
350
376
/// Creates the [Space] at [path] for a variable pattern of the declared
351
377
/// [type] .
352
378
///
353
379
/// If [nonNull] is `true` , the space is implicitly non-nullable.
354
- Space createVariableSpace (Path path, Type type, {required bool nonNull}) {
355
- return new Space (path, createStaticType (type, nonNull: nonNull));
380
+ Space createVariableSpace (Path path, StaticType contextType, Type type,
381
+ {required bool nonNull}) {
382
+ StaticType staticType =
383
+ _createStaticTypeWithContext (contextType, type, nonNull: nonNull);
384
+ return new Space (path, staticType);
356
385
}
357
386
358
387
/// Creates the [Space] at [path] for an object pattern of the required [type]
359
388
/// and [fieldPatterns] .
360
389
///
361
390
/// If [nonNull] is `true` , the space is implicitly non-nullable.
362
- Space createObjectSpace (
363
- Path path, Type type, Map <String , Pattern > fieldPatterns,
391
+ Space createObjectSpace (Path path, StaticType contextType, Type type,
392
+ Map <String , Pattern > fieldPatterns,
364
393
{required bool nonNull}) {
394
+ StaticType staticType =
395
+ _createStaticTypeWithContext (contextType, type, nonNull: nonNull);
365
396
Map <String , Space > fields = < String , Space > {};
366
397
for (MapEntry <String , Pattern > entry in fieldPatterns.entries) {
367
398
String name = entry.key;
368
- fields[name] =
369
- dispatchPattern (path.add (name), entry.value, nonNull: false );
399
+ StaticType fieldType = staticType.getField (objectFieldLookup, name) ??
400
+ StaticType .nullableObject;
401
+ fields[name] = dispatchPattern (path.add (name), fieldType, entry.value,
402
+ nonNull: false );
370
403
}
371
- StaticType staticType = createStaticType (type, nonNull: nonNull);
372
404
return new Space (path, staticType, fields: fields);
373
405
}
374
406
375
407
/// Creates the [Space] at [path] for a record pattern of the required [type] ,
376
408
/// [positionalFields] , and [namedFields] .
377
- Space createRecordSpace (Path path, Type recordType,
409
+ Space createRecordSpace (Path path, StaticType contextType, Type recordType,
378
410
List <Pattern > positionalFields, Map <String , Pattern > namedFields) {
411
+ StaticType staticType =
412
+ _createStaticTypeWithContext (contextType, recordType, nonNull: true );
379
413
Map <String , Space > fields = < String , Space > {};
380
414
for (int index = 0 ; index < positionalFields.length; index++ ) {
381
415
String name = '\$ ${index + 1 }' ;
382
- fields[name] = dispatchPattern (path.add (name), positionalFields[index],
416
+ StaticType fieldType = staticType.getField (objectFieldLookup, name) ??
417
+ StaticType .nullableObject;
418
+ fields[name] = dispatchPattern (
419
+ path.add (name), fieldType, positionalFields[index],
383
420
nonNull: false );
384
421
}
385
422
for (MapEntry <String , Pattern > entry in namedFields.entries) {
386
423
String name = entry.key;
387
- fields[name] =
388
- dispatchPattern (path.add (name), entry.value, nonNull: false );
424
+ StaticType fieldType = staticType.getField (objectFieldLookup, name) ??
425
+ StaticType .nullableObject;
426
+ fields[name] = dispatchPattern (path.add (name), fieldType, entry.value,
427
+ nonNull: false );
389
428
}
390
- return new Space (path, createStaticType (recordType, nonNull: true ),
391
- fields: fields);
429
+ return new Space (path, staticType, fields: fields);
392
430
}
393
431
394
432
/// Creates the [Space] at [path] for a wildcard pattern with the declared
395
433
/// [type] .
396
434
///
397
435
/// If [nonNull] is `true` , the space is implicitly non-nullable.
398
- Space createWildcardSpace (Path path, Type ? type, {required bool nonNull}) {
436
+ Space createWildcardSpace (Path path, StaticType contextType, Type ? type,
437
+ {required bool nonNull}) {
399
438
if (type == null ) {
400
- if (nonNull) {
401
- return new Space (path, StaticType .nonNullableObject);
402
- } else {
403
- return new Space (path, StaticType .nullableObject);
439
+ StaticType staticType = contextType;
440
+ if (nonNull && staticType is NullableStaticType ) {
441
+ staticType = staticType.underlying;
404
442
}
443
+ return new Space (path, staticType);
405
444
} else {
406
- StaticType staticType = createStaticType (type, nonNull: nonNull);
445
+ StaticType staticType =
446
+ _createStaticTypeWithContext (contextType, type, nonNull: nonNull);
407
447
return new Space (path, staticType);
408
448
}
409
449
}
@@ -418,45 +458,49 @@ mixin SpaceCreator<Pattern extends Object, Type extends Object> {
418
458
/// [subPattern] .
419
459
///
420
460
/// If [nonNull] is `true` , the space is implicitly non-nullable.
421
- Space createCastSpace (Path path, Pattern subPattern,
461
+ Space createCastSpace (Path path, StaticType contextType, Pattern subPattern,
422
462
{required bool nonNull}) {
423
463
// TODO(johnniwinther): Handle types (sibling sealed types?) implicitly
424
464
// handled by the throw of the invalid cast.
425
- return dispatchPattern (path, subPattern, nonNull: nonNull);
465
+ return dispatchPattern (path, contextType, subPattern, nonNull: nonNull);
426
466
}
427
467
428
468
/// Creates the [Space] at [path] for a null check pattern with the given
429
469
/// [subPattern] .
430
- Space createNullCheckSpace (Path path, Pattern subPattern) {
431
- return dispatchPattern (path, subPattern, nonNull: true );
470
+ Space createNullCheckSpace (
471
+ Path path, StaticType contextType, Pattern subPattern) {
472
+ return dispatchPattern (path, contextType, subPattern, nonNull: true );
432
473
}
433
474
434
475
/// Creates the [Space] at [path] for a null assert pattern with the given
435
476
/// [subPattern] .
436
- Space createNullAssertSpace (Path path, Pattern subPattern) {
437
- Space space = dispatchPattern (path, subPattern, nonNull: true );
477
+ Space createNullAssertSpace (
478
+ Path path, StaticType contextType, Pattern subPattern) {
479
+ Space space = dispatchPattern (path, contextType, subPattern, nonNull: true );
438
480
return space.union (new Space (path, StaticType .nullType));
439
481
}
440
482
441
483
/// Creates the [Space] at [path] for a logical or pattern with the given
442
484
/// [left] and [right] subpatterns.
443
485
///
444
486
/// If [nonNull] is `true` , the space is implicitly non-nullable.
445
- Space createLogicalOrSpace (Path path, Pattern left, Pattern right,
487
+ Space createLogicalOrSpace (
488
+ Path path, StaticType contextType, Pattern left, Pattern right,
446
489
{required bool nonNull}) {
447
- Space aSpace = dispatchPattern (path, left, nonNull: nonNull);
448
- Space bSpace = dispatchPattern (path, right, nonNull: nonNull);
490
+ Space aSpace = dispatchPattern (path, contextType, left, nonNull: nonNull);
491
+ Space bSpace = dispatchPattern (path, contextType, right, nonNull: nonNull);
449
492
return aSpace.union (bSpace);
450
493
}
451
494
452
495
/// Creates the [Space] at [path] for a logical and pattern with the given
453
496
/// [left] and [right] subpatterns.
454
497
///
455
498
/// If [nonNull] is `true` , the space is implicitly non-nullable.
456
- Space createLogicalAndSpace (Path path, Pattern left, Pattern right,
499
+ Space createLogicalAndSpace (
500
+ Path path, StaticType contextType, Pattern left, Pattern right,
457
501
{required bool nonNull}) {
458
- Space aSpace = dispatchPattern (path, left, nonNull: nonNull);
459
- Space bSpace = dispatchPattern (path, right, nonNull: nonNull);
502
+ Space aSpace = dispatchPattern (path, contextType, left, nonNull: nonNull);
503
+ Space bSpace = dispatchPattern (path, contextType, right, nonNull: nonNull);
460
504
return _createSpaceIntersection (path, aSpace, bSpace);
461
505
}
462
506
@@ -469,47 +513,56 @@ mixin SpaceCreator<Pattern extends Object, Type extends Object> {
469
513
required List <Pattern > tailElements,
470
514
required bool hasRest,
471
515
required bool hasExplicitTypeArgument}) {
472
- Map <Key , Space > additionalFields = {};
473
516
int headSize = headElements.length;
474
517
int tailSize = tailElements.length;
518
+
519
+ String typeArgumentText;
520
+ if (hasExplicitTypeArgument) {
521
+ StringBuffer sb = new StringBuffer ();
522
+ sb.write ('<' );
523
+ sb.write (typeOperations.typeToString (elementType));
524
+ sb.write ('>' );
525
+ typeArgumentText = sb.toString ();
526
+ } else {
527
+ typeArgumentText = '' ;
528
+ }
529
+
530
+ ListTypeIdentity <Type > identity = new ListTypeIdentity (
531
+ elementType, typeArgumentText,
532
+ size: headSize + tailSize, hasRest: hasRest);
533
+
534
+ StaticType staticType = createListType (type, identity);
535
+
536
+ Map <Key , Space > additionalFields = {};
475
537
for (int index = 0 ; index < headSize; index++ ) {
476
538
Key key = new HeadKey (index);
539
+ StaticType fieldType =
540
+ staticType.getAdditionalField (key) ?? StaticType .nullableObject;
477
541
additionalFields[key] = dispatchPattern (
478
- path.add (key.name), headElements[index],
542
+ path.add (key.name), fieldType, headElements[index],
479
543
nonNull: false );
480
544
}
481
545
if (hasRest) {
482
546
Key key = new RestKey (headSize, tailSize);
547
+ StaticType fieldType =
548
+ staticType.getAdditionalField (key) ?? StaticType .nullableObject;
483
549
if (restElement != null ) {
484
- additionalFields[key] =
485
- dispatchPattern (path.add (key.name), restElement, nonNull: false );
550
+ additionalFields[key] = dispatchPattern (
551
+ path.add (key.name), fieldType, restElement,
552
+ nonNull: false );
486
553
} else {
487
- additionalFields[key] =
488
- new Space (path.add (key.name), StaticType .nullableObject);
554
+ additionalFields[key] = new Space (path.add (key.name), fieldType);
489
555
}
490
556
}
491
557
for (int index = 0 ; index < tailSize; index++ ) {
492
558
Key key = new TailKey (index);
493
- additionalFields[key] = dispatchPattern (
494
- path.add (key.name), tailElements[tailElements.length - index - 1 ],
559
+ StaticType fieldType =
560
+ staticType.getAdditionalField (key) ?? StaticType .nullableObject;
561
+ additionalFields[key] = dispatchPattern (path.add (key.name), fieldType,
562
+ tailElements[tailElements.length - index - 1 ],
495
563
nonNull: false );
496
564
}
497
- String typeArgumentText;
498
- if (hasExplicitTypeArgument) {
499
- StringBuffer sb = new StringBuffer ();
500
- sb.write ('<' );
501
- sb.write (typeOperations.typeToString (elementType));
502
- sb.write ('>' );
503
- typeArgumentText = sb.toString ();
504
- } else {
505
- typeArgumentText = '' ;
506
- }
507
-
508
- ListTypeIdentity <Type > identity = new ListTypeIdentity (
509
- elementType, typeArgumentText,
510
- size: headSize + tailSize, hasRest: hasRest);
511
- return new Space (path, createListType (type, identity),
512
- additionalFields: additionalFields);
565
+ return new Space (path, staticType, additionalFields: additionalFields);
513
566
}
514
567
515
568
/// Creates the [Space] at [path] for a map pattern.
@@ -520,12 +573,6 @@ mixin SpaceCreator<Pattern extends Object, Type extends Object> {
520
573
required Map <MapKey , Pattern > entries,
521
574
required bool hasRest,
522
575
required bool hasExplicitTypeArguments}) {
523
- Map <Key , Space > additionalFields = {};
524
- for (MapEntry <Key , Pattern > entry in entries.entries) {
525
- Key key = entry.key;
526
- additionalFields[key] =
527
- dispatchPattern (path.add (key.name), entry.value, nonNull: false );
528
- }
529
576
String typeArgumentsText;
530
577
if (hasExplicitTypeArguments) {
531
578
StringBuffer sb = new StringBuffer ();
@@ -542,8 +589,18 @@ mixin SpaceCreator<Pattern extends Object, Type extends Object> {
542
589
MapTypeIdentity <Type > identity = new MapTypeIdentity (
543
590
keyType, valueType, entries.keys.toSet (), typeArgumentsText,
544
591
hasRest: hasRest);
545
- return new Space (path, createMapType (type, identity),
546
- additionalFields: additionalFields);
592
+ StaticType staticType = createMapType (type, identity);
593
+
594
+ Map <Key , Space > additionalFields = {};
595
+ for (MapEntry <Key , Pattern > entry in entries.entries) {
596
+ Key key = entry.key;
597
+ StaticType fieldType =
598
+ staticType.getAdditionalField (key) ?? StaticType .nullableObject;
599
+ additionalFields[key] = dispatchPattern (
600
+ path.add (key.name), fieldType, entry.value,
601
+ nonNull: false );
602
+ }
603
+ return new Space (path, staticType, additionalFields: additionalFields);
547
604
}
548
605
549
606
/// Creates the [Space] at [path] for a pattern with unknown space.
0 commit comments