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
This commit is contained in:
Tim Blasi 2015-06-04 15:53:16 -07:00
parent 851797aecb
commit 529805508a
5 changed files with 44 additions and 27 deletions

View File

@ -131,7 +131,7 @@ export class ChangeDetectorJITGenerator {
} }
${this.typeName}.prototype.hydrated = function() { ${this.typeName}.prototype.hydrated = function() {
return ${CONTEXT_ACCESSOR} !== ${UTIL}.uninitialized(); return Boolean(${CONTEXT_ACCESSOR});
} }
return function(dispatcher, pipeRegistry) { return function(dispatcher, pipeRegistry) {
@ -173,7 +173,11 @@ export class ChangeDetectorJITGenerator {
fields = fields.concat(this._getNonNullPipeNames()); fields = fields.concat(this._getNonNullPipeNames());
fields = fields.concat(this._genGetDirectiveFieldNames()); fields = fields.concat(this._genGetDirectiveFieldNames());
fields = fields.concat(this._genGetDetectorFieldNames()); 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 { _genHydrateDirectives(): string {

View File

@ -15,8 +15,11 @@ import 'package:angular2/src/change_detection/proto_record.dart';
class Codegen { class Codegen {
final StringBuffer _buf = new StringBuffer(); final StringBuffer _buf = new StringBuffer();
void generate(String name, ChangeDetectorDefinition def) { /// Generates a change detector class with name `changeDetectorTypeName`
new _CodegenState(name, def)._writeToBuf(_buf); /// 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 { String get imports {
@ -33,7 +36,8 @@ class Codegen {
/// The state needed to generate a change detector for a single `Component`. /// The state needed to generate a change detector for a single `Component`.
class _CodegenState { class _CodegenState {
final String _typeName; final String _contextTypeName;
final String _changeDetectorTypeName;
final String _changeDetectionMode; final String _changeDetectionMode;
final List<ProtoRecord> _records; final List<ProtoRecord> _records;
final List<DirectiveRecord> _directiveRecords; final List<DirectiveRecord> _directiveRecords;
@ -42,8 +46,9 @@ class _CodegenState {
final List<String> _fieldNames; final List<String> _fieldNames;
final List<String> _pipeNames; final List<String> _pipeNames;
_CodegenState._(this._typeName, String changeDetectionStrategy, this._records, _CodegenState._(this._contextTypeName, this._changeDetectorTypeName,
this._directiveRecords, List<String> localNames) String changeDetectionStrategy, this._records, this._directiveRecords,
List<String> localNames)
: this._localNames = localNames, : this._localNames = localNames,
_changeNames = _getChangeNames(localNames), _changeNames = _getChangeNames(localNames),
_fieldNames = _getFieldNames(localNames), _fieldNames = _getFieldNames(localNames),
@ -51,21 +56,23 @@ class _CodegenState {
_changeDetectionMode = ChangeDetectionUtil _changeDetectionMode = ChangeDetectionUtil
.changeDetectionMode(changeDetectionStrategy); .changeDetectionMode(changeDetectionStrategy);
factory _CodegenState(String typeName, ChangeDetectorDefinition def) { factory _CodegenState(String typeName, String changeDetectorTypeName,
ChangeDetectorDefinition def) {
var protoRecords = new ProtoRecordBuilder(); var protoRecords = new ProtoRecordBuilder();
def.bindingRecords def.bindingRecords
.forEach((rec) => protoRecords.add(rec, def.variableNames)); .forEach((rec) => protoRecords.add(rec, def.variableNames));
var records = coalesce(protoRecords.records); var records = coalesce(protoRecords.records);
return new _CodegenState._(typeName, def.strategy, records, return new _CodegenState._(typeName, changeDetectorTypeName, def.strategy,
def.directiveRecords, _getLocalNames(records)); records, def.directiveRecords, _getLocalNames(records));
} }
/// Generates sanitized names for use as local variables. /// Generates sanitized names for use as local variables.
static List<String> _getLocalNames(List<ProtoRecord> records) { static List<String> _getLocalNames(List<ProtoRecord> records) {
var whitespacePattern = new RegExp(r'\W');
var localNames = new List<String>(records.length + 1); var localNames = new List<String>(records.length + 1);
localNames[0] = 'context'; localNames[0] = 'context';
for (var i = 0; i < records.length; ++i) { 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'; localNames[i + 1] = '$sanitizedName$i';
} }
return localNames; return localNames;
@ -85,17 +92,21 @@ class _CodegenState {
void _writeToBuf(StringBuffer buf) { void _writeToBuf(StringBuffer buf) {
buf.write(''' buf.write('''
class $_typeName extends $_BASE_CLASS { class $_changeDetectorTypeName extends $_BASE_CLASS {
final dynamic $_DISPATCHER_ACCESSOR; final dynamic $_DISPATCHER_ACCESSOR;
final $_GEN_PREFIX.PipeRegistry $_PIPE_REGISTRY_ACCESSOR; final $_GEN_PREFIX.PipeRegistry $_PIPE_REGISTRY_ACCESSOR;
final $_GEN_PREFIX.List<$_GEN_PREFIX.ProtoRecord> $_PROTOS_ACCESSOR; final $_GEN_PREFIX.List<$_GEN_PREFIX.ProtoRecord> $_PROTOS_ACCESSOR;
final $_GEN_PREFIX.List<$_GEN_PREFIX.DirectiveRecord> final $_GEN_PREFIX.List<$_GEN_PREFIX.DirectiveRecord>
$_DIRECTIVES_ACCESSOR; $_DIRECTIVES_ACCESSOR;
dynamic $_LOCALS_ACCESSOR = null; dynamic $_LOCALS_ACCESSOR = null;
${_allFields().map( ${_allFields().map((f) {
(f) => 'dynamic $f = $_UTIL.uninitialized();').join('')} if (f == _CONTEXT_ACCESSOR) {
return '$_contextTypeName $f = null;';
}
return 'dynamic $f = $_UTIL.uninitialized();';
}).join('')}
$_typeName( $_changeDetectorTypeName(
this.$_DISPATCHER_ACCESSOR, this.$_DISPATCHER_ACCESSOR,
this.$_PIPE_REGISTRY_ACCESSOR, this.$_PIPE_REGISTRY_ACCESSOR,
this.$_PROTOS_ACCESSOR, this.$_PROTOS_ACCESSOR,
@ -116,7 +127,7 @@ class _CodegenState {
${_getCallOnAllChangesDoneBody()} ${_getCallOnAllChangesDoneBody()}
} }
void hydrate(context, locals, directives) { void hydrate($_contextTypeName context, locals, directives) {
$_MODE_ACCESSOR = '$_changeDetectionMode'; $_MODE_ACCESSOR = '$_changeDetectionMode';
$_CONTEXT_ACCESSOR = context; $_CONTEXT_ACCESSOR = context;
$_LOCALS_ACCESSOR = locals; $_LOCALS_ACCESSOR = locals;
@ -126,19 +137,22 @@ class _CodegenState {
void dehydrate() { void dehydrate() {
${_genPipeOnDestroy()} ${_genPipeOnDestroy()}
${_allFields().map((f) => '$f = $_UTIL.uninitialized();').join('')} ${_allFields().map((f) {
return f == _CONTEXT_ACCESSOR
? '$f = null;'
: '$f = $_UTIL.uninitialized();';
}).join('')}
$_LOCALS_ACCESSOR = null; $_LOCALS_ACCESSOR = null;
} }
hydrated() => !$_IDENTICAL_CHECK_FN( hydrated() => $_CONTEXT_ACCESSOR == null;
$_CONTEXT_ACCESSOR, $_UTIL.uninitialized());
static $_GEN_PREFIX.ProtoChangeDetector static $_GEN_PREFIX.ProtoChangeDetector
$PROTO_CHANGE_DETECTOR_FACTORY_METHOD( $PROTO_CHANGE_DETECTOR_FACTORY_METHOD(
$_GEN_PREFIX.PipeRegistry registry, $_GEN_PREFIX.PipeRegistry registry,
$_GEN_PREFIX.ChangeDetectorDefinition def) { $_GEN_PREFIX.ChangeDetectorDefinition def) {
return new $_GEN_PREFIX.PregenProtoChangeDetector( 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); registry, def);
} }
} }

View File

@ -48,7 +48,7 @@ Future<String> processTemplates(AssetReader reader, AssetId entryPoint,
var defs = getChangeDetectorDefinitions(viewDefEntry.hostMetadata, var defs = getChangeDetectorDefinitions(viewDefEntry.hostMetadata,
result.protoView, viewDefEntry.viewDef.directives); result.protoView, viewDefEntry.viewDef.directives);
for (var i = 0; i < defs.length; ++i) { for (var i = 0; i < defs.length; ++i) {
changeDetectorClasses.generate( changeDetectorClasses.generate('${rType.typeName}',
'_${rType.typeName}_ChangeDetector$i', defs[i]); '_${rType.typeName}_ChangeDetector$i', defs[i]);
} }

View File

@ -13,7 +13,7 @@ void main(List<String> args) {
var allDefs = getAllDefinitions('propName'); var allDefs = getAllDefinitions('propName');
for (var i = 0; i < allDefs.length; ++i) { for (var i = 0; i < allDefs.length; ++i) {
var className = 'ChangeDetector${i}'; var className = 'ChangeDetector${i}';
codegen.generate(className, allDefs[i]); codegen.generate('dynamic', className, allDefs[i]);
if (i > 0) { if (i > 0) {
buf.write(','); buf.write(',');
} }

View File

@ -27,7 +27,7 @@ class _MyComponent_ChangeDetector0 extends _gen.AbstractChangeDetector {
final _gen.List<_gen.ProtoRecord> _protos; final _gen.List<_gen.ProtoRecord> _protos;
final _gen.List<_gen.DirectiveRecord> _directiveRecords; final _gen.List<_gen.DirectiveRecord> _directiveRecords;
dynamic _locals = null; dynamic _locals = null;
dynamic _context = _gen.ChangeDetectionUtil.uninitialized(); MyComponent _context = null;
_MyComponent_ChangeDetector0(this._dispatcher, this._pipeRegistry, _MyComponent_ChangeDetector0(this._dispatcher, this._pipeRegistry,
this._protos, this._directiveRecords) this._protos, this._directiveRecords)
@ -45,19 +45,18 @@ class _MyComponent_ChangeDetector0 extends _gen.AbstractChangeDetector {
void callOnAllChangesDone() {} void callOnAllChangesDone() {}
void hydrate(context, locals, directives) { void hydrate(MyComponent context, locals, directives) {
mode = 'ALWAYS_CHECK'; mode = 'ALWAYS_CHECK';
_context = context; _context = context;
_locals = locals; _locals = locals;
} }
void dehydrate() { void dehydrate() {
_context = _gen.ChangeDetectionUtil.uninitialized(); _context = null;
_locals = null; _locals = null;
} }
hydrated() => hydrated() => _context == null;
!_gen.looseIdentical(_context, _gen.ChangeDetectionUtil.uninitialized());
static _gen.ProtoChangeDetector newProtoChangeDetector( static _gen.ProtoChangeDetector newProtoChangeDetector(
_gen.PipeRegistry registry, _gen.ChangeDetectorDefinition def) { _gen.PipeRegistry registry, _gen.ChangeDetectorDefinition def) {