[_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:
Johnni Winther 2023-03-03 12:31:26 +00:00 committed by Commit Queue
parent 8dbf923e89
commit 2a746cb51f
3 changed files with 120 additions and 11 deletions

View file

@ -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;
}
}

View file

@ -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.

View file

@ -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) {