Inconsistent inferred return type of function literal with specialized body #3715
Labels
inference
question
Further information is requested
type-inference
Type inference, issues or improvements
Consider the following program:
This program has an implied expectation that the inferred return type of the function literal is
void
in all four cases (if it isn'tvoid
or some other top type then we'll have a compile-time error).The reason why the function literal return type should be
void
is the following rule from this section:In the context,
R
is the 'imposed return type schema' (which is obtained from the context type of the function literal) andS
is the inferred return type of the function literal. In the example aboveR
isvoid
, and we're computing the value ofS
. The rule cited above says thatS
should bevoid
. This result is applicable to all kinds of function literals (and we don't have a context type whose return type isFutureOr<void>
and hence we can ignore the part between the commas).The motivation for this rule is that this will allow function literals to have the same kind of
void
related sanity checks that a regular function gets. For example:In this example we get a compile-time error indicating that we cannot return 3 from a function whose return type is
void
, at both occurrences ofreturn 3;
.In general, this compile-time error is not required for soundness reasons, it's an opinionated rule that gives developers a heads-up when they write code that seems to imply that a given non-void value (here:
3
) is being returned to someone, but the value will actually (almost certainly) be ignored, because the return type isvoid
. That is considered to be a likely bug, hence the error.For a
sync*
orasync*
function it is an error to declare the return type to bevoid
. This implies that when the inferred return type isvoid
, a compile-time error is reported, and the developer will then know that it is a likely bug to use async*
orasync*
function in that manner, just like they'd encounter a compile-time error if they were to declare a function likevoid f() sync* {...}
.For an
async
function there may or may not be a lint message warning against using the return typevoid
in a declaration of anasync
function. Again, we get the same kind of feedback for the regular function with return typevoid
as we do for the function literal whose context type has return typevoid
.The conclusion so far is that in example 1, the function literal should have the type
void Function()
in all four cases.However, this is not the behavior that we can observe. Here are the adjusted versions of example 1 that are accepted without compile-time errors by the analyzer respectively the CFE:
As we can see, the tools do not use the rule mentioned above to make the inferred return type
void
, they use the kind of return type which is associated with the given kind of function body. However, they do not agree on the type argument.It is in principle a breaking change to change the inferred return type to
void
. However, it is likely to bring out locations in code where something unintended is taking place, so it's arguably "good breakage".So, @dart-lang/language-team, WDYT? Should we change the specification to say that the
sync*
,async
,async*
function literals should have a return type of the formIterable<...>
,Future<...>
, respectivelyStream<...>
? In that case, what's the actual type argument? Alternatively, should we ask the tool teams to infervoid
and report a compile-time error?The text was updated successfully, but these errors were encountered: