-
Notifications
You must be signed in to change notification settings - Fork 170
void_checks: Specify individual types which a FutureOr<void> target can accept #2274
Conversation
lib/src/rules/void_checks.dart
Outdated
_futureDynamicType = context.typeProvider.futureDynamicType; | ||
_futureDynamicType = context.typeSystem.leastUpperBound( | ||
context.typeProvider.futureDynamicType, | ||
context.typeProvider.nullType) as InterfaceType; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, if you need this only for FutureOr
, instead use typeProvider.futureOrElement.instantiate
and provide nullabilitySuffix
. LUB
is more expensive.
lib/src/rules/void_checks.dart
Outdated
var futureOrVoidType = | ||
context.typeProvider.futureOrType2(context.typeProvider.voidType); | ||
if (expectedType.isVoid && !isTypeAcceptableWhenExpectingVoid(type) || | ||
expectedType == futureOrVoidType && | ||
!typeSystem.isAssignableTo(type, _futureDynamicType)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you explain the portion of expecting FutureOr<void>
and typeSystem.isAssignableTo(type, _futureDynamicType)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure why futureDynamicType was chosen originally. Seems like a strange choice to me. This fix just makes it so that when Null is used where the expected type is FutureOr<void>
, then the lint rule will not complain "Hey don't assign a Null to FutureOr<void>
.
If I changed this check to "is the type assignable to Future", for example, then it no longer catches a case like:
FutureOr<void> a = 1;
I think because technically this is legal, int
is assignable to FutureOr<void>
, but the lint wishes to call it out as "Don't assign to void."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I don't understand which types we want to allow.
When the return/target type is void
we allow only void
and Null
. BTW, it is already an error, but we also get a lint, which is probably not useful.
// @dart = 2.7
import 'dart:async';
void f(FutureOr<int> a) {
return 0;
}
When the target type is FutureOr<void>
, which types do we want to allow?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the return type of f
in your example were FutureOr<void>
, I think we want to allow:
Future<dynamic>
(tested on line 58),Future<void>
(not tested?),Future<Null>
(not tested?),FutureOr<dynamic>
(not tested?),FutureOr<void>
(line 71),FutureOr<Null>
(newly tested in this PR, line 10)dynamic
(line 72),void
(untested?),Null
(line 73),
and nothing else, I think. Right now the language allows, e.g. an int to be returned where FutureOr<void>
is expected.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we can have this nice exhaustive list of types, I think it would be better to check for it explicitly, like we did for void
, instead of using a more heavy isAssignableTo
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah ha, good point. I've used isTypeAcceptableWhenExpectingVoid to write a isTypeAcceptableWhenExpectingFutureOrVoid.
lib/src/rules/void_checks.dart
Outdated
var futureOrVoidType = | ||
context.typeProvider.futureOrType2(context.typeProvider.voidType); | ||
if (expectedType.isVoid && !isTypeAcceptableWhenExpectingVoid(type) || | ||
expectedType == futureOrVoidType && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems to me that we are doing it the opposite way here - we should not construct FutureOr<void>
and then use ==
so do force the analyzer to deconstruct it again. Instead check isDartAsyncFutureOr
and that the type argument isVoid
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also looked at isTypeAcceptableWhenExpectingVoid
and it seems that it can be improved by recursion instead of repeating the checks for void
and Null
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah I understand. OK fixed both issues.
Description
The type of
() {}
changed toNull Function()
(fromvoid Function()
in Null Safety. The check performed in void_checks must then compare assignability withFuture<dynamic>?
.Fixes dart-lang/sdk#58205