Skip to content

Commit

Permalink
fix(Compiler): relax childIsRecursive check
Browse files Browse the repository at this point in the history
Fix how the compiler checks for recursive components by also considering
component descendants. Previously, it only checked if the current
component was evaluated previously. This failed in certain cases of
mutually recursive components, causing `createAsync` in tests to not
resolve.

closes [7084](#7084)
  • Loading branch information
KiaraGrouwstra committed Jun 22, 2016
1 parent 397f5e2 commit f832dc9
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 4 deletions.
4 changes: 3 additions & 1 deletion modules/@angular/compiler/src/runtime_compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,9 @@ export class RuntimeCompiler implements ComponentResolver {
this._metadataResolver.getViewDirectivesMetadata(dep.comp.type.runtime);
var childViewPipes: CompilePipeMetadata[] =
this._metadataResolver.getViewPipesMetadata(dep.comp.type.runtime);
var childIsRecursive = ListWrapper.contains(childCompilingComponentsPath, childCacheKey);
var childIsRecursive = childCompilingComponentsPath.indexOf(childCacheKey) > -1 ||
childViewDirectives.some(
dir => childCompilingComponentsPath.indexOf(dir.type.runtime) > -1);
childCompilingComponentsPath.push(childCacheKey);

var childComp = this._loadAndCompileComponent(
Expand Down
45 changes: 42 additions & 3 deletions modules/@angular/core/test/linker/regression_integration_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {AsyncTestCompleter} from '@angular/core/testing/testing_internal';

import {IS_DART} from '../../src/facade/lang';

import {Component, Pipe, PipeTransform, provide, ViewMetadata, OpaqueToken, Injector} from '@angular/core';
import {Component, Pipe, PipeTransform, provide, ViewMetadata, PLATFORM_PIPES, OpaqueToken, Injector, forwardRef} from '@angular/core';
import {NgIf, NgClass} from '@angular/common';
import {CompilerConfig} from '@angular/compiler';

Expand Down Expand Up @@ -162,8 +162,7 @@ function declareTests({useJit}: {useJit: boolean}) {

it('should support ngClass before a component and content projection inside of an ngIf',
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
[TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async: any) => {
tcb.overrideView(
MyComp1, new ViewMetadata({
template: `A<cmp-content *ngIf="true" [ngClass]="'red'">B</cmp-content>C`,
Expand All @@ -177,6 +176,15 @@ function declareTests({useJit}: {useJit: boolean}) {
});
}));

it('should handle mutual recursion entered from multiple sides - #7084',
inject(
[TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async: any) => {
tcb.createAsync(FakeRecursiveComp).then((fixture) => {
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('[]');
async.done();
});
}));

});
}
Expand All @@ -199,3 +207,34 @@ class CustomPipe implements PipeTransform {
@Component({selector: 'cmp-content', template: `<ng-content></ng-content>`})
class CmpWithNgContent {
}

@Component({
selector: 'left',
template: `L<right *ngIf="false"></right>`,
directives: [
forwardRef(() => RightComp),
]
})
class LeftComp {
}

@Component({
selector: 'right',
template: `R<left *ngIf="false"></left>`,
directives: [
forwardRef(() => LeftComp),
]
})
class RightComp {
}

@Component({
selector: 'fakeRecursiveComp',
template: `[<left *ngIf="false"></left><right *ngIf="false"></right>]`,
directives: [
forwardRef(() => LeftComp),
forwardRef(() => RightComp),
]
})
export class FakeRecursiveComp {
}

0 comments on commit f832dc9

Please sign in to comment.