From 84fd965e3e7bc577fa96a5d551c435c0939cd78e Mon Sep 17 00:00:00 2001 From: tycho01 Date: Wed, 18 May 2016 13:50:32 +0800 Subject: [PATCH] fix(Compiler): relax childIsRecursive check 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](https://github.com/angular/angular/issues/7084) --- .../@angular/compiler/src/runtime_compiler.ts | 5 +++ .../linker/regression_integration_spec.ts | 39 ++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/modules/@angular/compiler/src/runtime_compiler.ts b/modules/@angular/compiler/src/runtime_compiler.ts index f2db5c07dba4fa..89d5b355b144bf 100644 --- a/modules/@angular/compiler/src/runtime_compiler.ts +++ b/modules/@angular/compiler/src/runtime_compiler.ts @@ -116,6 +116,11 @@ export class RuntimeCompiler implements ComponentResolver { var childViewPipes: CompilePipeMetadata[] = this._metadataResolver.getViewPipesMetadata(dep.comp.type.runtime); var childIsRecursive = ListWrapper.contains(childCompilingComponentsPath, childCacheKey); + childViewDirectives.map(x => x.type.runtime).forEach(descendant => { + if (ListWrapper.contains(childCompilingComponentsPath, descendant)) { + childIsRecursive = true; + } + }); 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 cfbd42c0908d3c..8de4f6e6c6ee43 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, PLATFORM_PIPES, 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'; @@ -180,6 +180,15 @@ function declareTests(isJit: boolean) { }); })); + it('should handle mutual recursion entered from multiple sides - #7084', + inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => { + tcb.createAsync(FakeRecursiveComp) + .then((fixture) => { + fixture.detectChanges(); + expect(fixture.nativeElement).toHaveText('[]'); + async.done(); + }); + })); }); } @@ -202,3 +211,31 @@ class CustomPipe implements PipeTransform { @Component({selector: 'cmp-content', template: ``}) class CmpWithNgContent { } + +@Component({ + selector: 'left', + template: `L`, + directives: [ + forwardRef(() => RightComp), + ] +}) +class LeftComp {} + +@Component({ + selector: 'right', + template: `R`, + directives: [ + forwardRef(() => LeftComp), + ] +}) +class RightComp {} + +@Component({ + selector: 'fakeRecursiveComp', + template: `[]`, + directives: [ + forwardRef(() => LeftComp), + forwardRef(() => RightComp), + ] +}) +class FakeRecursiveComp {}