fix(ivy): properly parenthesize ternary expressions when emitted (#34221)

Previously, ternary expressions were emitted as:

condExpr ? trueCase : falseCase

However, this causes problems when ternary operations are nested. In
particular, a template expression of the form:

a?.b ? c : d

would have compiled to:

a == null ? null : a.b ? c : d

The ternary operator is right-associative, so that expression is interpreted
as:

a == null ? null : (a.b ? c : d)

when in reality left-associativity is desired in this particular instance:

(a == null ? null : a.b) ? c : d

This commit adds a check in the expression translator to detect such
left-associative usages of ternaries and to enforce such associativity with
parentheses when necessary.

A test is also added for the template type-checking expression translator,
to ensure it correctly produces right-associative expressions for ternaries
in the user's template.

Fixes #34087

PR Close #34221
This commit is contained in:
Alex Rickabaugh
2019-12-03 17:46:45 -08:00
committed by Andrew Kushnir
parent f72de51a6f
commit 718d7fe5fe
3 changed files with 59 additions and 1 deletions

View File

@ -755,4 +755,29 @@ describe('compiler compliance: template', () => {
expectEmit(result.source, template, 'Incorrect template');
});
it('should safely nest ternary operations', () => {
const files = {
app: {
'spec.ts': `
import {Component, NgModule} from '@angular/core';
@Component({
selector: 'my-component',
template: \`
{{a?.b ? 1 : 2 }}\`
})
export class MyComponent {}
@NgModule({declarations: [MyComponent]})
export class MyModule {}
`
}
};
const template = `i0.ɵɵtextInterpolate1(" ", (ctx.a == null ? null : ctx.a.b) ? 1 : 2, "")`;
const result = compile(files, angularFiles);
expectEmit(result.source, template, 'Incorrect template');
});
});