mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 10:49:00 +00:00
[_fe_analyzer_shared] Use subpattern for CastPattern exhaustiveness
This changes the Space computation for CastPattern to just the Space for the subpattern. For a non-throwing cast, this is exactly what the pattern will match. There is still potential for handling the types rejected by the cast. For instance recognizing that the (yet) unhandled subtypes of a sealed type are exhausted by the throw. Change-Id: Ia846895449f37a970f87a7f6c54a0ff8285df6b0 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/286825 Reviewed-by: Konstantin Shcheglov <scheglov@google.com> Commit-Queue: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
parent
90ff190627
commit
8617cc68fa
3 changed files with 44 additions and 13 deletions
|
@ -8,23 +8,30 @@ class A {
|
|||
A(this.field);
|
||||
}
|
||||
|
||||
sealed class B {}
|
||||
class C extends B {}
|
||||
class D extends B {}
|
||||
class E extends B {}
|
||||
|
||||
simpleCast(o1, o2) {
|
||||
var a = /*
|
||||
fields={},
|
||||
subtypes={Object,Null},
|
||||
type=Object?
|
||||
*/switch (o1) {
|
||||
_ as A /*space=??*/=> 0,
|
||||
_ /*space=()*/=> 1
|
||||
_ as A /*space=()*/=> 0,
|
||||
_ /*
|
||||
error=unreachable,
|
||||
space=()
|
||||
*/=> 1
|
||||
};
|
||||
|
||||
var b = /*
|
||||
error=non-exhaustive:Object,
|
||||
fields={},
|
||||
subtypes={Object,Null},
|
||||
type=Object?
|
||||
*/switch (o2) {
|
||||
_ as A /*space=??*/=> 0,
|
||||
_ as A /*space=()*/=> 0,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -36,7 +43,7 @@ restrictedCase(o1, o2) {
|
|||
subtypes={Object,Null},
|
||||
type=Object?
|
||||
*/switch (o1) {
|
||||
A(field: 42) as A /*space=??*/=> 0,
|
||||
A(field: 42) as A /*cfe.space=A(field: IntConstant(42))*//*analyzer.space=A(field: int (42))*/=> 0,
|
||||
_ /*space=()*/=> 1
|
||||
};
|
||||
|
||||
|
@ -46,6 +53,26 @@ restrictedCase(o1, o2) {
|
|||
subtypes={Object,Null},
|
||||
type=Object?
|
||||
*/switch (o2) {
|
||||
A(field: 42) as A /*space=??*/=> 0,
|
||||
A(field: 42) as A /*cfe.space=A(field: IntConstant(42))*//*analyzer.space=A(field: int (42))*/=> 0,
|
||||
};
|
||||
}
|
||||
|
||||
sealedCast(B b1, B b2) {
|
||||
/*
|
||||
fields={hashCode:int,runtimeType:Type},
|
||||
subtypes={C,D,E},
|
||||
type=B
|
||||
*/switch (b1) {
|
||||
/*space=C*/case C():
|
||||
/*space=()*/case _ as D:
|
||||
}
|
||||
/*
|
||||
error=non-exhaustive:E,
|
||||
fields={hashCode:int,runtimeType:Type},
|
||||
subtypes={C,D,E},
|
||||
type=B
|
||||
*/switch (b2) {
|
||||
/*space=D*/case D():
|
||||
/*space=C*/case var c as C:
|
||||
}
|
||||
}
|
|
@ -381,12 +381,12 @@ class PatternConverter {
|
|||
} else if (pattern is NullAssertPattern) {
|
||||
Space space = convertPattern(pattern.pattern, nonNull: true, path: path);
|
||||
return space.union(Space(path, StaticType.nullType));
|
||||
} else if (pattern is CastPattern ||
|
||||
pattern is RelationalPattern ||
|
||||
pattern is LogicalAndPattern) {
|
||||
} else if (pattern is CastPattern) {
|
||||
// TODO(johnniwinther): Handle types (sibling sealed types?) implicitly
|
||||
// handled by the throw of the invalid cast.
|
||||
return convertPattern(pattern.pattern, nonNull: nonNull, path: path);
|
||||
} else if (pattern is RelationalPattern || pattern is LogicalAndPattern) {
|
||||
// These pattern do not add to the exhaustiveness coverage.
|
||||
// TODO(johnniwinther): Handle `Null` aspect implicitly covered by
|
||||
// [NullAssertPattern] and `as Null`.
|
||||
// TODO(johnniwinther): Handle top in [AndPattern] branches.
|
||||
return Space(path, cache.getUnknownStaticType());
|
||||
} else if (pattern is ListPattern || pattern is MapPattern) {
|
||||
|
|
|
@ -480,8 +480,12 @@ Space convertPatternToSpace(CfeExhaustivenessCache cache, Pattern pattern,
|
|||
cache, pattern.pattern, constants, context,
|
||||
nonNull: true, path: path);
|
||||
return space.union(new Space(path, StaticType.nullType));
|
||||
} else if (pattern is CastPattern ||
|
||||
pattern is InvalidPattern ||
|
||||
} else if (pattern is CastPattern) {
|
||||
// TODO(johnniwinther): Handle types (sibling sealed types?) implicitly
|
||||
// handled by the throw of the invalid cast.
|
||||
return convertPatternToSpace(cache, pattern.pattern, constants, context,
|
||||
nonNull: nonNull, path: path);
|
||||
} else if (pattern is InvalidPattern ||
|
||||
pattern is RelationalPattern ||
|
||||
pattern is AndPattern) {
|
||||
// These pattern do not add to the exhaustiveness coverage.
|
||||
|
|
Loading…
Reference in a new issue