google / built_value.dart

Immutable value types, enum classes, and serialization.
https://pub.dev/packages/built_value
BSD 3-Clause "New" or "Revised" License
862 stars 183 forks source link

non-instantiable Builders can't be used as Builder attributes #831

Open micimize opened 4 years ago

micimize commented 4 years ago

The following fails due to the NamedBuilder named attribute on the builder, probably because non-instantiable builders aren't really Builders:

[SEVERE] built_value_generator:built_value on lib/graphql/temp.dart:
Error in BuiltValueGenerator for abstract class Container implements Built<Container, ContainerBuilder>.
Please make the following changes to use BuiltValue:

1. Make builder have exactly these fields: named

Source:

import 'package:meta/meta.dart';
import 'package:built_collection/built_collection.dart';
import 'package:built_value/built_value.dart';

part 'temp.g.dart';

@BuiltValue(instantiable: false)
abstract class Named {
  @nullable
  String get name;

  Named rebuild(void Function(NamedBuilder) updates);
  NamedBuilder toBuilder();
}

/// Exposes the name attribute of [Named]
abstract class Container implements Built<Container, ContainerBuilder> {
  Container._();
  factory Container([void Function(ContainerBuilder) updates]) = _$Container;

  Named get named;
}

abstract class ContainerBuilder
    implements Builder<Container, ContainerBuilder> {
  factory ContainerBuilder() = _$ContainerBuilder;
  ContainerBuilder._();

  NamedBuilder named;
  // Named named; // works just fine
}

relevant pubspec:

dependencies:
  built_collection: ^4.3.2
  built_value: ^7.0.9
  built_value_generator: ^7.0.9
  build: ^1.2.2

dev_dependencies:
  build_runner: ^1.7.4
  build_test:
micimize commented 4 years ago

I attempted to work around this with generic interfaces, but it still fails:

@BuiltValue(instantiable: false)
abstract class Character<V extends Character<V, B>,
    B extends CharacterBuilder<V, B>> extends Built<V, B>

abstract class CharacterBuilder<V extends Character<V, B>,
    B extends CharacterBuilder<V, B>> extends Builder<V, B>

abstract class DroidBuilder
    implements
        CharacterBuilder<Droid, DroidBuilder>,
        Builder<Droid, DroidBuilder>

  // builder field that fails with
  // Make builder field droids have type:
  //  BuiltList<Droid> (or, if applicable, builder)
  ListBuilder<DroidBuilder> droids;

My attempt to apply the same technique to actual "generic builders" also fails:

// fails with 
// Make builder field hero have type: Character<Character<Character<Character, CharacterBuilder>, CharacterBuilder<Character, CharacterBuilder>>, CharacterBuilder<Character<Character, CharacterBuilder>, CharacterBuilder<Character, CharacterBuilder>>>

  @nullable
  Character<Character<Character, CharacterBuilder>,
      CharacterBuilder<Character, CharacterBuilder>> get hero;

I honestly didn't exactly expect it to work đŸ˜… just thought it seemed related enough to #426 to be worth taking a crack at

davidmorgan commented 4 years ago

I think the problem is that the type NamedBuilder is not available yet as it hasn't been generated, so the generator is getting confused about the field type.

It might work to move Named to another file/package.

Or, the generator should be fixed so it doesn't get confused :)