Skip to content

[Bug report] extract method: The argument type 'void Function(SnackBarData)' can't be assigned to the parameter type 'void Function(dynamic)' #5350

Closed

Description

@stephane-archer

Input:

        var snackBarData = await _executeConversionWithExceptionAsValue(
          () async {
            await JxlToJpeg.convert(
              jxlFile,
              outputPath: path_lib.join(
                selectedOutputDirPath,
                path_lib.setExtension(path_lib.basename(jxlFile.path), '.jpg'),
              ),
            );
          },
        );
        if (snackBarData != null) {
          displayFeedbackForTheUser(snackBarData);
        }
        _progress.value += 1;

extract method _abc

Result:

  Future<void> _abc(File jxlFile, String selectedOutputDirPath, void displayFeedbackForTheUser(SnackBarData )) async {
    var snackBarData = await _executeConversionWithExceptionAsValue(
      () async {
        await JxlToJpeg.convert(
          jxlFile,
          outputPath: path_lib.join(
            selectedOutputDirPath,
            path_lib.setExtension(path_lib.basename(jxlFile.path), '.jpg'),
          ),
        );
      },
    );
    if (snackBarData != null) {
      displayFeedbackForTheUser(snackBarData);
    }
    _progress.value += 1;
  }

The argument type 'void Function(SnackBarData)' can't be assigned to the parameter type 'void Function(dynamic)'.

Correct output:

  Future<void> _abc(File jxlFile, String selectedOutputDirPath, void Function(SnackBarData) displayFeedbackForTheUser) async {
    var snackBarData = await _executeConversionWithExceptionAsValue(
      () async {
        await JxlToJpeg.convert(
          jxlFile,
          outputPath: path_lib.join(
            selectedOutputDirPath,
            path_lib.setExtension(path_lib.basename(jxlFile.path), '.jpg'),
          ),
        );
      },
    );
    if (snackBarData != null) {
      displayFeedbackForTheUser(snackBarData);
    }
    _progress.value += 1;
  }

