Repository: flutter
Issue: [go_router] Using GoRouter.routingConfig and switch between StatefulShellRoute and GoRoute will cause type error
Labels: c: crash,package,has reproducible steps,P2,p: go_router,team-go_router,found in release: 3.24

### Steps to reproduce

Reproducible in go_router `14.2.3`

In mobile device, we use bottom nav bar, something like:

```dart
final mobileConfig = RoutingConfig(routes: [
  StatefulShellRoute.indexedStack(
    builder: builder,
    branches: [
      StatefulShellBranch(routes: [GoRoute(path: '/', builder: mainBuilder)]),
      StatefulShellBranch(routes: [GoRoute(path: '/route1', builder: route1Builder)]),
      StatefulShellBranch(routes: [GoRoute(path: '/route2', builder: route2Builder)]),
      StatefulShellBranch(routes: [GoRoute(path: '/others', builder: othersBuilder)]),
    ],
  ),
  GoRoute(name: 'route3', path: '/route3', builder: route3Builder),
  GoRoute(path: '/route4', builder: route4Builder),
  GoRoute(path: '/route4', builder: route5Builder),
]);
```

In desktop device, we use rail, which allow more branches:

```dart
final desktopConfig = RoutingConfig(routes: [
  StatefulShellRoute.indexedStack(
    builder: builder,
    branches: [
      StatefulShellBranch(routes: [GoRoute(path: '/', builder: mainBuilder)]),
      StatefulShellBranch(routes: [GoRoute(path: '/route1', builder: route1Builder)]),
      StatefulShellBranch(routes: [GoRoute(path: '/route2', builder: route2Builder)]),
      StatefulShellBranch(routes: [GoRoute(name: 'route3', path: '/route3', builder: route3Builder)]),
      StatefulShellBranch(routes: [GoRoute(path: '/route4', builder: route4Builder)]),
      StatefulShellBranch(routes: [GoRoute(path: '/route5', builder: route5Builder)]),
    ],
  ),
]);
```

When we monitor device width and change the routing config from `mobileConfig` to `desktopConfig`, it will cause error:

```
type 'ShellRouteMatch' is not a subtype of type 'RouteMatch' of 'value'
```

1. First use `mobileConfig` by setting device to portrait
2. Nav to `/others`
3. Press button to execute `context.pushNamed('route3')`
4. Turn the device to landscape
5. Error show up

### Expected results

Still stay in `/route5` without any error.

### Actual results

Throw the error and stop changing route config:

```
════════ Exception caught by foundation library ════════════════════════════════
The following _TypeError was thrown while dispatching notifications for ValueNotifier<RoutingConfig>:
type 'ShellRouteMatch' is not a subtype of type 'RouteMatch' of 'value'

When the exception was thrown, this was the stack:
#0      List.add (dart:core-patch/growable_array.dart:277:14)
growable_array.dart:277
#1      RouteMatchList._createNewMatchUntilIncompatible (package:go_router/src/match.dart:623:10)
match.dart:623
#2      RouteMatchList.push (package:go_router/src/match.dart:593:16)
match.dart:593
#3      RouteConfiguration.reparse (package:go_router/src/configuration.dart:328:23)
configuration.dart:328
#4      GoRouter._handleRoutingConfigChanged (package:go_router/src/router.dart:298:27)
router.dart:298
#5      ChangeNotifier.notifyListeners (package:flutter/src/foundation/change_notifier.dart:433:24)
change_notifier.dart:433
#6      ValueNotifier.value= (package:flutter/src/foundation/change_notifier.dart:555:5)
change_notifier.dart:555
#7      App.build (package:example/app.dart:30:20)
app.dart:30
#8      StatelessElement.build (package:flutter/src/widgets/framework.dart:5557:49)
framework.dart:5557
#9      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5487:15)
framework.dart:5487
#10     Element.rebuild (package:flutter/src/widgets/framework.dart:5203:7)
framework.dart:5203
#11     BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2905:19)
framework.dart:2905
#12     WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:1136:21)
binding.dart:1136
#13     RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:443:5)
binding.dart:443
#14     SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1392:15)
binding.dart:1392
#15     SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1313:9)
binding.dart:1313
#16     SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1171:5)
binding.dart:1171
#20     _invoke (dart:ui/hooks.dart:314:10)
hooks.dart:314
#21     PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:419:5)
platform_dispatcher.dart:419
#22     _drawFrame (dart:ui/hooks.dart:283:31)
hooks.dart:283
(elided 3 frames from dart:async)

The ValueNotifier<RoutingConfig> sending notification was: ValueNotifier<RoutingConfig>#ac657(Instance of 'RoutingConfig')
════════════════════════════════════════════════════════════════════════════════
```

### Code sample

<details open><summary>Code sample</summary>

