Comments (5)
This is definitely a bug. That code should not compile.
The return type of _PerformerImpl.perform
is (String id, Future<void> completion)
, inherited from the super interface.
The function itself is async
, so it should be a compile time error to have a return type that Future
is not assignable to.
from sdk.
What is even more interesting is this.
Consider changing main to:
void main(List<String> args) async {
final Performer performer = _PerformerImpl();
final result = performer.perform();
final (id, future) = result;
print('id: ${id}');
print('id: ${id.runtimeType}');
print('future: ${future.runtimeType}');
print('result: ${result.runtimeType}');
if (id.length < 10) {
print(id);
}
await future;
}
it prints:
id: 8
id: int
future: _RootZone
result: Future<Object?>
Unhandled exception:
NoSuchMethodError: Class 'int' has no instance getter 'length'.
Receiver: 8
Tried calling: length
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:38:5)
#1 main
invalid_destruction.dart:11
#2 _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:295:33)
#3 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)
However, if I change:
final (id, future) = result;
to
final (id, future) = result as dynamic;
The error I get is:
Unhandled exception:
type 'Future<Object?>' is not a subtype of type '(dynamic, dynamic)'
#0 main
invalid_destruction.dart:5
#1 _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:295:33)
#2 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)
from sdk.
The following example also brought interesting results:
void main(List<String> args) async {
final Performer performer = _PerformerImpl();
final result = performer.perform();
final ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) = result;
print($1);
print($1.runtimeType);
print($2.runtimeType);
print($3.runtimeType);
print($4.runtimeType);
print($5.runtimeType);
print($6.runtimeType);
print($7.runtimeType);
print($8.runtimeType);
print($9.runtimeType);
print($10.runtimeType);
print($11.runtimeType);
print(result.runtimeType);
if ($1.length < 10) {
print($1);
}
await $2;
}
abstract interface class Performer {
(
String,
String,
String,
String,
String,
String,
String,
String,
String,
String,
String,
) perform();
}
class _PerformerImpl implements Performer {
perform() async {
return ('id1', 'id2');
}
}
Output:
8
int
_RootZone
(String, String)
Null
int
int
String
String
int
Null
int
Future<Object?>
Unhandled exception:
NoSuchMethodError: Class 'int' has no instance getter 'length'.
Receiver: 8
Tried calling: length
from sdk.
Interestingly, as well:
void main(List<String> args) async {
final Performer performer = _PerformerImpl();
final result = performer.perform();
final (:v1, :v2) = result;
print(v1.runtimeType);
print(v2.runtimeType);
print(result.runtimeType);
}
abstract interface class Performer {
({
String v1,
String v2,
}) perform();
}
class _PerformerImpl implements Performer {
perform() async {
return (value: 'v1', value2: 'v2');
}
}
Executes with the destructed record in main having values even though no such property is ever returned.
On the other hand, doing:
void main(List<String> args) async {
final Performer performer = _PerformerImpl();
final result = performer.perform();
final Value(:value) = result;
print(value.runtimeType);
print(result.runtimeType);
}
abstract interface class Performer {
Value<String> perform();
}
class _PerformerImpl implements Performer {
perform() async {
return const Value(value: 'id');
}
}
class Value<T> {
final T value;
const Value({
required this.value,
});
}
Errors at destruction because the returned Future
is not a Value
.
from sdk.
It seems the compiler trusts the type, and uses unchecked "get first instance variable value" and "get second instance variable value" operations to get the (presumed) first and second positional field of the record.
It just happens to be a _Future
object, not a record, so the first field is an integer state and the second is the zone the future belongs to.
A state of "8" means completed with a value. If there had been a third field, you would likely see the value there, which is indeed what the 11-field version shows. (Then it reads past the end of the object, which is very concerning.)
When using named fields, the result is the same, because optimized record code can statically translate names to instance variable positions.
On the web, the behavior is different (it tries reading $1
which doesn't exist), but the code is still allowed.
from sdk.
Related Issues (20)
- [CFE] Add implicit "return null" to AST if function end is reachable according to Dart language flow analysis
- `Swap with parent/child` assist should work on single-child `Flex`
- avoid_init_to_null fix of late initialize causes runtime errors HOT 1
- [dart2wasm] iFrame locks position on transition into view HOT 4
- [CP] [vm/ffi] Fix variadic arguments on MacOS Arm64 HOT 2
- analyzer plugins do not reanalyze non-Dart files when they are modified HOT 7
- `dart fix` output case inconsistency HOT 1
- Import `new_library` assist should auto-remove unecessary import HOT 2
- Add more context to `not_a_type` diagnostics
- Dart2Wasm compiler fails building when dart:ffi library is conditionally imported HOT 4
- [Null-aware elements] [meta] Null-aware elements implementation
- [resource_identifiers] `UsageQueryable` proposal HOT 4
- Possible index error in _processExpressionCompilationRequest
- Different async timing whether using vm, node, dart2js and dart2wasm HOT 3
- Macros: Expose doc comments of a declaration
- [Null-aware elements] Implement parser changes
- [Null-aware elements] CFE Implementation
- Make analysis server/IDEs show the distinction between fields and getters accurately and consistently
- The return type 'String' isn't a 'String', as required by the closure's context HOT 2
- Flaky coverage/package:front_end/src/fasta/type_inference/inference_visitor_base.dart on front-end-linux-release-x64-try
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from sdk.