Updated Angel Container to Null Safety

This commit is contained in:
thomashii 2021-03-18 08:21:42 +08:00
parent 5a1782efba
commit aefe1f1ab8
12 changed files with 79 additions and 78 deletions

View file

@ -3,10 +3,11 @@
* Updated pretty_logging to 3.0.0 * Updated pretty_logging to 3.0.0
* Updated angel_http_exception to 3.0.0 * Updated angel_http_exception to 3.0.0
* Moved angel_cli to https://github.com/dukefirehawk/cli * Moved angel_cli to https://github.com/dukefirehawk/cli
* Added code_buffer 2.0.0 * Added code_buffer and updated to 2.0.0
* Added combinator 2.0.0 * Added combinator and updated to 2.0.0
* Updated angel_route to 5.0.0 * Updated angel_route to 5.0.0
* Updated angel_model to 3.0.0 * Updated angel_model to 3.0.0
* Updated angel_container to 3.0.0
# 3.0.0 (Non NNBD) # 3.0.0 (Non NNBD)
* Changed Dart SDK requirements for all packages to ">=2.10.0 <3.0.0" * Changed Dart SDK requirements for all packages to ">=2.10.0 <3.0.0"

View file

@ -21,14 +21,14 @@ Future<void> main() async {
}); });
// Use `make` to create an instance. // Use `make` to create an instance.
var truck = container.make<Truck>(); var truck = container.make<Truck>()!;
// You can also resolve injections asynchronously. // You can also resolve injections asynchronously.
container.registerFactory<Future<int>>((_) async => 24); container.registerFactory<Future<int>>((_) async => 24);
print(await container.makeAsync<int>()); print(await container.makeAsync<int>());
// Asynchronous resolution also works for plain objects. // Asynchronous resolution also works for plain objects.
await container.makeAsync<Truck>().then((t) => t.drive()); await container.makeAsync<Truck>()!.then((t) => t.drive());
// Register a named singleton. // Register a named singleton.
container.registerNamedSingleton('the_truck', truck); container.registerNamedSingleton('the_truck', truck);
@ -37,7 +37,7 @@ Future<void> main() async {
truck.drive(); truck.drive();
// Should print the same. // Should print the same.
container.findByName<Truck>('the_truck').drive(); container.findByName<Truck>('the_truck')!.drive();
// We can make a child container with its own factory. // We can make a child container with its own factory.
var childContainer = container.createChild(); var childContainer = container.createChild();
@ -47,10 +47,10 @@ Future<void> main() async {
}); });
// Make a truck with 5666 HP. // Make a truck with 5666 HP.
childContainer.make<Truck>().drive(); childContainer.make<Truck>()!.drive();
// However, calling `make<Engine>` will return the Engine singleton we created above. // However, calling `make<Engine>` will return the Engine singleton we created above.
print(childContainer.make<Engine>().horsePower); print(childContainer.make<Engine>()!.horsePower);
} }
abstract class Truck { abstract class Truck {
@ -64,12 +64,12 @@ class Engine {
} }
class _TruckImpl implements Truck { class _TruckImpl implements Truck {
final Engine engine; final Engine? engine;
_TruckImpl(this.engine); _TruckImpl(this.engine);
@override @override
void drive() { void drive() {
print('Vroom! I have ${engine.horsePower} horsepower in my engine.'); print('Vroom! I have ${engine!.horsePower} horsepower in my engine.');
} }
} }

View file

@ -7,11 +7,11 @@ class Container {
final Map<Type, dynamic> _singletons = {}; final Map<Type, dynamic> _singletons = {};
final Map<Type, dynamic Function(Container)> _factories = {}; final Map<Type, dynamic Function(Container)> _factories = {};
final Map<String, dynamic> _namedSingletons = {}; final Map<String, dynamic> _namedSingletons = {};
final Container _parent; final Container? _parent;
Container(this.reflector) : _parent = null; Container(this.reflector) : _parent = null;
Container._child(this._parent) : reflector = _parent.reflector; Container._child(Container this._parent) : reflector = _parent.reflector;
bool get isRoot => _parent == null; bool get isRoot => _parent == null;
@ -23,8 +23,8 @@ class Container {
} }
/// Determines if the container has an injection of the given type. /// Determines if the container has an injection of the given type.
bool has<T>([Type t]) { bool has<T>([Type? t]) {
var search = this; Container? search = this;
t ??= T == dynamic ? t : T; t ??= T == dynamic ? t : T;
while (search != null) { while (search != null) {
@ -42,7 +42,7 @@ class Container {
/// Determines if the container has a named singleton with the given [name]. /// Determines if the container has a named singleton with the given [name].
bool hasNamed(String name) { bool hasNamed(String name) {
var search = this; Container? search = this;
while (search != null) { while (search != null) {
if (search._namedSingletons.containsKey(name)) { if (search._namedSingletons.containsKey(name)) {
@ -59,9 +59,9 @@ class Container {
/// ///
/// It is similar to [make], but resolves an injection of either /// It is similar to [make], but resolves an injection of either
/// `Future<T>` or `T`. /// `Future<T>` or `T`.
Future<T> makeAsync<T>([Type type]) { Future<T>? makeAsync<T>([Type? type]) {
type ??= T; type ??= T;
Type futureType; //.Future<T>.value(null).runtimeType; Type? futureType; //.Future<T>.value(null).runtimeType;
if (T == dynamic) { if (T == dynamic) {
try { try {
@ -87,18 +87,18 @@ class Container {
/// ///
/// In contexts where a static generic type cannot be used, use /// In contexts where a static generic type cannot be used, use
/// the [type] argument, instead of [T]. /// the [type] argument, instead of [T].
T make<T>([Type type]) { T? make<T>([Type? type]) {
type ??= T; type ??= T;
var search = this; Container? search = this;
while (search != null) { while (search != null) {
if (search._singletons.containsKey(type)) { if (search._singletons.containsKey(type)) {
// Find a singleton, if any. // Find a singleton, if any.
return search._singletons[type] as T; return search._singletons[type] as T?;
} else if (search._factories.containsKey(type)) { } else if (search._factories.containsKey(type)) {
// Find a factory, if any. // Find a factory, if any.
return search._factories[type](this) as T; return search._factories[type]!(this) as T?;
} else { } else {
search = search._parent; search = search._parent;
} }
@ -115,8 +115,8 @@ class Container {
var constructor = reflectedType.constructors.firstWhere( var constructor = reflectedType.constructors.firstWhere(
(c) => isDefault(c.name), (c) => isDefault(c.name),
orElse: () => throw ReflectionException( orElse: (() => throw ReflectionException(
'${reflectedType.name} has no default constructor, and therefore cannot be instantiated.')); '${reflectedType.name} has no default constructor, and therefore cannot be instantiated.')) as ReflectedFunction Function()?);
for (var param in constructor.parameters) { for (var param in constructor.parameters) {
var value = make(param.type.reflectedType); var value = make(param.type.reflectedType);
@ -131,7 +131,7 @@ class Container {
return reflectedType.newInstance( return reflectedType.newInstance(
isDefault(constructor.name) ? '' : constructor.name, isDefault(constructor.name) ? '' : constructor.name,
positional, positional,
named, []).reflectee as T; named, []).reflectee as T?;
} else { } else {
throw ReflectionException( throw ReflectionException(
'$type is not a class, and therefore cannot be instantiated.'); '$type is not a class, and therefore cannot be instantiated.');
@ -144,7 +144,7 @@ class Container {
/// ///
/// Returns [f]. /// Returns [f].
T Function(Container) registerLazySingleton<T>(T Function(Container) f, T Function(Container) registerLazySingleton<T>(T Function(Container) f,
{Type as}) { {Type? as}) {
return registerFactory<T>( return registerFactory<T>(
(container) { (container) {
var r = f(container); var r = f(container);
@ -159,7 +159,7 @@ class Container {
/// type within *this* container will return the result of [f]. /// type within *this* container will return the result of [f].
/// ///
/// Returns [f]. /// Returns [f].
T Function(Container) registerFactory<T>(T Function(Container) f, {Type as}) { T Function(Container) registerFactory<T>(T Function(Container) f, {Type? as}) {
as ??= T; as ??= T;
if (_factories.containsKey(as)) { if (_factories.containsKey(as)) {
@ -174,7 +174,7 @@ class Container {
/// type within *this* container will return [object]. /// type within *this* container will return [object].
/// ///
/// Returns [object]. /// Returns [object].
T registerSingleton<T>(T object, {Type as}) { T registerSingleton<T>(T object, {Type? as}) {
as ??= T == dynamic ? as : T; as ??= T == dynamic ? as : T;
if (_singletons.containsKey(as ?? object.runtimeType)) { if (_singletons.containsKey(as ?? object.runtimeType)) {
@ -192,11 +192,11 @@ class Container {
/// ///
/// [findByName] is best reserved for internal logic that end users of code should /// [findByName] is best reserved for internal logic that end users of code should
/// not see. /// not see.
T findByName<T>(String name) { T? findByName<T>(String name) {
if (_namedSingletons.containsKey(name)) { if (_namedSingletons.containsKey(name)) {
return _namedSingletons[name] as T; return _namedSingletons[name] as T?;
} else if (_parent != null) { } else if (_parent != null) {
return _parent.findByName<T>(name); return _parent!.findByName<T>(name);
} else { } else {
throw StateError( throw StateError(
'This container does not have a singleton named "$name".'); 'This container does not have a singleton named "$name".');

View file

@ -1,6 +1,6 @@
import '../../angel_container.dart'; import '../../angel_container.dart';
final Map<Symbol, String> _symbolNames = <Symbol, String>{}; final Map<Symbol, String?> _symbolNames = <Symbol, String?>{};
/// A [Reflector] implementation that performs no actual reflection, /// A [Reflector] implementation that performs no actual reflection,
/// instead returning empty objects on every invocation. /// instead returning empty objects on every invocation.
@ -13,9 +13,9 @@ class EmptyReflector extends Reflector {
const EmptyReflector(); const EmptyReflector();
@override @override
String getName(Symbol symbol) { String? getName(Symbol symbol) {
return _symbolNames.putIfAbsent( return _symbolNames.putIfAbsent(
symbol, () => symbolRegex.firstMatch(symbol.toString()).group(1)); symbol, () => symbolRegex.firstMatch(symbol.toString())!.group(1));
} }
@override @override
@ -52,13 +52,13 @@ class _EmptyReflectedClass extends ReflectedClass {
@override @override
ReflectedInstance newInstance( ReflectedInstance newInstance(
String constructorName, List positionalArguments, String constructorName, List positionalArguments,
[Map<String, dynamic> namedArguments, List<Type> typeArguments]) { [Map<String, dynamic>? namedArguments, List<Type>? typeArguments]) {
throw UnsupportedError( throw UnsupportedError(
'Classes reflected via an EmptyReflector cannot be instantiated.'); 'Classes reflected via an EmptyReflector cannot be instantiated.');
} }
@override @override
bool isAssignableTo(ReflectedType other) { bool isAssignableTo(ReflectedType? other) {
return other == this; return other == this;
} }
@ -75,13 +75,13 @@ class _EmptyReflectedType extends ReflectedType {
@override @override
ReflectedInstance newInstance( ReflectedInstance newInstance(
String constructorName, List positionalArguments, String constructorName, List positionalArguments,
[Map<String, dynamic> namedArguments, List<Type> typeArguments]) { [Map<String, dynamic>? namedArguments, List<Type>? typeArguments]) {
throw UnsupportedError( throw UnsupportedError(
'Types reflected via an EmptyReflector cannot be instantiated.'); 'Types reflected via an EmptyReflector cannot be instantiated.');
} }
@override @override
bool isAssignableTo(ReflectedType other) { bool isAssignableTo(ReflectedType? other) {
return other == this; return other == this;
} }

View file

@ -85,7 +85,7 @@ class _ReflectedTypeMirror extends ReflectedType {
); );
@override @override
bool isAssignableTo(ReflectedType other) { bool isAssignableTo(ReflectedType? other) {
if (other is _ReflectedClassMirror) { if (other is _ReflectedClassMirror) {
return mirror.isAssignableTo(other.mirror); return mirror.isAssignableTo(other.mirror);
} else if (other is _ReflectedTypeMirror) { } else if (other is _ReflectedTypeMirror) {
@ -98,7 +98,7 @@ class _ReflectedTypeMirror extends ReflectedType {
@override @override
ReflectedInstance newInstance( ReflectedInstance newInstance(
String constructorName, List positionalArguments, String constructorName, List positionalArguments,
[Map<String, dynamic> namedArguments, List<Type> typeArguments]) { [Map<String, dynamic>? namedArguments, List<Type>? typeArguments]) {
throw ReflectionException( throw ReflectionException(
'$name is not a class, and therefore cannot be instantiated.'); '$name is not a class, and therefore cannot be instantiated.');
} }
@ -154,7 +154,7 @@ class _ReflectedClassMirror extends ReflectedClass {
List<ReflectedFunction> get constructors => _constructorsOf(mirror); List<ReflectedFunction> get constructors => _constructorsOf(mirror);
@override @override
bool isAssignableTo(ReflectedType other) { bool isAssignableTo(ReflectedType? other) {
if (other is _ReflectedClassMirror) { if (other is _ReflectedClassMirror) {
return mirror.isAssignableTo(other.mirror); return mirror.isAssignableTo(other.mirror);
} else if (other is _ReflectedTypeMirror) { } else if (other is _ReflectedTypeMirror) {
@ -167,7 +167,7 @@ class _ReflectedClassMirror extends ReflectedClass {
@override @override
ReflectedInstance newInstance( ReflectedInstance newInstance(
String constructorName, List positionalArguments, String constructorName, List positionalArguments,
[Map<String, dynamic> namedArguments, List<Type> typeArguments]) { [Map<String, dynamic>? namedArguments, List<Type>? typeArguments]) {
return _ReflectedInstanceMirror( return _ReflectedInstanceMirror(
mirror.newInstance(Symbol(constructorName), positionalArguments)); mirror.newInstance(Symbol(constructorName), positionalArguments));
} }
@ -207,7 +207,7 @@ class _ReflectedInstanceMirror extends ReflectedInstance {
class _ReflectedMethodMirror extends ReflectedFunction { class _ReflectedMethodMirror extends ReflectedFunction {
final dart.MethodMirror mirror; final dart.MethodMirror mirror;
final dart.ClosureMirror closureMirror; final dart.ClosureMirror? closureMirror;
_ReflectedMethodMirror(this.mirror, [this.closureMirror]) _ReflectedMethodMirror(this.mirror, [this.closureMirror])
: super( : super(
@ -242,7 +242,7 @@ class _ReflectedMethodMirror extends ReflectedFunction {
'This object was reflected without a ClosureMirror, and therefore cannot be directly invoked.'); 'This object was reflected without a ClosureMirror, and therefore cannot be directly invoked.');
} }
return _ReflectedInstanceMirror(closureMirror.invoke(invocation.memberName, return _ReflectedInstanceMirror(closureMirror!.invoke(invocation.memberName,
invocation.positionalArguments, invocation.namedArguments)); invocation.positionalArguments, invocation.namedArguments));
} }
} }

View file

@ -4,15 +4,15 @@ import 'package:quiver/core.dart';
abstract class Reflector { abstract class Reflector {
const Reflector(); const Reflector();
String getName(Symbol symbol); String? getName(Symbol symbol);
ReflectedClass reflectClass(Type clazz); ReflectedClass? reflectClass(Type clazz);
ReflectedFunction reflectFunction(Function function); ReflectedFunction? reflectFunction(Function function);
ReflectedType reflectType(Type type); ReflectedType? reflectType(Type type);
ReflectedInstance reflectInstance(Object object); ReflectedInstance? reflectInstance(Object object);
ReflectedType reflectFutureOf(Type type) { ReflectedType reflectFutureOf(Type type) {
throw UnsupportedError('`reflectFutureOf` requires `dart:mirrors`.'); throw UnsupportedError('`reflectFutureOf` requires `dart:mirrors`.');
@ -22,7 +22,7 @@ abstract class Reflector {
abstract class ReflectedInstance { abstract class ReflectedInstance {
final ReflectedType type; final ReflectedType type;
final ReflectedClass clazz; final ReflectedClass clazz;
final Object reflectee; final Object? reflectee;
const ReflectedInstance(this.type, this.clazz, this.reflectee); const ReflectedInstance(this.type, this.clazz, this.reflectee);
@ -56,9 +56,9 @@ abstract class ReflectedType {
ReflectedInstance newInstance( ReflectedInstance newInstance(
String constructorName, List positionalArguments, String constructorName, List positionalArguments,
[Map<String, dynamic> namedArguments, List<Type> typeArguments]); [Map<String, dynamic>? namedArguments, List<Type>? typeArguments]);
bool isAssignableTo(ReflectedType other); bool isAssignableTo(ReflectedType? other);
} }
abstract class ReflectedClass extends ReflectedType { abstract class ReflectedClass extends ReflectedType {
@ -94,7 +94,7 @@ abstract class ReflectedClass extends ReflectedType {
class ReflectedDeclaration { class ReflectedDeclaration {
final String name; final String name;
final bool isStatic; final bool isStatic;
final ReflectedFunction function; final ReflectedFunction? function;
const ReflectedDeclaration(this.name, this.isStatic, this.function); const ReflectedDeclaration(this.name, this.isStatic, this.function);

View file

@ -16,7 +16,7 @@ class StaticReflector extends Reflector {
this.instances = const {}}); this.instances = const {}});
@override @override
String getName(Symbol symbol) { String? getName(Symbol symbol) {
if (!names.containsKey(symbol)) { if (!names.containsKey(symbol)) {
throw ArgumentError( throw ArgumentError(
'The value of $symbol is unknown - it was not generated.'); 'The value of $symbol is unknown - it was not generated.');
@ -26,11 +26,11 @@ class StaticReflector extends Reflector {
} }
@override @override
ReflectedClass reflectClass(Type clazz) => ReflectedClass? reflectClass(Type clazz) =>
reflectType(clazz) as ReflectedClass; reflectType(clazz) as ReflectedClass?;
@override @override
ReflectedFunction reflectFunction(Function function) { ReflectedFunction? reflectFunction(Function function) {
if (!functions.containsKey(function)) { if (!functions.containsKey(function)) {
throw ArgumentError( throw ArgumentError(
'There is no reflection information available about $function.'); 'There is no reflection information available about $function.');
@ -40,7 +40,7 @@ class StaticReflector extends Reflector {
} }
@override @override
ReflectedInstance reflectInstance(Object object) { ReflectedInstance? reflectInstance(Object object) {
if (!instances.containsKey(object)) { if (!instances.containsKey(object)) {
throw ArgumentError( throw ArgumentError(
'There is no reflection information available about $object.'); 'There is no reflection information available about $object.');
@ -50,7 +50,7 @@ class StaticReflector extends Reflector {
} }
@override @override
ReflectedType reflectType(Type type) { ReflectedType? reflectType(Type type) {
if (!types.containsKey(type)) { if (!types.containsKey(type)) {
throw ArgumentError( throw ArgumentError(
'There is no reflection information available about $type.'); 'There is no reflection information available about $type.');

View file

@ -17,7 +17,7 @@ class ThrowingReflector extends Reflector {
const ThrowingReflector({this.errorMessage = defaultErrorMessage}); const ThrowingReflector({this.errorMessage = defaultErrorMessage});
@override @override
String getName(Symbol symbol) => const EmptyReflector().getName(symbol); String? getName(Symbol symbol) => const EmptyReflector().getName(symbol);
UnsupportedError _error() => UnsupportedError(errorMessage); UnsupportedError _error() => UnsupportedError(errorMessage);

View file

@ -1,13 +1,13 @@
name: angel_container name: angel_container
version: 2.0.0 version: 3.0.0
author: Tobe O <thosakwe@gmail.com> author: Tobe O <thosakwe@gmail.com>
description: A hierarchical DI container, and pluggable backends for reflection. description: A hierarchical DI container, and pluggable backends for reflection.
homepage: https://github.com/angel-dart/container.git homepage: https://github.com/angel-dart/container.git
environment: environment:
sdk: ">=2.10.0 <3.0.0" sdk: '>=2.12.0 <3.0.0'
dependencies: dependencies:
collection: ^1.15.0 collection: ^1.15.0
quiver: ^2.1.5 quiver: ^3.0.0
dev_dependencies: dev_dependencies:
pedantic: ^1.11.0 pedantic: ^1.11.0
test: ^1.16.5 test: ^1.16.8

View file

@ -7,7 +7,7 @@ void returnVoidFromAFunction(int x) {}
void testReflector(Reflector reflector) { void testReflector(Reflector reflector) {
var blaziken = Pokemon('Blaziken', PokemonType.fire); var blaziken = Pokemon('Blaziken', PokemonType.fire);
Container container; late Container container;
setUp(() { setUp(() {
container = Container(reflector); container = Container(reflector);
@ -16,7 +16,7 @@ void testReflector(Reflector reflector) {
}); });
test('get field', () { test('get field', () {
var blazikenMirror = reflector.reflectInstance(blaziken); var blazikenMirror = reflector.reflectInstance(blaziken)!;
expect(blazikenMirror.getField('type').reflectee, blaziken.type); expect(blazikenMirror.getField('type').reflectee, blaziken.type);
}); });
@ -24,19 +24,19 @@ void testReflector(Reflector reflector) {
var mirror = reflector.reflectFunction(returnVoidFromAFunction); var mirror = reflector.reflectFunction(returnVoidFromAFunction);
test('void return type returns dynamic', () { test('void return type returns dynamic', () {
expect(mirror.returnType, reflector.reflectType(dynamic)); expect(mirror!.returnType, reflector.reflectType(dynamic));
}); });
test('counts parameters', () { test('counts parameters', () {
expect(mirror.parameters, hasLength(1)); expect(mirror!.parameters, hasLength(1));
}); });
test('counts types parameters', () { test('counts types parameters', () {
expect(mirror.typeParameters, isEmpty); expect(mirror!.typeParameters, isEmpty);
}); });
test('correctly reflects parameter types', () { test('correctly reflects parameter types', () {
var p = mirror.parameters[0]; var p = mirror!.parameters[0];
expect(p.name, 'x'); expect(p.name, 'x');
expect(p.isRequired, true); expect(p.isRequired, true);
expect(p.isNamed, false); expect(p.isNamed, false);
@ -67,12 +67,12 @@ void testReflector(Reflector reflector) {
}); });
test('constructor injects singleton', () { test('constructor injects singleton', () {
var lower = container.make<LowerPokemon>(); var lower = container.make<LowerPokemon>()!;
expect(lower.lowercaseName, blaziken.name.toLowerCase()); expect(lower.lowercaseName, blaziken.name.toLowerCase());
}); });
test('newInstance works', () { test('newInstance works', () {
var type = container.reflector.reflectType(Pokemon); var type = container.reflector.reflectType(Pokemon)!;
var instance = var instance =
type.newInstance('changeName', [blaziken, 'Charizard']).reflectee type.newInstance('changeName', [blaziken, 'Charizard']).reflectee
as Pokemon; as Pokemon;
@ -83,7 +83,7 @@ void testReflector(Reflector reflector) {
test('isAssignableTo', () { test('isAssignableTo', () {
var pokemonType = container.reflector.reflectType(Pokemon); var pokemonType = container.reflector.reflectType(Pokemon);
var kantoPokemonType = container.reflector.reflectType(KantoPokemon); var kantoPokemonType = container.reflector.reflectType(KantoPokemon)!;
expect(kantoPokemonType.isAssignableTo(pokemonType), true); expect(kantoPokemonType.isAssignableTo(pokemonType), true);
expect( expect(

View file

@ -2,7 +2,7 @@ import 'package:angel_container/angel_container.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
void main() { void main() {
Container container; late Container container;
setUp(() { setUp(() {
container = Container(const EmptyReflector()) container = Container(const EmptyReflector())
@ -37,14 +37,14 @@ void main() {
} }
class Artist { class Artist {
final String name; final String? name;
final Song song; final Song? song;
Artist({this.name, this.song}); Artist({this.name, this.song});
} }
class Song { class Song {
final String title; final String? title;
Song({this.title}); Song({this.title});
} }

View file

@ -2,7 +2,7 @@ import 'package:angel_container/angel_container.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
void main() { void main() {
Container container; late Container container;
setUp(() { setUp(() {
container = Container(const EmptyReflector()); container = Container(const EmptyReflector());
@ -10,7 +10,7 @@ void main() {
}); });
test('fetch by name', () { test('fetch by name', () {
expect(container.findByName<Foo>('foo').bar, 'baz'); expect(container.findByName<Foo>('foo')!.bar, 'baz');
}); });
test('cannot redefine', () { test('cannot redefine', () {
@ -28,7 +28,7 @@ void main() {
} }
class Foo { class Foo {
final String bar; final String? bar;
Foo({this.bar}); Foo({this.bar});
} }