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() {
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 {

View File

@ -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<ProtoRecord> _records;
final List<DirectiveRecord> _directiveRecords;
@ -42,8 +46,9 @@ class _CodegenState {
final List<String> _fieldNames;
final List<String> _pipeNames;
_CodegenState._(this._typeName, String changeDetectionStrategy, this._records,
this._directiveRecords, List<String> localNames)
_CodegenState._(this._contextTypeName, this._changeDetectorTypeName,
String changeDetectionStrategy, this._records, this._directiveRecords,
List<String> 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<String> _getLocalNames(List<ProtoRecord> records) {
var whitespacePattern = new RegExp(r'\W');
var localNames = new List<String>(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);
}
}

View File

@ -48,7 +48,7 @@ Future<String> 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]);
}

View File

@ -13,7 +13,7 @@ void main(List<String> 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(',');
}

View File

@ -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) {