Repository: flutter
Issue: MergeSemantics crashes when wrapping a recognizer-containing TextSpan
Labels: c: crash,platform-ios,framework,a: accessibility,a: typography,platform-linux,a: desktop,has reproducible steps,P2,found in release: 3.0,found in release: 3.1,team-framework,triaged-framework

When wrapping a  `RichText` (and its `TextSpan` children) with `MergeSemantics`, a crash will be triggered if one of the `TextSpan`s has a `recognizer` set.


## Steps to Reproduce

Run this:

```dart
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart' as launcher;

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) => MaterialApp(
    home: MyHomePage(title: 'Demo'));
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(widget.title)),
      body: Center(
        child: MergeSemantics(
          child: RichText(
            text: TextSpan(
              style: TextStyle(color: Colors.black87),
              children: <TextSpan>[
                TextSpan(text: 'Visit'),
                TextSpan(
                  text: 'Flutter',
                  style: TextStyle(color: Colors.blue),
                  recognizer: TapGestureRecognizer()
                    ..onTap = () => launcher.launch('https://flutter.dev/'),
                ),
              ],
            ),
          ),
        )
      ),
    );
  }
}

```

## Logs

<!--
      Run your application with `flutter run --verbose` and attach all the
      log output below between the lines with the backticks. If there is an
      exception, please see if the error message includes enough information
      to explain how to solve the issue.
-->

```
flutter: ══╡ EXCEPTION CAUGHT BY SCHEDULER LIBRARY ╞═════════════════════════════════════════════════════════
flutter: The following assertion was thrown during a scheduler callback:
flutter: 'package:flutter/src/semantics/semantics.dart': Failed assertion: line 2607 pos 16: 'node.parent ==
flutter: null || !node.parent.isPartOfNodeMerging || node.isMergedIntoParent': is not true.
flutter:
flutter: Either the assertion indicates an error in the framework itself, or we should provide substantially
flutter: more information in this error message to help you determine and fix the underlying cause.
flutter: In either case, please report this assertion by filing a bug on GitHub:
flutter:   https://github.com/flutter/flutter/issues/new?template=BUG.md
flutter:
flutter: When the exception was thrown, this was the stack:
flutter: #2      SemanticsOwner.sendSemanticsUpdate 
package:flutter/…/semantics/semantics.dart:2607
flutter: #3      PipelineOwner.flushSemantics 
package:flutter/…/rendering/object.dart:1039
flutter: #4      RendererBinding.drawFrame 
package:flutter/…/rendering/binding.dart:344
flutter: #5      WidgetsBinding.drawFrame 
package:flutter/…/widgets/binding.dart:776
flutter: #6      RendererBinding._handlePersistentFrameCallback 
package:flutter/…/rendering/binding.dart:279
flutter: #7      SchedulerBinding._invokeFrameCallback 
package:flutter/…/scheduler/binding.dart:1040
flutter: #8      SchedulerBinding.handleDrawFrame 
package:flutter/…/scheduler/binding.dart:982
flutter: #9      SchedulerBinding.scheduleWarmUpFrame.<anonymous closure> 
package:flutter/…/scheduler/binding.dart:791
flutter: #18     _Timer._runTimers  (dart:isolate-patch/timer_impl.dart:382:19)
flutter: #19     _Timer._handleMessage  (dart:isolate-patch/timer_impl.dart:416:5)
flutter: #20     _RawReceivePortImpl._handleMessage  (dart:isolate-patch/isolate_patch.dart:172:12)
flutter: (elided 10 frames from class _AssertionError, package dart:async, and package dart:async-patch)
flutter: ════════════════════════════════════════════════════════════════════════════════════════════════════
[VERBOSE-2:ui_dart_state.cc(148)] Unhandled Exception: Bad state: Future already completed
#0      _AsyncCompleter.complete  (dart:async/future_impl.dart:39:31)
#1      WidgetsBinding.drawFrame.<anonymous closure> 
package:flutter/…/widgets/binding.dart:769
#2      _rootRunUnary  (dart:async/zone.dart:1136:13)
#3      _CustomZone.runUnary  (dart:async/zone.dart:1029:19)
#4      _CustomZone.runUnaryGuarded  (dart:async/zone.dart:931:7)
#5      _invoke1  (dart:ui/hooks.dart:265:10)
#6      _reportTimings  (dart:ui/hooks.dart:203:3)
[VERBOSE-2:ui_dart_state.cc(148)] Unhandled Exception: Bad state: Future already completed
#0      _AsyncCompleter.complete  (dart:async/future_impl.dart:39:31)
#1      WidgetsBinding.drawFrame.<anonymous closure> 
package:flutter/…/widgets/binding.dart:769
#2      _rootRunUnary  (dart:async/zone.dart:1136:13)
#3      _CustomZone.runUnary  (dart:async/zone.dart:1029:19)
#4      _CustomZone.runUnaryGuarded  (dart:async/zone.dart:931:7)
#5      _invoke1  (dart:ui/hooks.dart:265:10)
#6      _reportTimings  (dart:ui/hooks.dart:203:3)

════════ Exception caught by scheduler library ═════════════════════════════════
The following assertion was thrown during a scheduler callback:
'package:flutter/src/semantics/semantics.dart': Failed assertion: line 2607 pos 16: 'node.parent == null || !node.parent.isPartOfNodeMerging || node.isMergedIntoParent': is not true.


Either the assertion indicates an error in the framework itself, or we should provide substantially more information in this error message to help you determine and fix the underlying cause.
In either case, please report this assertion by filing a bug on GitHub:
  https://github.com/flutter/flutter/issues/new?template=BUG.md

When the exception was thrown, this was the stack
#2      SemanticsOwner.sendSemanticsUpdate 
package:flutter/…/semantics/semantics.dart:2607
#3      PipelineOwner.flushSemantics 
package:flutter/…/rendering/object.dart:1039
#4      RendererBinding.drawFrame 
package:flutter/…/rendering/binding.dart:344
#5      WidgetsBinding.drawFrame 
package:flutter/…/widgets/binding.dart:776
#6      RendererBinding._handlePersistentFrameCallback 
package:flutter/…/rendering/binding.dart:279
...
════════════════════════════════════════════════════════════════════════════════

════════ Exception caught by scheduler library ═════════════════════════════════
The following assertion was thrown during a scheduler callback:
'package:flutter/src/semantics/semantics.dart': Failed assertion: line 2607 pos 16: 'node.parent == null || !node.parent.isPartOfNodeMerging || node.isMergedIntoParent': is not true.


Either the assertion indicates an error in the framework itself, or we should provide substantially more information in this error message to help you determine and fix the underlying cause.
In either case, please report this assertion by filing a bug on GitHub:
  https://github.com/flutter/flutter/issues/new?template=BUG.md

When the exception was thrown, this was the stack
#2      SemanticsOwner.sendSemanticsUpdate 
package:flutter/…/semantics/semantics.dart:2607
#3      PipelineOwner.flushSemantics 
package:flutter/…/rendering/object.dart:1039
#4      RendererBinding.drawFrame 
package:flutter/…/rendering/binding.dart:344
#5      WidgetsBinding.drawFrame 
package:flutter/…/widgets/binding.dart:776
#6      RendererBinding._handlePersistentFrameCallback 
package:flutter/…/rendering/binding.dart:279
...
════════════════════════════════════════════════════════════════════════════════

```

