feat(change_detect): Guard `checkNoChanges` behind `assertionsEnabled`

Always generate `checkNoChanges` tests, but guard them behind
`assertionsEnabled` tests.

Closes #4560
This commit is contained in:
Tim Blasi 2015-10-28 10:06:53 -07:00
parent 2d0c8f1b0e
commit 63e853dcd7
14 changed files with 42 additions and 60 deletions

View File

@ -40,10 +40,7 @@ export function compilerProviders(): Array<Type | Provider | any[]> {
CommandCompiler, CommandCompiler,
ChangeDetectionCompiler, ChangeDetectionCompiler,
provide(ChangeDetectorGenConfig, provide(ChangeDetectorGenConfig,
{ {useValue: new ChangeDetectorGenConfig(assertionsEnabled(), false, true)}),
useValue:
new ChangeDetectorGenConfig(assertionsEnabled(), assertionsEnabled(), false, true)
}),
TemplateCompiler, TemplateCompiler,
provide(RuntimeCompiler, {useClass: RuntimeCompiler_}), provide(RuntimeCompiler, {useClass: RuntimeCompiler_}),
provide(Compiler, {useExisting: RuntimeCompiler}), provide(Compiler, {useExisting: RuntimeCompiler}),

View File

@ -1,5 +1,4 @@
import {isPresent, isBlank, StringWrapper} from 'angular2/src/core/facade/lang'; import {assertionsEnabled, isPresent, isBlank, StringWrapper} from 'angular2/src/core/facade/lang';
import {BaseException} from 'angular2/src/core/facade/exceptions';
import {ListWrapper} from 'angular2/src/core/facade/collection'; import {ListWrapper} from 'angular2/src/core/facade/collection';
import {ChangeDetectionUtil} from './change_detection_util'; import {ChangeDetectionUtil} from './change_detection_util';
import {ChangeDetectorRef, ChangeDetectorRef_} from './change_detector_ref'; import {ChangeDetectorRef, ChangeDetectorRef_} from './change_detector_ref';
@ -76,7 +75,11 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
detectChanges(): void { this.runDetectChanges(false); } detectChanges(): void { this.runDetectChanges(false); }
checkNoChanges(): void { throw new BaseException("Not implemented"); } checkNoChanges(): void {
if (assertionsEnabled()) {
this.runDetectChanges(true);
}
}
runDetectChanges(throwOnChange: boolean): void { runDetectChanges(throwOnChange: boolean): void {
if (this.mode === ChangeDetectionStrategy.Detached || if (this.mode === ChangeDetectionStrategy.Detached ||

View File

@ -1,4 +1,10 @@
import {Type, isBlank, isPresent, StringWrapper} from 'angular2/src/core/facade/lang'; import {
Type,
assertionsEnabled,
isBlank,
isPresent,
StringWrapper
} from 'angular2/src/core/facade/lang';
import {BaseException} from 'angular2/src/core/facade/exceptions'; import {BaseException} from 'angular2/src/core/facade/exceptions';
import {ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/core/facade/collection'; import {ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/core/facade/collection';
@ -97,8 +103,6 @@ export class ChangeDetectorJITGenerator {
${this._maybeGenHandleEventInternal()} ${this._maybeGenHandleEventInternal()}
${this._genCheckNoChanges()}
${this._maybeGenAfterContentLifecycleCallbacks()} ${this._maybeGenAfterContentLifecycleCallbacks()}
${this._maybeGenAfterViewLifecycleCallbacks()} ${this._maybeGenAfterViewLifecycleCallbacks()}
@ -434,7 +438,7 @@ export class ChangeDetectorJITGenerator {
/** @internal */ /** @internal */
_genThrowOnChangeCheck(oldValue: string, newValue: string): string { _genThrowOnChangeCheck(oldValue: string, newValue: string): string {
if (this.genConfig.genCheckNoChanges) { if (assertionsEnabled()) {
return ` return `
if(throwOnChange) { if(throwOnChange) {
this.throwOnChangeError(${oldValue}, ${newValue}); this.throwOnChangeError(${oldValue}, ${newValue});
@ -445,15 +449,6 @@ export class ChangeDetectorJITGenerator {
} }
} }
/** @internal */
_genCheckNoChanges(): string {
if (this.genConfig.genCheckNoChanges) {
return `${this.typeName}.prototype.checkNoChanges = function() { this.runDetectChanges(true); }`;
} else {
return '';
}
}
/** @internal */ /** @internal */
_genAddToChanges(r: ProtoRecord): string { _genAddToChanges(r: ProtoRecord): string {
var newValue = this._names.getLocalName(r.selfIndex); var newValue = this._names.getLocalName(r.selfIndex);

View File

@ -39,8 +39,8 @@ export interface ChangeDetector {
export interface ProtoChangeDetector { instantiate(dispatcher: ChangeDispatcher): ChangeDetector; } export interface ProtoChangeDetector { instantiate(dispatcher: ChangeDispatcher): ChangeDetector; }
export class ChangeDetectorGenConfig { export class ChangeDetectorGenConfig {
constructor(public genCheckNoChanges: boolean, public genDebugInfo: boolean, constructor(public genDebugInfo: boolean, public logBindingUpdate: boolean,
public logBindingUpdate: boolean, public useJit: boolean) {} public useJit: boolean) {}
} }
export class ChangeDetectorDefinition { export class ChangeDetectorDefinition {

View File

@ -19,7 +19,7 @@ export 'package:angular2/src/core/change_detection/proto_record.dart'
show ProtoRecord; show ProtoRecord;
export 'package:angular2/src/core/change_detection/change_detection_util.dart' export 'package:angular2/src/core/change_detection/change_detection_util.dart'
show ChangeDetectionUtil; show ChangeDetectionUtil;
export 'package:angular2/src/core/facade/lang.dart' show looseIdentical; export 'package:angular2/src/core/facade/lang.dart' show assertionsEnabled, looseIdentical;
typedef ProtoChangeDetector PregenProtoChangeDetectorFactory( typedef ProtoChangeDetector PregenProtoChangeDetectorFactory(
ChangeDetectorDefinition definition); ChangeDetectorDefinition definition);

View File

@ -89,8 +89,7 @@ function _getAppBindings() {
return [ return [
compilerProviders(), compilerProviders(),
provide(ChangeDetectorGenConfig, provide(ChangeDetectorGenConfig, {useValue: new ChangeDetectorGenConfig(true, false, true)}),
{useValue: new ChangeDetectorGenConfig(true, true, false, true)}),
provide(DOCUMENT, {useValue: appDoc}), provide(DOCUMENT, {useValue: appDoc}),
provide(DomRenderer, {useClass: DomRenderer_}), provide(DomRenderer, {useClass: DomRenderer_}),
provide(Renderer, {useExisting: DomRenderer}), provide(Renderer, {useExisting: DomRenderer}),

View File

@ -64,7 +64,7 @@ export function main() {
var protoChangeDetectors = var protoChangeDetectors =
createChangeDetectorDefinitions(new CompileTypeMetadata({name: 'SomeComp'}), createChangeDetectorDefinitions(new CompileTypeMetadata({name: 'SomeComp'}),
ChangeDetectionStrategy.Default, ChangeDetectionStrategy.Default,
new ChangeDetectorGenConfig(true, true, false, false), new ChangeDetectorGenConfig(true, false, false),
parser.parse(template, directives, 'TestComp')) parser.parse(template, directives, 'TestComp'))
.map(definition => new DynamicProtoChangeDetector(definition)); .map(definition => new DynamicProtoChangeDetector(definition));
var changeDetector = protoChangeDetectors[protoViewIndex].instantiate(dispatcher); var changeDetector = protoChangeDetectors[protoViewIndex].instantiate(dispatcher);

View File

@ -80,7 +80,7 @@ export function main() {
describe('no jit', () => { describe('no jit', () => {
beforeEachBindings(() => [ beforeEachBindings(() => [
provide(ChangeDetectorGenConfig, provide(ChangeDetectorGenConfig,
{useValue: new ChangeDetectorGenConfig(true, true, false, false)}) {useValue: new ChangeDetectorGenConfig(true, false, false)})
]); ]);
it('should watch element properties', () => { it('should watch element properties', () => {
expect(detectChanges(compiler, '<div [el-prop]="someProp">')) expect(detectChanges(compiler, '<div [el-prop]="someProp">'))
@ -91,7 +91,7 @@ export function main() {
describe('jit', () => { describe('jit', () => {
beforeEachBindings(() => [ beforeEachBindings(() => [
provide(ChangeDetectorGenConfig, provide(ChangeDetectorGenConfig,
{useValue: new ChangeDetectorGenConfig(true, true, false, true)}) {useValue: new ChangeDetectorGenConfig(true, false, true)})
]); ]);
it('should watch element properties', () => { it('should watch element properties', () => {
expect(detectChanges(compiler, '<div [el-prop]="someProp">')) expect(detectChanges(compiler, '<div [el-prop]="someProp">'))

View File

@ -65,7 +65,7 @@ export const PROP_NAME = 'propName';
* In this case, we expect `id` and `expression` to be the same string. * In this case, we expect `id` and `expression` to be the same string.
*/ */
export function getDefinition(id: string): TestDefinition { export function getDefinition(id: string): TestDefinition {
var genConfig = new ChangeDetectorGenConfig(true, true, true, true); var genConfig = new ChangeDetectorGenConfig(true, true, true);
var testDef = null; var testDef = null;
if (StringMapWrapper.contains(_ExpressionWithLocals.availableDefinitions, id)) { if (StringMapWrapper.contains(_ExpressionWithLocals.availableDefinitions, id)) {
let val = StringMapWrapper.get(_ExpressionWithLocals.availableDefinitions, id); let val = StringMapWrapper.get(_ExpressionWithLocals.availableDefinitions, id);
@ -121,7 +121,7 @@ export function getDefinition(id: string): TestDefinition {
[_DirectiveUpdating.recordNoCallbacks], genConfig); [_DirectiveUpdating.recordNoCallbacks], genConfig);
testDef = new TestDefinition(id, cdDef, null); testDef = new TestDefinition(id, cdDef, null);
} else if (id == "updateElementProduction") { } else if (id == "updateElementProduction") {
var genConfig = new ChangeDetectorGenConfig(false, false, false, true); var genConfig = new ChangeDetectorGenConfig(false, false, true);
var records = _createBindingRecords("name"); var records = _createBindingRecords("name");
let cdDef = new ChangeDetectorDefinition(id, null, [], records, [], [], genConfig); let cdDef = new ChangeDetectorDefinition(id, null, [], records, [], [], genConfig);
testDef = new TestDefinition(id, cdDef, null); testDef = new TestDefinition(id, cdDef, null);
@ -167,7 +167,7 @@ class _ExpressionWithLocals {
var variableBindings = _convertLocalsToVariableBindings(this.locals); var variableBindings = _convertLocalsToVariableBindings(this.locals);
var bindingRecords = _createBindingRecords(this._expression); var bindingRecords = _createBindingRecords(this._expression);
var directiveRecords = []; var directiveRecords = [];
var genConfig = new ChangeDetectorGenConfig(true, true, true, true); var genConfig = new ChangeDetectorGenConfig(true, true, true);
return new ChangeDetectorDefinition('(empty id)', strategy, variableBindings, bindingRecords, return new ChangeDetectorDefinition('(empty id)', strategy, variableBindings, bindingRecords,
[], directiveRecords, genConfig); [], directiveRecords, genConfig);
} }
@ -231,7 +231,7 @@ class _ExpressionWithMode {
_createHostEventRecords("(host-event)='false'", dirRecordWithOnPush)) _createHostEventRecords("(host-event)='false'", dirRecordWithOnPush))
} }
var genConfig = new ChangeDetectorGenConfig(true, true, true, true); var genConfig = new ChangeDetectorGenConfig(true, true, true);
return new ChangeDetectorDefinition('(empty id)', this._strategy, variableBindings, return new ChangeDetectorDefinition('(empty id)', this._strategy, variableBindings,
bindingRecords, eventRecords, directiveRecords, genConfig); bindingRecords, eventRecords, directiveRecords, genConfig);
@ -260,7 +260,7 @@ class _DirectiveUpdating {
createChangeDetectorDefinition(): ChangeDetectorDefinition { createChangeDetectorDefinition(): ChangeDetectorDefinition {
var strategy = null; var strategy = null;
var variableBindings = []; var variableBindings = [];
var genConfig = new ChangeDetectorGenConfig(true, true, true, true); var genConfig = new ChangeDetectorGenConfig(true, true, true);
return new ChangeDetectorDefinition('(empty id)', strategy, variableBindings, return new ChangeDetectorDefinition('(empty id)', strategy, variableBindings,
this._bindingRecords, [], this._directiveRecords, this._bindingRecords, [], this._directiveRecords,

View File

@ -1575,7 +1575,7 @@ export function main() {
describe('logging property updates', () => { describe('logging property updates', () => {
beforeEachBindings(() => [ beforeEachBindings(() => [
provide(ChangeDetectorGenConfig, provide(ChangeDetectorGenConfig,
{useValue: new ChangeDetectorGenConfig(true, true, true, false)}) {useValue: new ChangeDetectorGenConfig(true, true, false)})
]); ]);
it('should reflect property values as attributes', it('should reflect property values as attributes',

View File

@ -248,7 +248,7 @@ function setUpChangeDetection(protoChangeDetectorFactory: Function, iterations,
var dispatcher = new DummyDispatcher(); var dispatcher = new DummyDispatcher();
var parser = new Parser(new Lexer()); var parser = new Parser(new Lexer());
var genConfig = new ChangeDetectorGenConfig(false, false, false, true); var genConfig = new ChangeDetectorGenConfig(false, false, true);
var parentProto = protoChangeDetectorFactory( var parentProto = protoChangeDetectorFactory(
new ChangeDetectorDefinition('parent', null, [], [], [], [], genConfig)); new ChangeDetectorDefinition('parent', null, [], [], [], [], genConfig));
var parentCd = parentProto.instantiate(dispatcher); var parentCd = parentProto.instantiate(dispatcher);

View File

@ -35,8 +35,7 @@ function _createBindings(): Provider[] {
}), }),
// Use DynamicChangeDetector as that is the only one that Dart supports as well // Use DynamicChangeDetector as that is the only one that Dart supports as well
// so that we can compare the numbers between JS and Dart // so that we can compare the numbers between JS and Dart
provide(ChangeDetectorGenConfig, provide(ChangeDetectorGenConfig, {useValue: new ChangeDetectorGenConfig(false, false, false)})
{useValue: new ChangeDetectorGenConfig(false, false, false, false)})
]; ];
} }

View File

@ -123,7 +123,8 @@ class _CodegenState {
var names = new CodegenNameUtil( var names = new CodegenNameUtil(
protoRecords, eventBindings, def.directiveRecords, '$genPrefix$_UTIL'); protoRecords, eventBindings, def.directiveRecords, '$genPrefix$_UTIL');
var logic = new CodegenLogicUtil(names, '$genPrefix$_UTIL', '$genPrefix$_STATE', def.strategy); var logic = new CodegenLogicUtil(
names, '$genPrefix$_UTIL', '$genPrefix$_STATE', def.strategy);
return new _CodegenState._( return new _CodegenState._(
genPrefix, genPrefix,
def.id, def.id,
@ -163,8 +164,6 @@ class _CodegenState {
${_maybeGenHandleEventInternal()} ${_maybeGenHandleEventInternal()}
${_genCheckNoChanges()}
${_maybeGenAfterContentLifecycleCallbacks()} ${_maybeGenAfterContentLifecycleCallbacks()}
${_maybeGenAfterViewLifecycleCallbacks()} ${_maybeGenAfterViewLifecycleCallbacks()}
@ -515,23 +514,11 @@ class _CodegenState {
} }
String _genThrowOnChangeCheck(String oldValue, String newValue) { String _genThrowOnChangeCheck(String oldValue, String newValue) {
if (this._genConfig.genCheckNoChanges) { return '''
return ''' if(${_genPrefix}assertionsEnabled() && throwOnChange) {
if(throwOnChange) { this.throwOnChangeError(${oldValue}, ${newValue});
this.throwOnChangeError(${oldValue}, ${newValue}); }
} ''';
''';
} else {
return "";
}
}
String _genCheckNoChanges() {
if (this._genConfig.genCheckNoChanges) {
return 'void checkNoChanges() { runDetectChanges(true); }';
} else {
return '';
}
} }
String _maybeFirstInBinding(ProtoRecord r) { String _maybeFirstInBinding(ProtoRecord r) {

View File

@ -28,8 +28,10 @@ import 'compile_data_creator.dart';
/// ///
/// This method assumes a {@link DomAdapter} has been registered. /// This method assumes a {@link DomAdapter} has been registered.
Future<Outputs> processTemplates(AssetReader reader, AssetId assetId, Future<Outputs> processTemplates(AssetReader reader, AssetId assetId,
{bool reflectPropertiesAsAttributes: false, List<String> ambientDirectives}) async { {bool reflectPropertiesAsAttributes: false,
var viewDefResults = await createCompileData(reader, assetId, ambientDirectives); List<String> ambientDirectives}) async {
var viewDefResults =
await createCompileData(reader, assetId, ambientDirectives);
if (viewDefResults == null) return null; if (viewDefResults == null) return null;
final directiveMetadatas = viewDefResults.ngMeta.types.values; final directiveMetadatas = viewDefResults.ngMeta.types.values;
if (directiveMetadatas.isNotEmpty) { if (directiveMetadatas.isNotEmpty) {
@ -45,7 +47,7 @@ Future<Outputs> processTemplates(AssetReader reader, AssetId assetId,
var templateCompiler = zone.templateCompiler; var templateCompiler = zone.templateCompiler;
if (templateCompiler == null) { if (templateCompiler == null) {
templateCompiler = createTemplateCompiler(reader, templateCompiler = createTemplateCompiler(reader,
changeDetectionConfig: new ChangeDetectorGenConfig(assertionsEnabled(), changeDetectionConfig: new ChangeDetectorGenConfig(
assertionsEnabled(), reflectPropertiesAsAttributes, false)); assertionsEnabled(), reflectPropertiesAsAttributes, false));
} }