fix(ivy): template inputs/outputs should not be bound in template scope (#30669)
The R3TargetBinder "binds" an Angular template AST, computing semantic information regarding the template and making it accessible. One of the binding passes previously had a bug, where for the following template: <div *ngIf="foo as foo"></div> which desugars to: <ng-template ngIf [ngIf]="foo" let-foo="ngIf"> <div></div> </ng-template> would have the `[ngIf]` binding processed twice - in both the scope which contains the `<ng-template>` and the scope inside the template. The bug arises because during the latter, `foo` is a variable defined by `let-foo`, and so the R3TargetBinder would incorrectly learn that `foo` inside `[ngIf]` maps to that variable. This commit fixes the bug by only processing inputs, outputs, and templateAttrs from `Template`s in the outer scope. PR Close #30669
This commit is contained in:
parent
b4644d7bb0
commit
b61784948a
|
@ -270,6 +270,31 @@ describe('ngtsc type checking', () => {
|
|||
expect(diags[0].messageText).toContain('does_not_exist');
|
||||
});
|
||||
|
||||
it('should property type-check a microsyntax variable with the same name as the expression',
|
||||
() => {
|
||||
env.write('test.ts', `
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {Component, Input, NgModule} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'test',
|
||||
template: '<div *ngIf="foo as foo">{{foo}}</div>',
|
||||
})
|
||||
export class TestCmp<T extends {name: string}> {
|
||||
foo: any;
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [TestCmp],
|
||||
imports: [CommonModule],
|
||||
})
|
||||
export class Module {}
|
||||
`);
|
||||
|
||||
const diags = env.driveDiagnostics();
|
||||
expect(diags.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should properly type-check inherited directives', () => {
|
||||
env.write('test.ts', `
|
||||
import {Component, Directive, Input, NgModule} from '@angular/core';
|
||||
|
|
|
@ -372,12 +372,8 @@ class TemplateBinder extends RecursiveAstVisitor implements Visitor {
|
|||
|
||||
private ingest(template: Template|Node[]): void {
|
||||
if (template instanceof Template) {
|
||||
// For <ng-template>s, process inputs, outputs, template attributes,
|
||||
// variables, and child nodes.
|
||||
// References were processed in the scope of the containing template.
|
||||
template.inputs.forEach(this.visitNode);
|
||||
template.outputs.forEach(this.visitNode);
|
||||
template.templateAttrs.forEach(this.visitNode);
|
||||
// For <ng-template>s, process only variables and child nodes. Inputs, outputs, templateAttrs,
|
||||
// and references were all processed in the scope of the containing template.
|
||||
template.variables.forEach(this.visitNode);
|
||||
template.children.forEach(this.visitNode);
|
||||
|
||||
|
|
Loading…
Reference in New Issue