<!--
     Run `flutter analyze` and attach any output of that command below.
     If there are any analysis errors, try resolving them before filing this issue.
-->

```
$ flutter analyze
Analyzing playground...
No issues found! (ran in 2.5s)
```

<!-- Finally, paste the output of running `flutter doctor -v` here. -->

```
$ flutter doctor -v
Downloading android-arm-profile/darwin-x64 tools...                 0.6s
Downloading android-arm-release/darwin-x64 tools...                 0.3s
Downloading android-arm64-profile/darwin-x64 tools...               0.3s
Downloading android-arm64-release/darwin-x64 tools...               0.3s
[✓] Flutter (Channel master, v1.10.6-pre.33, on Mac OS X 10.14.6 18G95, locale en-US)
    • Flutter version 1.10.6-pre.33 at /Users/katelovett/github/flutter
    • Framework revision 961f1b746d (3 hours ago), 2019-09-23 10:09:38 -0700
    • Engine revision b875c7a5ff
    • Dart version 2.6.0 (build 2.6.0-dev.0.0 7c1821c4aa)


[✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
    • Android SDK at /Users/katelovett/Library/Android/sdk
    • Android NDK location not configured (optional; useful for native profiling support)
    • Platform android-28, build-tools 28.0.3
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 10.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 10.1, Build version 10B61
    • CocoaPods version 1.7.2

[✓] Android Studio (version 3.4)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin version 36.1.1
    • Dart plugin version 183.6270
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01)

[✓] IntelliJ IDEA Ultimate Edition (version 2019.1.2)
    • IntelliJ at /Applications/IntelliJ IDEA.app
    • Flutter plugin version 39.0.2
    • Dart plugin version 191.8423

[✓] VS Code (version 1.38.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.4.1

[✓] Connected device (1 available)
    • SixthSense • 1c017dd332591e8a3553c3a7ec3f7a6daf2d1d27 • ios • iOS 12.4.1

• No issues found!
```