diff --git a/modules/@angular/compiler/src/runtime_compiler.ts b/modules/@angular/compiler/src/runtime_compiler.ts index 504eab0074..8275c27cfa 100644 --- a/modules/@angular/compiler/src/runtime_compiler.ts +++ b/modules/@angular/compiler/src/runtime_compiler.ts @@ -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( diff --git a/modules/@angular/core/test/linker/regression_integration_spec.ts b/modules/@angular/core/test/linker/regression_integration_spec.ts index 71eb42383b..5de0418b86 100644 --- a/modules/@angular/core/test/linker/regression_integration_spec.ts +++ b/modules/@angular/core/test/linker/regression_integration_spec.ts @@ -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'; @@ -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: `ABC`, @@ -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(); + }); + })); }); } @@ -199,3 +207,37 @@ class CustomPipe implements PipeTransform { @Component({selector: 'cmp-content', template: ``}) class CmpWithNgContent { } + +@Component({ + selector: 'left', + template: `L`, + directives: [ + NgIf, + forwardRef(() => RightComp), + ] +}) +class LeftComp { +} + +@Component({ + selector: 'right', + template: `R`, + directives: [ + NgIf, + forwardRef(() => LeftComp), + ] +}) +class RightComp { +} + +@Component({ + selector: 'fakeRecursiveComp', + template: `[]`, + directives: [ + NgIf, + forwardRef(() => LeftComp), + forwardRef(() => RightComp), + ] +}) +export class FakeRecursiveComp { +}