From 529805508ae47c564e0ed26ff261c2918c24dd9e Mon Sep 17 00:00:00 2001 From: Tim Blasi Date: Thu, 4 Jun 2015 15:53:16 -0700 Subject: [PATCH] feat(dart/change_detect): Add type to ChangeDetector context Add a type for the `context` field in Dart's pre-generated change detectors. This requires slight changes to set the dehydrated value of `context` to `null` rather than `ChangeDetectionUtil.uninitialized()`, which was its former dehydrated state. Mirror these chagnes as closely as possible in the `ChangeDetectionJITGenerator` to allow easier maintenance. Closes #2070 --- .../change_detection_jit_generator.ts | 8 ++- .../change_detector_codegen.dart | 50 ++++++++++++------- .../template_compiler/generator.dart | 2 +- .../generator/gen_change_detectors.dart | 2 +- .../expected/bar.ng_deps.dart | 9 ++-- 5 files changed, 44 insertions(+), 27 deletions(-) diff --git a/modules/angular2/src/change_detection/change_detection_jit_generator.ts b/modules/angular2/src/change_detection/change_detection_jit_generator.ts index 06742bc74a..ba63826aea 100644 --- a/modules/angular2/src/change_detection/change_detection_jit_generator.ts +++ b/modules/angular2/src/change_detection/change_detection_jit_generator.ts @@ -131,7 +131,7 @@ export class ChangeDetectorJITGenerator { } ${this.typeName}.prototype.hydrated = function() { - return ${CONTEXT_ACCESSOR} !== ${UTIL}.uninitialized(); + return Boolean(${CONTEXT_ACCESSOR}); } return function(dispatcher, pipeRegistry) { @@ -173,7 +173,11 @@ export class ChangeDetectorJITGenerator { fields = fields.concat(this._getNonNullPipeNames()); fields = fields.concat(this._genGetDirectiveFieldNames()); fields = fields.concat(this._genGetDetectorFieldNames()); - return fields.map((n) => `${n} = ${UTIL}.uninitialized();`).join("\n"); + return fields.map((n) => { + return n == CONTEXT_ACCESSOR ? `${n} = null;` : + `${n} = ${UTIL}.uninitialized();`; + }) + .join("\n"); } _genHydrateDirectives(): string { diff --git a/modules/angular2/src/transform/template_compiler/change_detector_codegen.dart b/modules/angular2/src/transform/template_compiler/change_detector_codegen.dart index 2916382e77..71afdf641a 100644 --- a/modules/angular2/src/transform/template_compiler/change_detector_codegen.dart +++ b/modules/angular2/src/transform/template_compiler/change_detector_codegen.dart @@ -15,8 +15,11 @@ import 'package:angular2/src/change_detection/proto_record.dart'; class Codegen { final StringBuffer _buf = new StringBuffer(); - void generate(String name, ChangeDetectorDefinition def) { - new _CodegenState(name, def)._writeToBuf(_buf); + /// Generates a change detector class with name `changeDetectorTypeName` + /// which is used to detect changes in Objects of type `typeName`. + void generate(String typeName, String changeDetectorTypeName, + ChangeDetectorDefinition def) { + new _CodegenState(typeName, changeDetectorTypeName, def)._writeToBuf(_buf); } String get imports { @@ -33,7 +36,8 @@ class Codegen { /// The state needed to generate a change detector for a single `Component`. class _CodegenState { - final String _typeName; + final String _contextTypeName; + final String _changeDetectorTypeName; final String _changeDetectionMode; final List _records; final List _directiveRecords; @@ -42,8 +46,9 @@ class _CodegenState { final List _fieldNames; final List _pipeNames; - _CodegenState._(this._typeName, String changeDetectionStrategy, this._records, - this._directiveRecords, List localNames) + _CodegenState._(this._contextTypeName, this._changeDetectorTypeName, + String changeDetectionStrategy, this._records, this._directiveRecords, + List localNames) : this._localNames = localNames, _changeNames = _getChangeNames(localNames), _fieldNames = _getFieldNames(localNames), @@ -51,21 +56,23 @@ class _CodegenState { _changeDetectionMode = ChangeDetectionUtil .changeDetectionMode(changeDetectionStrategy); - factory _CodegenState(String typeName, ChangeDetectorDefinition def) { + factory _CodegenState(String typeName, String changeDetectorTypeName, + ChangeDetectorDefinition def) { var protoRecords = new ProtoRecordBuilder(); def.bindingRecords .forEach((rec) => protoRecords.add(rec, def.variableNames)); var records = coalesce(protoRecords.records); - return new _CodegenState._(typeName, def.strategy, records, - def.directiveRecords, _getLocalNames(records)); + return new _CodegenState._(typeName, changeDetectorTypeName, def.strategy, + records, def.directiveRecords, _getLocalNames(records)); } /// Generates sanitized names for use as local variables. static List _getLocalNames(List records) { + var whitespacePattern = new RegExp(r'\W'); var localNames = new List(records.length + 1); localNames[0] = 'context'; for (var i = 0; i < records.length; ++i) { - var sanitizedName = records[i].name.replaceAll(new RegExp(r'\W'), ''); + var sanitizedName = records[i].name.replaceAll(whitespacePattern, ''); localNames[i + 1] = '$sanitizedName$i'; } return localNames; @@ -85,17 +92,21 @@ class _CodegenState { void _writeToBuf(StringBuffer buf) { buf.write(''' - class $_typeName extends $_BASE_CLASS { + class $_changeDetectorTypeName extends $_BASE_CLASS { final dynamic $_DISPATCHER_ACCESSOR; final $_GEN_PREFIX.PipeRegistry $_PIPE_REGISTRY_ACCESSOR; final $_GEN_PREFIX.List<$_GEN_PREFIX.ProtoRecord> $_PROTOS_ACCESSOR; final $_GEN_PREFIX.List<$_GEN_PREFIX.DirectiveRecord> $_DIRECTIVES_ACCESSOR; dynamic $_LOCALS_ACCESSOR = null; - ${_allFields().map( - (f) => 'dynamic $f = $_UTIL.uninitialized();').join('')} + ${_allFields().map((f) { + if (f == _CONTEXT_ACCESSOR) { + return '$_contextTypeName $f = null;'; + } + return 'dynamic $f = $_UTIL.uninitialized();'; + }).join('')} - $_typeName( + $_changeDetectorTypeName( this.$_DISPATCHER_ACCESSOR, this.$_PIPE_REGISTRY_ACCESSOR, this.$_PROTOS_ACCESSOR, @@ -116,7 +127,7 @@ class _CodegenState { ${_getCallOnAllChangesDoneBody()} } - void hydrate(context, locals, directives) { + void hydrate($_contextTypeName context, locals, directives) { $_MODE_ACCESSOR = '$_changeDetectionMode'; $_CONTEXT_ACCESSOR = context; $_LOCALS_ACCESSOR = locals; @@ -126,19 +137,22 @@ class _CodegenState { void dehydrate() { ${_genPipeOnDestroy()} - ${_allFields().map((f) => '$f = $_UTIL.uninitialized();').join('')} + ${_allFields().map((f) { + return f == _CONTEXT_ACCESSOR + ? '$f = null;' + : '$f = $_UTIL.uninitialized();'; + }).join('')} $_LOCALS_ACCESSOR = null; } - hydrated() => !$_IDENTICAL_CHECK_FN( - $_CONTEXT_ACCESSOR, $_UTIL.uninitialized()); + hydrated() => $_CONTEXT_ACCESSOR == null; static $_GEN_PREFIX.ProtoChangeDetector $PROTO_CHANGE_DETECTOR_FACTORY_METHOD( $_GEN_PREFIX.PipeRegistry registry, $_GEN_PREFIX.ChangeDetectorDefinition def) { return new $_GEN_PREFIX.PregenProtoChangeDetector( - (a, b, c, d) => new $_typeName(a, b, c, d), + (a, b, c, d) => new $_changeDetectorTypeName(a, b, c, d), registry, def); } } diff --git a/modules/angular2/src/transform/template_compiler/generator.dart b/modules/angular2/src/transform/template_compiler/generator.dart index a3f574ee83..4f4fb69cee 100644 --- a/modules/angular2/src/transform/template_compiler/generator.dart +++ b/modules/angular2/src/transform/template_compiler/generator.dart @@ -48,7 +48,7 @@ Future processTemplates(AssetReader reader, AssetId entryPoint, var defs = getChangeDetectorDefinitions(viewDefEntry.hostMetadata, result.protoView, viewDefEntry.viewDef.directives); for (var i = 0; i < defs.length; ++i) { - changeDetectorClasses.generate( + changeDetectorClasses.generate('${rType.typeName}', '_${rType.typeName}_ChangeDetector$i', defs[i]); } diff --git a/modules/angular2/test/change_detection/generator/gen_change_detectors.dart b/modules/angular2/test/change_detection/generator/gen_change_detectors.dart index 16a67e073e..5b7ef61a83 100644 --- a/modules/angular2/test/change_detection/generator/gen_change_detectors.dart +++ b/modules/angular2/test/change_detection/generator/gen_change_detectors.dart @@ -13,7 +13,7 @@ void main(List args) { var allDefs = getAllDefinitions('propName'); for (var i = 0; i < allDefs.length; ++i) { var className = 'ChangeDetector${i}'; - codegen.generate(className, allDefs[i]); + codegen.generate('dynamic', className, allDefs[i]); if (i > 0) { buf.write(','); } diff --git a/modules/angular2/test/transform/integration/two_annotations_files/expected/bar.ng_deps.dart b/modules/angular2/test/transform/integration/two_annotations_files/expected/bar.ng_deps.dart index dfcb5996fe..66f7e6878e 100644 --- a/modules/angular2/test/transform/integration/two_annotations_files/expected/bar.ng_deps.dart +++ b/modules/angular2/test/transform/integration/two_annotations_files/expected/bar.ng_deps.dart @@ -27,7 +27,7 @@ class _MyComponent_ChangeDetector0 extends _gen.AbstractChangeDetector { final _gen.List<_gen.ProtoRecord> _protos; final _gen.List<_gen.DirectiveRecord> _directiveRecords; dynamic _locals = null; - dynamic _context = _gen.ChangeDetectionUtil.uninitialized(); + MyComponent _context = null; _MyComponent_ChangeDetector0(this._dispatcher, this._pipeRegistry, this._protos, this._directiveRecords) @@ -45,19 +45,18 @@ class _MyComponent_ChangeDetector0 extends _gen.AbstractChangeDetector { void callOnAllChangesDone() {} - void hydrate(context, locals, directives) { + void hydrate(MyComponent context, locals, directives) { mode = 'ALWAYS_CHECK'; _context = context; _locals = locals; } void dehydrate() { - _context = _gen.ChangeDetectionUtil.uninitialized(); + _context = null; _locals = null; } - hydrated() => - !_gen.looseIdentical(_context, _gen.ChangeDetectionUtil.uninitialized()); + hydrated() => _context == null; static _gen.ProtoChangeDetector newProtoChangeDetector( _gen.PipeRegistry registry, _gen.ChangeDetectorDefinition def) {