```dart
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

void main() {
  runApp(const Example());
}

class Example extends StatelessWidget {
  static final routingConfig = ValueNotifier<RoutingConfig>(mobileConfig);
  static final routerConfig = GoRouter.routingConfig(routingConfig: routingConfig);

  const Example({super.key});

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraint) {
        routingConfig.value = constraint.maxWidth < 600 ? mobileConfig : desktopConfig;
        return MaterialApp.router(
          routerConfig: routerConfig,
        );
      },
    );
  }
}

Widget builder(BuildContext context, GoRouterState state, StatefulNavigationShell shell) {
  final size = Example.routingConfig.value == mobileConfig ? 4 : 6;
  return Scaffold(
    bottomNavigationBar: NavigationBar(
      selectedIndex: shell.currentIndex,
      onDestinationSelected: (index) => shell.goBranch(index),
      destinations: [
        for (int index = 0; index < size; index++)
          NavigationDestination(
            icon: const Icon(Icons.abc),
            label: '$index',
          ),
      ],
    ),
    body: Center(child: shell),
  );
}

final mobileConfig = RoutingConfig(routes: [
  StatefulShellRoute.indexedStack(
    builder: builder,
    branches: [
      StatefulShellBranch(routes: [GoRoute(path: '/', builder: createBuilder('main'))]),
      StatefulShellBranch(routes: [GoRoute(path: '/route1', builder: createBuilder('route1'))]),
      StatefulShellBranch(routes: [GoRoute(path: '/route2', builder: createBuilder('route2'))]),
      StatefulShellBranch(routes: [
        GoRoute(
          path: '/others',
          builder: (ctx, state) => Scaffold(
            body: Column(children: [
              ElevatedButton(
                onPressed: () => ctx.pushNamed('route4'),
                child: const Text('Go to route4'),
              ),
              ElevatedButton(
                onPressed: () => ctx.pushNamed('route4'),
                child: const Text('Go to route5'),
              ),
            ]),
          ),
        ),
      ]),
    ],
  ),
  GoRoute(name: 'route3', path: '/route3', builder: createBuilder('route3')),
  GoRoute(name: 'route4', path: '/route4', builder: createBuilder('route4')),
  GoRoute(name: 'route5', path: '/route5', builder: createBuilder('route5')),
]);
final desktopConfig = RoutingConfig(routes: [
  StatefulShellRoute.indexedStack(
    builder: builder,
    branches: [
      StatefulShellBranch(routes: [GoRoute(path: '/', builder: createBuilder('main'))]),
      StatefulShellBranch(routes: [GoRoute(path: '/route1', builder: createBuilder('route1'))]),
      StatefulShellBranch(routes: [GoRoute(path: '/route2', builder: createBuilder('route2'))]),
      StatefulShellBranch(routes: [GoRoute(name: 'route3', path: '/route3', builder: createBuilder('route3'))]),
      StatefulShellBranch(routes: [GoRoute(name: 'route4', path: '/route4', builder: createBuilder('route4'))]),
      StatefulShellBranch(routes: [GoRoute(name: 'route5', path: '/route5', builder: createBuilder('route5'))]),
    ],
  ),
]);

Widget Function(BuildContext, GoRouterState) createBuilder(String name) {
  return (ctx, state) => Material(child: Center(child: Text(name)));
}
```

</details>


### Screenshots or Video

<details open>
<summary>Screenshots / Video demonstration</summary>

[Upload media here]

</details>


### Logs

<details open><summary>Logs</summary>

```console
[Paste your logs here]
```

</details>


### Flutter Doctor output

<details open><summary>Doctor output</summary>

```console
flutter doctor -v                             Sun Aug 11 10:36:21 2024
[✓] Flutter (Channel stable, 3.22.1, on macOS 14.6.1 23G93 darwin-arm64, locale en-TW)
    • Flutter version 3.22.1 on channel stable at /Users/evan.lu/Development/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision a14f74ff3a (3 months ago), 2024-05-22 11:08:21 -0500
    • Engine revision 55eae6864b
    • Dart version 3.4.1
    • DevTools version 2.34.3

[!] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
    • Android SDK at /Users/evan.lu/Library/Android/sdk
    ✗ cmdline-tools component is missing
      Run `path/to/sdkmanager --install "cmdline-tools;latest"`
      See https://developer.android.com/studio/command-line for more details.
    ✗ Android license status unknown.
      Run `flutter doctor --android-licenses` to accept the SDK licenses.
      See https://flutter.dev/docs/get-started/install/macos#android-setup for more details.

[✗] Xcode - develop for iOS and macOS
    ✗ Xcode installation is incomplete; a full installation is necessary for iOS and macOS development.
      Download at: https://developer.apple.com/xcode/
      Or install Xcode via the App Store.
      Once installed, run:
        sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer
        sudo xcodebuild -runFirstLaunch
    ✗ CocoaPods not installed.
        CocoaPods is used to retrieve the iOS and macOS platform side's plugin code that responds to your plugin
        usage on the Dart side.
        Without CocoaPods, plugins will not work on iOS or macOS.
        For more info, see https://flutter.dev/platform-plugins
      To install see https://guides.cocoapods.org/using/getting-started.html#installation for instructions.

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2023.2)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 17.0.9+0-17.0.9b1087.7-11185874)

[✓] VS Code (version 1.92.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.94.0

[✓] Connected device (3 available)
    • sdk gphone64 arm64 (mobile) • emulator-5554 • android-arm64  • Android 14 (API 34) (emulator)
    • macOS (desktop)             • macos         • darwin-arm64   • macOS 14.6.1 23G93 darwin-arm64
    • Chrome (web)                • chrome        • web-javascript • Google Chrome 127.0.6533.100

[✓] Network resources
    • All expected network resources are available.
```

</details>