Skip to content

Commit

Permalink
Make Reference.type return Reference (#175)
Browse files Browse the repository at this point in the history
Fixes #174

While these changes are technically breaking we expect clients won't
be impacted.

- Add a test which fails before this change and passes after
- Add tests for nested function types since that was untested previously
- Make `Reference.type` return `Reference`, update call sites.
- Return `this` from the `type` getter.
  • Loading branch information
natebosch committed Nov 27, 2017
1 parent db564b1 commit 0ff897d
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 10 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Expand Up @@ -87,6 +87,9 @@ void main() {
* Added `nullSafeProperty` to `Expression` to access properties with `?.`
* Added `conditional` to `Expression` to use the ternary operator `? : `
* Methods taking `positionalArguments` accept `Iterable<Expression>`
* **BUG FIX**: Parameters can take a `FunctionType` as a `type`.
`Reference.type` now returns a `Reference`. Note that this change is
technically breaking but should not impacts most clients.

## 2.2.0

Expand Down
13 changes: 7 additions & 6 deletions lib/src/emitter.dart
Expand Up @@ -100,18 +100,19 @@ class DartEmitter extends Object
visitTypeParameters(spec.types.map((r) => r.type), output);
if (spec.extend != null) {
output.write(' extends ');
visitType(spec.extend.type, output);
spec.extend.type.accept(this, output);
}
if (spec.mixins.isNotEmpty) {
output
..write(' with ')
..writeAll(spec.mixins.map<StringSink>((m) => visitType(m.type)), ',');
..writeAll(
spec.mixins.map<StringSink>((m) => m.type.accept(this)), ',');
}
if (spec.implements.isNotEmpty) {
output
..write(' implements ')
..writeAll(
spec.implements.map<StringSink>((m) => visitType(m.type)), ',');
spec.implements.map<StringSink>((m) => m.type.accept(this)), ',');
}
output.write(' {');
spec.constructors.forEach((c) {
Expand Down Expand Up @@ -198,7 +199,7 @@ class DartEmitter extends Object
}
if (spec.redirect != null) {
output.write(' = ');
visitType(spec.redirect.type, output);
spec.redirect.type.accept(this, output);
output.write(';');
} else if (spec.body != null) {
if (_isLambdaConstructor(spec)) {
Expand Down Expand Up @@ -484,12 +485,12 @@ class DartEmitter extends Object
}

@override
visitTypeParameters(Iterable<TypeReference> specs, [StringSink output]) {
visitTypeParameters(Iterable<Reference> specs, [StringSink output]) {
output ??= new StringBuffer();
if (specs.isNotEmpty) {
output
..write('<')
..writeAll(specs.map<StringSink>(visitType), ',')
..writeAll(specs.map<StringSink>((s) => s.accept(this)), ',')
..write('>');
}
return output;
Expand Down
2 changes: 1 addition & 1 deletion lib/src/specs/reference.dart
Expand Up @@ -123,7 +123,7 @@ class Reference extends Expression implements Spec {
.toString();

/// Returns as a [TypeReference], which allows adding generic type parameters.
TypeReference get type => new TypeReference((b) => b
Reference get type => new TypeReference((b) => b
..url = url
..symbol = symbol);
}
3 changes: 1 addition & 2 deletions lib/src/specs/type_function.dart
Expand Up @@ -14,7 +14,6 @@ import '../visitors.dart';
import 'code.dart';
import 'expression.dart';
import 'reference.dart';
import 'type_reference.dart';

part 'type_function.g.dart';

Expand Down Expand Up @@ -58,7 +57,7 @@ abstract class FunctionType extends Expression
String get symbol => null;

@override
TypeReference get type => null;
Reference get type => this;

@override
Expression newInstance(
Expand Down
2 changes: 1 addition & 1 deletion lib/src/visitors.dart
Expand Up @@ -45,5 +45,5 @@ abstract class SpecVisitor<T> {

T visitType(TypeReference spec, [T context]);

T visitTypeParameters(Iterable<TypeReference> specs, [T context]);
T visitTypeParameters(Iterable<Reference> specs, [T context]);
}
47 changes: 47 additions & 0 deletions test/specs/method_test.dart
Expand Up @@ -145,6 +145,53 @@ void main() {
);
});

test('should create a method with a nested function type return type', () {
expect(
new Method((b) => b
..name = 'foo'
..returns = new FunctionType((b) => b
..returnType = new FunctionType((b) => b
..returnType = refer('String')
..requiredParameters.add(refer('String')))
..requiredParameters.addAll([
refer('int'),
]))),
equalsDart(r'''
String Function(String) Function(int) foo();
'''),
);
});

test('should create a method with a function type argument', () {
expect(
new Method((b) => b
..name = 'foo'
..requiredParameters.add(new Parameter((b) => b
..type = new FunctionType((b) => b
..returnType = refer('String')
..requiredParameters.add(refer('int')))
..name = 'argument'))),
equalsDart(r'''
foo(String Function(int) argument);
'''));
});

test('should create a method with a nested function type argument', () {
expect(
new Method((b) => b
..name = 'foo'
..requiredParameters.add(new Parameter((b) => b
..type = new FunctionType((b) => b
..returnType = new FunctionType((b) => b
..returnType = refer('String')
..requiredParameters.add(refer('String')))
..requiredParameters.add(refer('int')))
..name = 'argument'))),
equalsDart(r'''
foo(String Function(String) Function(int) argument);
'''));
});

test('should create a method with generic types', () {
expect(
new Method((b) => b
Expand Down

0 comments on commit 0ff897d

Please sign in to comment.