Skip to content

Add workaround for dart2js issue with polymorphism. #233

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

Merged
merged 1 commit into from
Sep 25, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# Changelog

## 4.1.2
## 4.2.0

- Generated code ignores more lints.
- Add a workaround so "polymorphism" features can be used with dart2js.
See example/lib/polymorphism.dart.

## 4.1.1

Expand Down
39 changes: 30 additions & 9 deletions built_value_generator/lib/src/value_source_class.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ abstract class ValueSourceClass
@memoized
ClassElement get builderElement => element.library.getType(name + 'Builder');

@memoized
bool get implementsBuilt => element.allSupertypes
.any((interfaceType) => interfaceType.name == 'Built');

@memoized
BuiltValue get settings {
final annotations = element.metadata
Expand Down Expand Up @@ -146,9 +150,12 @@ abstract class ValueSourceClass

static bool needsBuiltValue(ClassElement classElement) {
// TODO(davidmorgan): more exact type check.
return classElement.allSupertypes
.any((interfaceType) => interfaceType.name == 'Built') &&
!classElement.displayName.startsWith('_\$');
return !classElement.displayName.startsWith('_\$') &&
(classElement.allSupertypes
.any((interfaceType) => interfaceType.name == 'Built') ||
classElement.metadata
.map((annotation) => annotation.computeConstantValue())
.any((value) => value?.type?.displayName == 'BuiltValue'));
}

Iterable<String> _computeErrors() {
Expand All @@ -172,10 +179,13 @@ abstract class ValueSourceClass
result.add('Make class abstract.');
}

final expectedBuildParameters = '$name$_generics, ${name}Builder$_generics';
if (builtParameters != expectedBuildParameters) {
result.add('Make class implement Built<$expectedBuildParameters>. '
'Currently: Built<$builtParameters>');
if (settings.instantiable) {
final expectedBuildParameters =
'$name$_generics, ${name}Builder$_generics';
if (builtParameters != expectedBuildParameters) {
result.add('Make class implement Built<$expectedBuildParameters>. '
'Currently: Built<$builtParameters>');
}
}

if (settings.instantiable) {
Expand Down Expand Up @@ -552,8 +562,19 @@ abstract class ValueSourceClass
/// Generates an abstract builder with just abstract setters and getters.
String _generateAbstractBuilder() {
final result = new StringBuffer();
result.writeln('abstract class ${name}Builder$_boundedGenerics '
'implements ${builderImplements.join(", ")} {');

if (implementsBuilt) {
result.writeln('abstract class ${name}Builder$_boundedGenerics '
'implements ${builderImplements.join(", ")} {');
} else {
// The "Built" interface has been omitted to work around dart2js issue
// https://github.com/dart-lang/sdk/issues/14729. So, we can't implement
// "Builder". Add the methods explicitly.
result.writeln('abstract class ${name}Builder$_boundedGenerics {');

result.writeln('void replace($name$_generics other);');
result.writeln('void update(void updates(${name}Builder$_generics b));');
}

for (final field in fields) {
final typeInBuilder = field.typeInBuilder;
Expand Down
4 changes: 4 additions & 0 deletions built_value_generator/lib/src/value_source_class.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions example/lib/polymorphism.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ part 'polymorphism.g.dart';
/// Very little code is generated for a non-instantiable Built Value; just the
/// interface for the builder. You can write this yourself if you prefer, then
/// nothing will be generated.
///
/// Note that this type of inheritance is currently not supported by dart2js.
/// See [Dart2jsCompatibleAnimal].
@BuiltValue(instantiable: false)
abstract class Animal extends Object
with Walker
Expand All @@ -26,6 +29,20 @@ abstract class Animal extends Object
int get legs;
}

/// The dart2js issue https://github.com/dart-lang/sdk/issues/14729
/// prevents this working when compiling to js. As a workaround, make `Animal`
/// not implement `Built`, and add the `rebuild` and `toBuilder` methods to
/// it explicitly if you need them.
@BuiltValue(instantiable: false)
abstract class Dart2jsCompatibleAnimal extends Object with Walker {
@override
int get legs;

Dart2jsCompatibleAnimal rebuild(
void updates(Dart2jsCompatibleAnimalBuilder b));
Dart2jsCompatibleAnimalBuilder toBuilder();
}

/// `Cat` implements the non-instantiable Built Value `Animal`. The generated
/// builder `CatBuilder` automatically extends 'AnimalBuilder`. This allows you
/// to use `Cat` as an `Animal`.
Expand Down
7 changes: 7 additions & 0 deletions example/lib/polymorphism.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.