Activity

  1. DanTup commented on Nov 26, 2024

    @DanTup
    Member

    Are you able to provide a complete code sample I can use to repro this? I tried stubbing out the things missing from your code, but I wasn't able to reproduce the issue:

    Future<void> main() async {
      var jxlFile = 1;
      var value = 1;
      var selectedOutputDirPath = '';
      var snackBarData = await _executeConversionWithExceptionAsValue(
        () async {
          await JxlToJpeg.convert(
            jxlFile,
            outputPath: join(
              selectedOutputDirPath,
              '.jpg',
            ),
          );
        },
      );
      if (snackBarData != null) {
        displayFeedbackForTheUser(snackBarData);
      }
      value += 1;
    }
    
    Future<Object?> _executeConversionWithExceptionAsValue(Function f) =>
        throw UnimplementedError();
    
    Future<void> foo() async {}
    
    Future<Object?> bar(Function x) async {}
    
    class JxlToJpeg {
      static Future<void> convert(int a, {required String outputPath}) {
        throw UnimplementedError();
      }
    }
    
    String join(String a, String b) => throw UnimplementedError();
    
    void displayFeedbackForTheUser(Object? o) {}

    Extracting the same code from here didn't produce any incorrect code.

    Thanks!

  2. added
    awaiting infoRequires more information from the customer to progress
    on Nov 26, 2024
  3. stephane-archer commented on Nov 26, 2024

    @stephane-archer
    Author
      Future<void> _processDroppedFiles(DropDoneDetails dropDoneDetails) async {
        var displayFeedbackForTheUser = getDisplayFeedbackForTheUser(context);
        if (_appState.value != _AppState.idle) {
          return;
        }
        final filePaths = _getDroppedPath(dropDoneDetails);
        if (filePaths.isEmpty) {
          return;
        }
        _appState.value = _AppState.selecting;
        String? selectedOutputDirPath = await FilePicker.platform.getDirectoryPath(
          lockParentWindow: true,
          dialogTitle: "Please select an output folder",
          initialDirectory: path_lib.dirname(filePaths.first),
        );
        if (selectedOutputDirPath == null) {
          _appState.value = _AppState.idle;
          return;
        }
        try {
          _appState.value = _AppState.processing;
          final jpegFiles = _pathsToFiles(_getJpegPaths(filePaths));
          final jxlFiles = _pathsToFiles(_getJxlPaths(filePaths));
          _batchSize.value = jpegFiles.length + jxlFiles.length;
          _progress.value = 0;
          for (var jpegFile in jpegFiles) {
            var snackBarData = await _executeConversionWithExceptionAsValue(
              () async {
                await JpegToJxl.convert(
                  jpegFile,
                  outputPath: path_lib.join(
                    selectedOutputDirPath,
                    path_lib.setExtension(path_lib.basename(jpegFile.path), '.jxl'),
                  ),
                );
              },
            );
            if (snackBarData != null) {
              displayFeedbackForTheUser(snackBarData);
            }
            _progress.value += 1;
          }
          for (var jxlFile in jxlFiles) {
            var snackBarData = await _executeConversionWithExceptionAsValue(
              () async {
                await JxlToJpeg.convert(
                  jxlFile,
                  outputPath: path_lib.join(
                    selectedOutputDirPath,
                    path_lib.setExtension(path_lib.basename(jxlFile.path), '.jpg'),
                  ),
                );
              },
            );
            if (snackBarData != null) {
              displayFeedbackForTheUser(snackBarData);
            }
            _progress.value += 1;
          }
        } finally {
          displayFeedbackForTheUser((message: 'Done', color: Colors.green));
          _appState.value = _AppState.idle;
        }
      }
    

    with this code in another file:

    import 'package:flutter/material.dart';
    
    void Function(SnackBarData) getDisplayFeedbackForTheUser(BuildContext context) {
      return (snackBarData) {
        final snackBar = SnackBar(
          backgroundColor: snackBarData.color,
          content: Text(snackBarData.message),
          duration: snackBarData.color != Colors.green
              ? Duration(seconds: 6)
              : Duration(seconds: 4),
        );
        ScaffoldMessenger.of(context).showSnackBar(snackBar);
      };
    }
    
    typedef SnackBarData = ({String message, Color color});
    

    sorry my code is pretty ugly, I hope this helps you solve the issue, make sure to use a typedef, I think this is what cause the issue

  4. added
    in editorRelates to code editing or language features
    relies on sdk changesSomething that requires changes in the Dart/Flutter SDK to ship before it will become available
    in lsp/analysis serverSomething to be fixed in the Dart analysis server
    and removed
    awaiting infoRequires more information from the customer to progress
    on Nov 27, 2024
  5. added this to the v3.104.0 milestone on Nov 27, 2024
  6. DanTup commented on Nov 27, 2024

    @DanTup
    Member

    Thanks! I was able to trim this down to:

    Future<void> f(void Function(String) f, String a) async {
      f(a);
    }
    

    The issue here is that the refactor was written before the generic function syntax (where function types can have parameters with no names) and writes a signature using the old style (which doesn't support not having names).

  7. DanTup commented on Nov 27, 2024

    @DanTup
    Member

    Got a fix up for review at https://dart-review.googlesource.com/c/sdk/+/397900

    The fix is in the Dart analysis server so once merged, will ship in a future Dart/Flutter SDK release (not a VS Code extension release).

  8. stephane-archer commented on Nov 27, 2024

    @stephane-archer
    Author

    @DanTup you are the best! thank you for solving my issue!

  9. DanTup commented on Dec 2, 2024

    @DanTup
    Member

    Thanks, no problem! The fix has now landed in the Dart SDK and will be included in a future Dart/Flutter SDK release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    in editorRelates to code editing or language featuresin lsp/analysis serverSomething to be fixed in the Dart analysis serveris bugrelies on sdk changesSomething that requires changes in the Dart/Flutter SDK to ship before it will become available

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions