mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 10:49:00 +00:00
[_fe_analyzer_shared] Improve exhaustiveness for null-assert
This improves the exhaustiveness handling for null assert patterns by extending the space of the subpattern with the null space. This reflects the fact that null assert will throw on `null` and can therefore be considered to cover that case. Change-Id: If344eaaa55dcc70474f45519b53586e7d36e6e80 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/286400 Commit-Queue: Johnni Winther <johnniwinther@google.com> Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
parent
8dbf923e89
commit
2a746cb51f
3 changed files with 120 additions and 11 deletions
|
@ -8,23 +8,29 @@ class A {
|
|||
A(this.field);
|
||||
}
|
||||
|
||||
sealed class B {}
|
||||
class C extends B {}
|
||||
class D extends B {}
|
||||
|
||||
simpleAssert(o1, o2) {
|
||||
var a = /*
|
||||
fields={},
|
||||
subtypes={Object,Null},
|
||||
type=Object?
|
||||
*/switch (o1) {
|
||||
_! /*space=??*/=> 0,
|
||||
_ /*space=()*/=> 1
|
||||
_! /*space=()*/=> 0,
|
||||
_ /*
|
||||
error=unreachable,
|
||||
space=()
|
||||
*/=> 1
|
||||
};
|
||||
|
||||
var b = /*
|
||||
error=non-exhaustive:Object,
|
||||
fields={},
|
||||
subtypes={Object,Null},
|
||||
type=Object?
|
||||
*/switch (o2) {
|
||||
_! /*space=??*/=> 0,
|
||||
_! /*space=()*/=> 0,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -36,7 +42,7 @@ restrictedCase(o1, o2) {
|
|||
subtypes={Object,Null},
|
||||
type=Object?
|
||||
*/switch (o1) {
|
||||
A(field: 42)! /*space=??*/=> 0,
|
||||
A(field: 42)! /*cfe.space=A(field: IntConstant(42))|Null*//*analyzer.space=A(field: int (42))|Null*/=> 0,
|
||||
_ /*space=()*/=> 1
|
||||
};
|
||||
|
||||
|
@ -46,6 +52,103 @@ restrictedCase(o1, o2) {
|
|||
subtypes={Object,Null},
|
||||
type=Object?
|
||||
*/switch (o2) {
|
||||
A(field: 42)! /*space=??*/=> 0,
|
||||
A(field: 42)! /*cfe.space=A(field: IntConstant(42))|Null*//*analyzer.space=A(field: int (42))|Null*/=> 0,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
nullableBool(bool? b1, bool? b2) {
|
||||
/*
|
||||
expandedSubtypes={true,false,Null},
|
||||
fields={},
|
||||
subtypes={bool,Null},
|
||||
type=bool?
|
||||
*/
|
||||
switch (b1) {
|
||||
/*space=true?*/
|
||||
case true!:
|
||||
break;
|
||||
/*space=false*/
|
||||
case false:
|
||||
break;
|
||||
}
|
||||
/*
|
||||
error=non-exhaustive:false,
|
||||
expandedSubtypes={true,false,Null},
|
||||
fields={},
|
||||
subtypes={bool,Null},
|
||||
type=bool?
|
||||
*/
|
||||
switch (b2) {
|
||||
/*space=true?*/
|
||||
case true!:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
nullableA(A? a1, A? a2, A? a3) {
|
||||
var a = /*
|
||||
fields={},
|
||||
subtypes={A,Null},
|
||||
type=A?
|
||||
*/switch (a1) {
|
||||
A()! /*space=A?*/=> 0,
|
||||
};
|
||||
var b = /*
|
||||
fields={},
|
||||
subtypes={A,Null},
|
||||
type=A?
|
||||
*/switch (a2) {
|
||||
A(:var field)! /*space=A(field: int)|Null*/=> 0,
|
||||
};
|
||||
var c = /*
|
||||
error=non-exhaustive:A(field: int),
|
||||
fields={},
|
||||
subtypes={A,Null},
|
||||
type=A?
|
||||
*/switch (a3) {
|
||||
A(field: 42)!
|
||||
/*cfe.space=A(field: IntConstant(42))|Null*/
|
||||
/*analyzer.space=A(field: int (42))|Null*/
|
||||
=> 0,
|
||||
};
|
||||
}
|
||||
|
||||
nullableB(B? b1, B? b2, B? b3) {
|
||||
/*
|
||||
expandedSubtypes={C,D,Null},
|
||||
fields={},
|
||||
subtypes={B,Null},
|
||||
type=B?
|
||||
*/
|
||||
switch (b1) {
|
||||
/*space=B?*/
|
||||
case B()!:
|
||||
break;
|
||||
}
|
||||
/*
|
||||
expandedSubtypes={C,D,Null},
|
||||
fields={},
|
||||
subtypes={B,Null},
|
||||
type=B?
|
||||
*/
|
||||
switch (b2) {
|
||||
/*space=C?*/
|
||||
case C()!:
|
||||
break;
|
||||
/*space=D*/
|
||||
case D():
|
||||
break;
|
||||
}
|
||||
/*
|
||||
error=non-exhaustive:D,
|
||||
expandedSubtypes={C,D,Null},
|
||||
fields={},
|
||||
subtypes={B,Null},
|
||||
type=B?
|
||||
*/
|
||||
switch (b3) {
|
||||
/*space=C?*/
|
||||
case C()!:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -380,8 +380,10 @@ class PatternConverter {
|
|||
return convertPattern(pattern.pattern, nonNull: true);
|
||||
} else if (pattern is ParenthesizedPattern) {
|
||||
return convertPattern(pattern.pattern, nonNull: nonNull);
|
||||
} else if (pattern is NullAssertPattern ||
|
||||
pattern is CastPattern ||
|
||||
} else if (pattern is NullAssertPattern) {
|
||||
Space space = convertPattern(pattern.pattern, nonNull: true);
|
||||
return Space.union([space, Space.nullSpace]);
|
||||
} else if (pattern is CastPattern ||
|
||||
pattern is RelationalPattern ||
|
||||
pattern is LogicalAndPattern) {
|
||||
// These pattern do not add to the exhaustiveness coverage.
|
||||
|
|
|
@ -473,8 +473,12 @@ Space convertPatternToSpace(CfeExhaustivenessCache cache, Pattern pattern,
|
|||
} else if (pattern is NullCheckPattern) {
|
||||
return convertPatternToSpace(cache, pattern.pattern, constants, context,
|
||||
nonNull: true);
|
||||
} else if (pattern is NullAssertPattern ||
|
||||
pattern is CastPattern ||
|
||||
} else if (pattern is NullAssertPattern) {
|
||||
Space space = convertPatternToSpace(
|
||||
cache, pattern.pattern, constants, context,
|
||||
nonNull: true);
|
||||
return new Space.union([space, Space.nullSpace]);
|
||||
} else if (pattern is CastPattern ||
|
||||
pattern is InvalidPattern ||
|
||||
pattern is RelationalPattern ||
|
||||
pattern is AndPattern) {
|
||||
|
|
Loading…
Reference in a new issue