-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
await futureOr
may return a Future when the generic is Object
#54311
Comments
This is a somewhat twisted corner of the language, and it does indeed show an issue with a type function called The async function The intuition is that the future value type is the "real" returned value for an async function, that is, the kind of object that you will receive by awaiting the In other words, if the async function returns So the invocation of [Edit: I tried out the program on the command line, and Just to finish the story about what should have happened, assume that it returns a The return statement in (We do get that behavior if the return type of So the conclusion is that |
@chloestefantsova, @johnniwinther, WDYT? |
It fails too with this simpler code: import 'dart:async';
void main() async {
final value = await fn();
print(value);
}
FutureOr<Object> fn() async => 42; But not with: import 'dart:async';
void main() async {
final value = await fn();
print(value);
}
Future<Object> fn() async => 42; I can suppose that Dart coders would expect same behaviour on both cases. (This is in line with what @eernstg said) |
Interesting, @busslina! Clearly the return type |
The most likely reason is that the "future value type" uses the old unsafe approach, and becomes |
The CFE generates the right "runtimeCheckType":
|
@johnniwinther just checked the generated code, and it does contain the expected future value type. It looks like there's a need to double check what the backends are doing. I'm creating issues for that. Subtasks: |
The
A quick check shows that the context type of the return type of return expressions is correct: import "dart:async";
void main() {
printType(foo(1));
printType(o(1));
}
String lastName = "";
Object o(Object? value) async {
lastName = "Object";
return captureContext(value);
}
FutureOr<Object> foo(Object? value) async {
lastName = "FutureOr<Object>";
return captureContext(value);
}
Type lastContext = Null;
T captureContext<T>(Object? o) {
lastContext = T;
// print("Context type: $T");
return o as T;
}
void printType<T>(T value) {
// Prints value, runtime type and static type captured in type variable.
print("$lastName: $value");
print(" RuntimeType: ${value.runtimeType}");
print(" Static type: $T");
print(" Async context type: $lastContext");
}
(Run with dart2js in DartPad, any branch.) The However, the returned future is a My hunch is that the code re-computes the future-value-type, instead of using the type provided by the CFE and used for the return statements, but does so on a normalized (by Norm) return type. The normalization of But it's suspicious that it's consistent across implementations. (@johnniwinther Are we sure the type of future created is not provided by the CFE?). |
True, it's the
@johnniwinther and I discussed this IRL, and I didn't notice that the Kernel code shown so far only contained the One possible explanation would be that the magic comment |
FWIW, the fix to dart2js is landing here. Outside of an experimental/disabled kernel transformation, dart2js simply never used the |
If we had normalized |
@lrhn: You mentioned that there are other functions which must operate on non-normalized types. Is this list documented anywhere? It's been convenient for us to eagerly normalize types at construction in our internal representations, but we may have to rethink this design. |
There is no list. I don't know where it matters, but generally anything in the language semantics is defined in terms of un-normalized types unless it explicitly says otherwise. All the type functions, Up, flatten, the subtype relation itself, etc., assumes that the input can be non-normalized. And some uses of them require it. Or at least this one. The place I can remember that normalization is mentioned is Since any type is a mutual subtype with its normalization, any rules based entirely on subtyping shouldn't be affected by normalization. On the other hand, any place where a type is special-cased independently of subtyping, it's important to not normalize. That includes:
These are the two most special-cased types, and their interaction with union types is where we can most see the effect. Generally we seem to eagerly remove That's why this problem comes from I don't think flatten has the same issue, because we've designed it to give the same result before and after normalization. (If we hadn't, and had used the same principle as for future-value-type, flatten( So if there are other cases, then they're likely around (All of this from memory, on my phone. I can take a closer look tomorrow.) |
Hi, i have a small question. Future<int> fn() async() {
return Future<int>.value(42);
}
I felt something wrong here, since the actual return type of fn() would (needs to) be but its being resolved to Future. Is that expected? |
Yes, that is currently specified behavior. Making that no longer be the case is dart-lang/language#870, which we hope to get done eventually. |
Well, this issue may solved by this dart-lang/language#870 ? |
…c change Calculation of element type for the value returned from async/async*/sync* functions was recently adjusted in the spec to address soundness issue (dart-lang/language#3218). This change adjusts Dart VM to conform to the new spec. TEST=language/async/regression_54311_test TEST=co19/Language/Functions/element_type_* Fixes #54316 Issue #54311 Issue #54159 Change-Id: I4c51e7cba704d034350519375210bdb2086c5432 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/342082 Reviewed-by: Alexander Aprelev <aam@google.com> Reviewed-by: Erik Ernst <eernst@google.com> Commit-Queue: Alexander Markov <alexmarkov@google.com>
I think this is fixed here So can be closed? |
No, dart-lang/language#870 makes it an error to have This issue is about the actual type of future which is being returned when an |
#54318 is still marked as open, that is, DDC still needs to be updated. |
You are right @eernstg |
Right, 6b12473 is a VM update that targets this spec change. |
(closing now that the DDC issue is also closed) |
Consider the following code:
This should print
42
but actually printsInstance of '_Future<dynamic>'
Returning anything other than
FutureOr<Object>
infn
fixes the issue. This includes changingObject
toint
.The text was updated successfully, but these errors were encountered: