Closed huanghui1998hhh closed 2 months ago
Summary: The user is experiencing a "RuntimeError: unreachable" in their Flutter app when tapping the "Go back" button on the SecondScreen
. This error occurs during the gesture recognition process, specifically when handling a tap event.
/cc @osa1 Could you have a look at this?
I've been debugging this. The unreachable is actually an illegal cast that wasm-opt converts into an unreachable. Somehow we pass a Closure-0-1
(a closure that expects no type arguments, one positional argument, and no named arguments) to an _InkResponseStateWidget.onTap
field which expects Closure-0-0
.
Because Closure-0-1
is a subtype of Closure-0-0
(I don't remember why this is, is this necessary?) this doesn't cause Wasm validation issues but it fails in runtime when we try to use Closure-0-1
as Closure-0-0
.
Relevant closure and vtable types:
(type $#Closure-0-0 (;833;) (sub $#ClosureBase (struct
(field $field0 i32)
(field $field1 (mut i32))
(field $field2 (mut (ref struct)))
(field $field3 (ref $#Vtable-0-0))
(field $field4 (ref $_FunctionType)))))
(type $#Closure-0-1 (;834;) (sub $#Closure-0-0 (struct
(field $field0 i32)
(field $field1 (mut i32))
(field $field2 (mut (ref struct)))
(field $field3 (ref $#Vtable-0-1))
(field $field4 (ref $_FunctionType)))))
(type $#Vtable-0-0 (;822;) (sub $#VtableBase (struct (field $field0 (ref $type818)) (field $field1 (ref $type819)))))
(type $#Vtable-0-1 (;826;) (sub $#Vtable-0-0 (struct
(field $field0 (ref $type818))
(field $field1 (ref $type819))
(field $field2 (ref $type820)))))
_InkResponseStateWidget
:
(type $_InkResponseStateWidget (;2371;) (sub final $StatefulWidget (struct
(field $field0 i32)
(field $field1 (mut i32))
(field $key (ref null $Key))
(field $child (ref null $Widget))
(field $onTap (ref null $#Closure-0-0)) ;; <----- we are passing Closure-0-1 here
(field $onTapDown (ref null $#Closure-0-1))
(field $onTapUp (ref null $#Closure-0-1))
(field $onTapCancel (ref null $#Closure-0-0))
(field $onDoubleTap (ref null $#Closure-0-0))
(field $onLongPress (ref null $#Closure-0-0))
(field $onSecondaryTap (ref null $#Closure-0-0))
(field $onSecondaryTapUp (ref null $#Closure-0-1))
(field $onSecondaryTapDown (ref null $#Closure-0-1))
(field $onHighlightChanged (ref null $#Closure-0-1))
(field $onHover (ref null $#Closure-0-1))
(field $mouseCursor (ref null $MouseCursor))
(field $containedInkWell i32)
(field $highlightShape (ref $BoxShape))
(field $radius (ref null $BoxedDouble))
(field $borderRadius (ref null $BorderRadius))
(field $customBorder (ref null $OutlinedBorder))
(field $focusColor (ref null $Color))
(field $hoverColor (ref null $Color))
(field $highlightColor (ref null $Color))
(field $overlayColor (ref null $_WidgetStatePropertyWith))
(field $splashColor (ref null $Color))
(field $splashFactory (ref null $InteractiveInkFeatureFactory))
(field $enableFeedback i32)
(field $excludeFromSemantics i32)
(field $onFocusChange (ref null $#Closure-0-1))
(field $autofocus i32)
(field $focusNode (ref null $FocusNode))
(field $canRequestFocus i32)
(field $parentState (ref null $_InkResponseState))
(field $getRectCallback (ref null $#Closure-0-1))
(field $statesController (ref null $WidgetStatesController))
(field $hoverDuration (ref null $Duration)))))
The problematic closure seems to be coming from this tear-off in user code:
onPressed: Navigator.of(context).pop,
If I replace this with a closure:
onPressed: () => Navigator.of(context).pop(),
Then the crash disappears.
The pop
member has a type argument, so the tear-off is an instantiation closure: https://github.com/flutter/flutter/blob/2ed3dab361a00ed40c5d9dbca3f3383eb231153e/packages/flutter/lib/src/widgets/navigator.dart#L5375-L5376
Explicitly instantiating it with Navigator.of(context).pop<dynamic>
does not fix the crash.
Minimal repro:
class A {
void test<T>([T? x]) {}
}
void main() {
final a = A();
void Function() x = a.test;
x();
}
Output:
wasm-function[771]:0x15c33: RuntimeError: illegal cast
RuntimeError: illegal cast
at #InstantiationTrampoline-1-0 (wasm://wasm/0008aca2:wasm-function[771]:0x15c33)
at main (wasm://wasm/0008aca2:wasm-function[756]:0x15a79)
at main tear-off trampoline (wasm://wasm/0008aca2:wasm-function[758]:0x15a8d)
at _invokeMain (wasm://wasm/0008aca2:wasm-function[67]:0xb9ac)
at Module.invoke (/usr/local/google/home/omersa/dart/sdk/test/test.mjs:323:26)
at main (/usr/local/google/home/omersa/dart/sdk/sdk/pkg/dart2wasm/bin/run_wasm.js:407:21)
at async action (/usr/local/google/home/omersa/dart/sdk/sdk/pkg/dart2wasm/bin/run_wasm.js:350:37)
at async eventLoop (/usr/local/google/home/omersa/dart/sdk/sdk/pkg/dart2wasm/bin/run_wasm.js:327:9)
Thanks for fix ! @osa1
Here is a sample on flutter, the error occurs when tapping "Go back" button on
SecondScreen
My dart version: Dart SDK version: 3.5.0 (stable) (Tue Jul 30 02:17:59 2024 -0700) on "windows_x64"
And here is the log
main.dart.wasm:0x8167b Uncaught RuntimeError: unreachable at #dummy function (:8080/ref struct) -> (ref null #Top) (http://localhost:8080/main.dart.wasm) at _InkResponseState.handleTap (main.dart.wasm:0xebddc) at _InkResponseState.handleTap tear-off trampoline (main.dart.wasm:0xebde9) at GestureRecognizer.invokeCallback (main.dart.wasm:0xe7907) at TapGestureRecognizer.handleTapUp (main.dart.wasm:0xe783e) at BaseTapGestureRecognizer._checkUp (main.dart.wasm:0xe7779) at BaseTapGestureRecognizer.handlePrimaryPointer (main.dart.wasm:0xe8277) at PrimaryPointerGestureRecognizer.handleEvent (main.dart.wasm:0xe8149) at PrimaryPointerGestureRecognizer.handleEvent tear-off trampoline (main.dart.wasm:0xe81ad) at PointerRouter._dispatchEventToRoutes closure at file:///E:/fvm-flutter-cache/versions/stable/packages/flutter/lib/src/gestures/pointer_router.dart:141:26 (main.dart.wasm:0x9bf01) $#dummy function (ref struct) -> (ref null #Top) @ main.dart.wasm:0x8167b $_InkResponseState.handleTap @ main.dart.wasm:0xebddc $_InkResponseState.handleTap tear-off trampoline @ main.dart.wasm:0xebde9 $GestureRecognizer.invokeCallback @ main.dart.wasm:0xe7907 $TapGestureRecognizer.handleTapUp @ main.dart.wasm:0xe783e $BaseTapGestureRecognizer._checkUp @ main.dart.wasm:0xe7779 $BaseTapGestureRecognizer.handlePrimaryPointer @ main.dart.wasm:0xe8277 $PrimaryPointerGestureRecognizer.handleEvent @ main.dart.wasm:0xe8149 $PrimaryPointerGestureRecognizer.handleEvent tear-off trampoline @ main.dart.wasm:0xe81ad $PointerRouter._dispatchEventToRoutes closure at file:///E:/fvm-flutter-cache/versions/stable/packages/flutter/lib/src/gestures/pointer_router.dart:141:26 @ main.dart.wasm:0x9bf01 $closure wrapper at file:///E:/fvm-flutter-cache/versions/stable/packages/flutter/lib/src/gestures/pointer_router.dart:141:26 trampoline @ main.dart.wasm:0x9bf82 $__Map&_HashFieldBase&MapMixin&_HashBase&_OperatorEqualsAndHashCode&_LinkedHashMapMixin.forEach @ main.dart.wasm:0x840c8 $PointerRouter._dispatchEventToRoutes @ main.dart.wasm:0x9be92 $PointerRouter.route @ main.dart.wasm:0x9bdb4 $_WidgetsFlutterBinding&BindingBase&GestureBinding.handleEvent @ main.dart.wasm:0x116ff0 $_WidgetsFlutterBinding&BindingBase&GestureBinding._flushPointerEventQueue @ main.dart.wasm:0x9ba5c $_WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerDataPacket @ main.dart.wasm:0x1366c4 $_WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerDataPacket tear-off trampoline @ main.dart.wasm:0x13673c $invoke1 @ main.dart.wasm:0xa344b $ClickDebouncer._sendToFramework @ main.dart.wasm:0x11474f $ClickDebouncer.onPointerData @ main.dart.wasm:0x13a9d6 $ClickDebouncer.onPointerData tear-off trampoline @ main.dart.wasm:0x13ab54 $_PointerAdapter.setup closure at org-dartlang-sdk:///lib/_engine/engine/pointer_binding.dart:1034:58 @ main.dart.wasm:0x138ca8 $closure wrapper at org-dartlang-sdk:///lib/_engine/engine/pointer_binding.dart:1034:58 trampoline @ main.dart.wasm:0x1395d1 $_PointerAdapter._addPointerEventListener closure at org-dartlang-sdk:///lib/_engine/engine/pointer_binding.dart:936:41 @ main.dart.wasm:0x13b47c $closure wrapper at org-dartlang-sdk:///lib/_engine/engine/pointer_binding.dart:936:41 trampoline @ main.dart.wasm:0x13b4a5 $_BaseAdapter.addEventListener closure loggedHandler at org-dartlang-sdk:///lib/_engine/engine/pointer_binding.dart:518:25 @ main.dart.wasm:0x13b7a0 $closure wrapper at org-dartlang-sdk:///lib/_engine/engine/pointer_binding.dart:518:25 trampoline @ main.dart.wasm:0x13b7ca $_1588 @ main.dart.wasm:0x7d1ec (anonymous) @ main.dart.mjs:219