@@ -222,7 +222,7 @@ class OverlayEntry implements Listenable {
222222 }
223223
224224 @override
225- String toString () => '${describeIdentity (this )}(opaque: $opaque ; maintainState: $maintainState )' ;
225+ String toString () => '${describeIdentity (this )}(opaque: $opaque ; maintainState: $maintainState )${ _disposedByOwner ? "(DISPOSED)" : "" } ' ;
226226}
227227
228228class _OverlayEntryWidget extends StatefulWidget {
@@ -296,7 +296,7 @@ class _OverlayEntryWidgetState extends State<_OverlayEntryWidget> {
296296 late final Iterable <RenderBox > _hitTestOrderIterable = _createChildIterable (reversed: true );
297297
298298 // The following uses sync* because hit-testing is lazy, and LinkedList as a
299- // Iterable doesn't support current modification.
299+ // Iterable doesn't support concurrent modification.
300300 Iterable <RenderBox > _createChildIterable ({ required bool reversed }) sync * {
301301 final LinkedList <_OverlayEntryLocation >? children = _sortedTheaterSiblings;
302302 if (children == null || children.isEmpty) {
@@ -543,6 +543,55 @@ class OverlayState extends State<Overlay> with TickerProviderStateMixin {
543543 return _entries.length;
544544 }
545545
546+ bool _debugCanInsertEntry (OverlayEntry entry) {
547+ final List <DiagnosticsNode > operandsInformation = < DiagnosticsNode > [
548+ DiagnosticsProperty <OverlayEntry >('The OverlayEntry was' , entry, style: DiagnosticsTreeStyle .errorProperty),
549+ DiagnosticsProperty <OverlayState >(
550+ 'The Overlay the OverlayEntry was trying to insert to was' , this , style: DiagnosticsTreeStyle .errorProperty,
551+ ),
552+ ];
553+
554+ if (! mounted) {
555+ throw FlutterError .fromParts (< DiagnosticsNode > [
556+ ErrorSummary ('Attempted to insert an OverlayEntry to an already disposed Overlay.' ),
557+ ...operandsInformation,
558+ ]);
559+ }
560+
561+ final OverlayState ? currentOverlay = entry._overlay;
562+ final bool alreadyContainsEntry = _entries.contains (entry);
563+
564+ if (alreadyContainsEntry) {
565+ final bool inconsistentOverlayState = ! identical (currentOverlay, this );
566+ throw FlutterError .fromParts (< DiagnosticsNode > [
567+ ErrorSummary ('The specified entry is already present in the target Overlay.' ),
568+ ...operandsInformation,
569+ if (inconsistentOverlayState) ErrorHint ('This could be an error in the Flutter framework.' )
570+ else ErrorHint (
571+ 'Consider calling remove on the OverlayEntry before inserting it to a different Overlay, '
572+ 'or switching to the OverlayPortal API to avoid manual OverlayEntry management.'
573+ ),
574+ if (inconsistentOverlayState) DiagnosticsProperty <OverlayState >(
575+ "The OverlayEntry's current Overlay was" , currentOverlay, style: DiagnosticsTreeStyle .errorProperty,
576+ ),
577+ ]);
578+ }
579+
580+ if (currentOverlay == null ) {
581+ return true ;
582+ }
583+
584+ throw FlutterError .fromParts (< DiagnosticsNode > [
585+ ErrorSummary ('The specified entry is already present in a different Overlay.' ),
586+ ...operandsInformation,
587+ DiagnosticsProperty <OverlayState >("The OverlayEntry's current Overlay was" , currentOverlay, style: DiagnosticsTreeStyle .errorProperty,),
588+ ErrorHint (
589+ 'Consider calling remove on the OverlayEntry before inserting it to a different Overlay, '
590+ 'or switching to the OverlayPortal API to avoid manual OverlayEntry management.'
591+ )
592+ ]);
593+ }
594+
546595 /// Insert the given entry into the overlay.
547596 ///
548597 /// If `below` is non-null, the entry is inserted just below `below` .
@@ -552,8 +601,7 @@ class OverlayState extends State<Overlay> with TickerProviderStateMixin {
552601 /// It is an error to specify both `above` and `below` .
553602 void insert (OverlayEntry entry, { OverlayEntry ? below, OverlayEntry ? above }) {
554603 assert (_debugVerifyInsertPosition (above, below));
555- assert (! _entries.contains (entry), 'The specified entry is already present in the Overlay.' );
556- assert (entry._overlay == null , 'The specified entry is already present in another Overlay.' );
604+ assert (_debugCanInsertEntry (entry));
557605 entry._overlay = this ;
558606 setState (() {
559607 _entries.insert (_insertionIndex (below, above), entry);
@@ -569,14 +617,7 @@ class OverlayState extends State<Overlay> with TickerProviderStateMixin {
569617 /// It is an error to specify both `above` and `below` .
570618 void insertAll (Iterable <OverlayEntry > entries, { OverlayEntry ? below, OverlayEntry ? above }) {
571619 assert (_debugVerifyInsertPosition (above, below));
572- assert (
573- entries.every ((OverlayEntry entry) => ! _entries.contains (entry)),
574- 'One or more of the specified entries are already present in the Overlay.' ,
575- );
576- assert (
577- entries.every ((OverlayEntry entry) => entry._overlay == null ),
578- 'One or more of the specified entries are already present in another Overlay.' ,
579- );
620+ assert (entries.every (_debugCanInsertEntry));
580621 if (entries.isEmpty) {
581622 return ;
582623 }
0 commit comments