Repository: flutter
Issue: [Proposal][Documentation] Update assert message and documentation for async State.dispose() implementations
Labels: framework,d: api docs,c: proposal,P3,team-framework,triaged-framework

### Is there an existing issue for this?

- [X] I have searched the [existing issues](https://github.com/flutter/flutter/issues)
- [X] I have read the [guide to filing a bug](https://flutter.dev/docs/resources/bug-reports)

### Use case

Context: https://github.com/flutter/flutter/issues/64935#issuecomment-686852369

Developers that need to do some cleanup in the dispose method of the State of a StatefulWidget might hit an assert.
The message of this assert is only partially correct, however. It does not specify that `super.dispose()` should be called in a synchronous context (i.e. before the first await in the method).

Furthermore, the documentation for `State.dispose()` mentions

```
Implementations of this method should end with a call to the inherited method, as in super.dispose().
```
which suffers from the same problem.

<details>

 <summary>Error message example</summary>
 
 ```
 ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following assertion was thrown while finalizing the widget tree:
FooState.dispose failed to call super.dispose.
dispose() implementations must always call their superclass dispose() method, to ensure that all the
resources used by the widget are fully released.

When the exception was thrown, this was the stack:
#0      StatefulElement.unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:5685:7)
#1      StatefulElement.unmount (package:flutter/src/widgets/framework.dart:5692:6)
#2      ConsumerStatefulElement.unmount (package:flutter_riverpod/src/consumer.dart:571:11)
#3      _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2067:13)
#4      _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#5      SingleChildRenderObjectElement.visitChildren (package:flutter/src/widgets/framework.dart:6722:14)
#6      _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#7      _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#8      ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:5523:14)
#9      _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#10     _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#11     SingleChildRenderObjectElement.visitChildren (package:flutter/src/widgets/framework.dart:6722:14)
#12     _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#13     _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#14     SingleChildRenderObjectElement.visitChildren (package:flutter/src/widgets/framework.dart:6722:14)
#15     _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#16     _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#17     ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:5523:14)
#18     _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#19     _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#20     SingleChildRenderObjectElement.visitChildren (package:flutter/src/widgets/framework.dart:6722:14)
#21     _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#22     _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#23     ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:5523:14)
#24     _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#25     _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#26     SingleChildRenderObjectElement.visitChildren (package:flutter/src/widgets/framework.dart:6722:14)
#27     _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#28     _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#29     ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:5523:14)
#30     _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#31     _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#32     ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:5523:14)
#33     _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#34     _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#35     SingleChildRenderObjectElement.visitChildren (package:flutter/src/widgets/framework.dart:6722:14)
#36     _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#37     _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#38     ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:5523:14)
#39     _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#40     _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#41     SingleChildRenderObjectElement.visitChildren (package:flutter/src/widgets/framework.dart:6722:14)
#42     _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#43     _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#44     ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:5523:14)
#45     _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#46     _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#47     ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:5523:14)
#48     _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#49     _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#50     ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:5523:14)
#51     _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#52     _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#53     ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:5523:14)
#54     _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#55     _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#56     SingleChildRenderObjectElement.visitChildren (package:flutter/src/widgets/framework.dart:6722:14)
#57     _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#58     _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#59     ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:5523:14)
#60     _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#61     _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#62     SingleChildRenderObjectElement.visitChildren (package:flutter/src/widgets/framework.dart:6722:14)
#63     _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#64     _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#65     ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:5523:14)
#66     _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#67     _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#68     ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:5523:14)
#69     _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#70     _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#71     ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:5523:14)
#72     _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#73     _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#74     ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:5523:14)
#75     _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#76     _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#77     ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:5523:14)
#78     _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#79     _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#80     ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:5523:14)
#81     _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#82     _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#83     SingleChildRenderObjectElement.visitChildren (package:flutter/src/widgets/framework.dart:6722:14)
#84     _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#85     _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#86     ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:5523:14)
#87     _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#88     _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#89     ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:5523:14)
#90     _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#91     _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#92     ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:5523:14)
#93     _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#94     _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#95     ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:5523:14)
#96     _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#97     _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#98     ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:5523:14)
#99     _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#100    _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#101    SingleChildRenderObjectElement.visitChildren (package:flutter/src/widgets/framework.dart:6722:14)
#102    _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#103    _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#104    ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:5523:14)
#105    _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#106    _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#107    ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:5523:14)
#108    _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#109    _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#110    ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:5523:14)
#111    _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#112    _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#113    ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:5523:14)
#114    _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#115    ListIterable.forEach (dart:_internal/iterable.dart:49:13)
#116    _InactiveElements._unmountAll (package:flutter/src/widgets/framework.dart:2076:25)
#117    BuildOwner.lockState (package:flutter/src/widgets/framework.dart:2755:15)
#118    BuildOwner.finalizeTree (package:flutter/src/widgets/framework.dart:3165:7)
#119    WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:987:19)
#120    RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:457:5)
#121    SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1325:15)
#122    SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1255:9)
#123    SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1113:5)
#124    _invoke (dart:ui/hooks.dart:312:13)
#125    PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:383:5)
#126    _drawFrame (dart:ui/hooks.dart:283:31)
════════════════════════════════════════════════════════════════════════════════════════════════════
 ```

</details>

### Proposal

I propose that we update both the assert and the documentation.

We should do the following:

1) Update the docs for `State.dispose()` so that these treat `void dispose()` and `Future<void> dispose()` separately.

```
// GOOD
@override
void dispose() {
  // do something before dispose
  super.dispose();
}

// OK (although, lifecycle-wise, dispose should come last)
@override
void dispose() {
  super.dispose();
  // do something after dispose
}

// BAD (will hit mustCallSuper lint anyway)
@override
void dispose() {
  // forget to call super
}

// GOOD
@override
Future<void> dispose() async {
  super.dispose();
  
  await doSomethingAfterDispose();
}

// BAD (will hit existing assert)
@override
Future<void> dispose() async {
  await doSomethingBeforeDispose();
  
  super.dispose();
}
```

2) Update the assert (if possible) to alter the message in the case that the dispose method returns a Future.

```
The following assertion was thrown while finalizing the widget tree:
FooState.dispose failed to call super.dispose.
Async dispose() implementations must always call their superclass dispose() method first, to ensure that all the
resources used by the widget are fully released.
```