Skip to content

Commit

Permalink
fix(Compiler): relax childIsRecursive check (angular#8705)
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](angular#7084)
  • Loading branch information
KiaraGrouwstra authored and vicb committed Jun 22, 2016
1 parent ef37d2a commit 3d5bb23
Show file tree
Hide file tree
Showing 2 changed files with 48 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
48 changes: 45 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,37 @@ 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: [
NgIf,
forwardRef(() => RightComp),
]
})
class LeftComp {
}

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

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

0 comments on commit 3d5bb23

Please sign in to comment.