spkersten / dart_functional_data

Simple and non-intrusive code generator for lenses and boilerplate of data types
https://pub.dev/packages/functional_data
MIT License
41 stars 15 forks source link

Flutter types typed as dynamic #3

Closed modulovalue closed 4 years ago

modulovalue commented 5 years ago

There's a weird bug that occurs when using flutter types.

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

part 'blend_mode.g.dart';

@FunctionalData()
class BlendModeData extends $BlendModeData {

    final BlendMode mode;

    const BlendModeData({
        @required this.mode,
    });

    const BlendModeData.deflt() : mode = BlendMode.srcOver;
}

would lead to

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'blend_mode.dart';

// **************************************************************************
// FunctionalDataGenerator
// **************************************************************************

abstract class $BlendModeData {
  dynamic get mode;
  const $BlendModeData();
  BlendModeData copyWith({dynamic mode}) =>
      BlendModeData(mode: mode ?? this.mode);
  String toString() => "BlendModeData(mode: $mode)";
  bool operator ==(dynamic other) =>
      other.runtimeType == runtimeType && mode == other.mode;
  @override
  int get hashCode {
    var result = 17;
    result = 37 * result + mode.hashCode;
    return result;
  }
}

class BlendModeData$ {
  static final mode = Lens<BlendModeData, dynamic>(
      (s_) => s_.mode, (s_, mode) => s_.copyWith(mode: mode));
}

Where mode should not be dynamic but BlendMode.

Everything works fine with non-flutter types. Am I doing something wrong or is this a real issue?

spkersten commented 5 years ago

I don't think you're doing something wrong. Thanks for reporting it.

modulovalue commented 5 years ago

Do you have an idea what the problem might be? I'd be willing to help if you don't have the time to fix this. But I'm not familiar with the builder package and you might be able to solve this more quickly than me. If you don't have the time but clues on what the problem might I'd appreciate it if you could share them.

(Honestly, this is my favorite package now, and I'm not saying that to only get you to fix this issue! 😀)

modulovalue commented 5 years ago

related? dart-lang/build/733

modulovalue commented 5 years ago

Solved it!

Not sure if optimal or if there are any edge cases I missed, but I get correct types now with:

// Inspired by remi's solution @ functional_widget
String type;
        if (f.type.isDynamic) {
            try {
                final parsedLibrary = element.session.getParsedLibraryByElement(element.library);
                final declaration = parsedLibrary.getElementDeclaration(f);
                final parameter = declaration.node as VariableDeclarationImpl;
                type = (parameter.parent.parent as FieldDeclarationImpl).fields.type.toString();
            } catch (e) {
                print("Unknown type");
            }
        } else {
            type = f.type.toString();
        }
spkersten commented 5 years ago

@modulovalue Great! I'll try to integrate it.

modulovalue commented 5 years ago

Just wanted to let you know that the solution above does not recognize wrapped types. So Optional<BlendMode> would still be Optional<dynamic>

spkersten commented 5 years ago

@modulovalue I've tried to reproduce the issue, but if I just use use your initial snippet code generates fine. However, I think others have shown me the same issue with dynamic. Do you know more about when it occurs?

modulovalue commented 5 years ago

Using the example folder as a starting point:

main.dart

import 'dart:ui';

import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:functional_data/functional_data.dart';
import 'dart:math' as math;

part 'main.g.dart';

// Only requirement is that it has a constructor with named arguments for all fields
@FunctionalData()
class Foo extends $Foo {
  final int number;
  final Optional<BlendMode> mode;
  final Offset offset;
  final Container container;
  final String name;

  String get displayString => "$name[$number]";

  const Foo({this.number, this.mode, this.name, this.offset, this.container});
}
...

pubspec.yaml

...
dependencies:
  flutter:
    sdk: flutter
  functional_data:
...

run flutter pub get

run flutter pub run build_runner watch --delete-conflicting-outputs

generates:

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'main.dart';

// **************************************************************************
// FunctionalDataGenerator
// **************************************************************************

abstract class $Foo {
  int get number;
  Optional<dynamic> get mode;
  dynamic get offset;
  Container get container;
  String get name;
  const $Foo();
  Foo copyWith(

Well, Container works, but reading the issues otherer packages have, it might just happen with dart:ui types and not those coming with flutter.

Does it still work for you?

derolf commented 5 years ago

I added a fix that just preserves the original type.