Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Frontend server exception when moving a parameter between objects and doing Flutter hot restart #55357

Closed
jason-simmons opened this issue Apr 2, 2024 · 1 comment
Assignees
Labels
area-front-end Use area-front-end for front end / CFE / kernel format related issues. cfe-incremental-compiler Incremental compiler issue in the CFE customer-flutter

Comments

@jason-simmons
Copy link
Contributor

This is based on the app in flutter/flutter#145891

  1. Run this app in Flutter:
import 'dart:ui' as ui;

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: Center(
        child: CustomButton(
          onTap: (_) {},
          child: Container(
            color: Colors.red,
            width: 120.0,
            height: 120.0,
            child: const Center(
              child: Text('Test'),
            ),
          ),
          borderRadius: BorderRadius.horizontal(left: Radius.circular(10), right: Radius.circular(10)),
        ),
      ),
    );
  }
}

class CustomButton extends StatefulWidget {
  final Widget child;
  final ValueChanged<Offset>? onTap;
  final ValueChanged<Offset>? onLongTap;
  final GestureTapDownCallback? onTapDown;
  final BorderRadiusGeometry borderRadius;

  const CustomButton({
    super.key,
    required this.child,
    required this.onTap,
    this.onLongTap,
    this.onTapDown,
    this.borderRadius = BorderRadius.zero,
  });

  @override
  _ButtonState createState() => _ButtonState();
}

class _ButtonState extends State<CustomButton>
    with SingleTickerProviderStateMixin {
  late final AnimationController _animation;
  late Duration _animationDuration;
  late Curve _animationCurve;
  Offset _tapPosition = Offset.zero;

  @override
  void initState() {
    super.initState();
    _animation = AnimationController(vsync: this);
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    final ThemeData theme = Theme.of(context);
    _animationDuration = theme.animationDuration;
    _animationCurve = theme.animationCurve;
  }

  @override
  void dispose() {
    _animation.dispose();
    super.dispose();
  }

  void _onHoverStart(TapDownDetails details) {
    _tapPosition = details.globalPosition;
    widget.onTapDown?.call(details);
    if (widget.onTap != null || widget.onLongTap != null) {
      _animation.animateTo(
        1.0,
        duration: _animationDuration,
        curve: _animationCurve,
      );
    }
  }

  void _onHoverEnd() {
    if (widget.onTap == null && widget.onLongTap == null) {
      return;
    }
    if (_animation.value < 1.0) {
      final TickerFuture ticker = _animation.animateTo(
        1.0,
        duration: _animationDuration * 0.5,
        curve: _animationCurve,
      );
      ticker.whenComplete(() {
        _animation.animateBack(
          0.0,
          duration: _animationDuration * 0.5,
          curve: _animationCurve,
        );
      });
    } else if (_animation.value > 0.0) {
      _animation.animateBack(
        0.0,
        duration: _animationDuration,
        curve: _animationCurve,
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: widget.onTap != null
          ? () => HapticFeedback.lightImpact()
              .whenComplete(() => widget.onTap!(_tapPosition))
          : null,
      onLongPress: widget.onLongTap != null
          ? () => HapticFeedback.lightImpact()
              .whenComplete(() => widget.onLongTap!(_tapPosition))
          : null,
      onTapDown: _onHoverStart,
      onTapUp: (_) => _onHoverEnd(),
      onTapCancel: () => _onHoverEnd(),
      child: Container(
        color: Colors.transparent,
        child: AnimatedBuilder(
          animation: _animation,
          child: widget.child,
          builder: (_, Widget? child) {
            final double blurSigma = Tween<double>(
              begin: 0.0,
              end: 1.0,
            ).evaluate(_animation);
            return Opacity(
              opacity: Tween<double>(
                begin: 1.0,
                end: 0.5,
              ).evaluate(_animation),
              child: ImageFiltered(
                imageFilter: ui.ImageFilter.blur(
                  sigmaX: blurSigma,
                  sigmaY: blurSigma,
                ),
                child: child!,
              ),
            );
          },
        ),
      ),
    );
  }
}

extension on ThemeData {
  Duration get animationDuration => const Duration(milliseconds: 300);

  Curve get animationCurve => Curves.linearToEaseOut;
}
  1. Move the borderRadius: BorderRadius.horizontal line out of the CustomButton and into the Container. Do a hot restart in the Flutter tool.

The compile will fail with a No named parameter with the name 'borderRadius' error, as expected.

  1. Move the borderRadius: BorderRadius.horizontal line back to its original position and do another hot restart.

The tool will exit with this exception from the frontend server:

Unhandled exception:
root::package:bug_145891/main.dart::@methods::package:bug_145891/main.dart::_ext
ension#0|get#animationDuration is already bound to Reference to
package:bug_145891/main.dart::@methods::package:bug_145891/main.dart::_extension
#0|get#animationDuration with node _extension#0|get#animationDuration
(Procedure:2059109), trying to bind to Reference to
_extension#0|get#animationDuration with node _extension#0|get#animationDuration
(Procedure:2060200)
#0      CanonicalName.bindTo (package:kernel/canonical_name.dart:215)
#1      Procedure.bindCanonicalNames (package:kernel/ast.dart:3082)
#2      Library.ensureCanonicalNames (package:kernel/ast.dart:527)
#3      Component.computeCanonicalNamesForLibrary
(package:kernel/ast.dart:14735)
#4      Component.computeCanonicalNames (package:kernel/ast.dart:14698)
#5      sortComponent (package:vm/kernel_front_end.dart:831)
#6      FrontendCompiler.writeDillFile
(package:frontend_server/frontend_server.dart:847)
#7      FrontendCompiler.recompileDelta
(package:frontend_server/frontend_server.dart:970)
<asynchronous suspension>
#8      listenAndCompile.<anonymous closure>
(package:frontend_server/frontend_server.dart:1389)
<asynchronous suspension>
the Dart compiler exited unexpectedly.
the Dart compiler exited unexpectedly.
the Dart compiler exited unexpectedly.
@jason-simmons jason-simmons changed the title Exception when moving Frontend server exception when moving a parameter between objects and doing Flutter hot restart Apr 2, 2024
@jason-simmons
Copy link
Contributor Author

I reproduced this using:

  • Flutter framework d35c2553ae38e5e82a638d15277bc6b3be9f5513
  • Flutter engine 5bf8b94505a44aaf2ac2a9319faa885548d52434 with Dart SDK e6e6d5fe3fb0fdb7c5da01fe1da7c809851dd904

It looks like this issue has existed for a long time.

@a-siva a-siva added area-front-end Use area-front-end for front end / CFE / kernel format related issues. customer-flutter labels Apr 3, 2024
@johnniwinther johnniwinther added the cfe-incremental-compiler Incremental compiler issue in the CFE label Apr 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-front-end Use area-front-end for front end / CFE / kernel format related issues. cfe-incremental-compiler Incremental compiler issue in the CFE customer-flutter
Projects
None yet
Development

No branches or pull requests

4 participants