feat(compiler): support unary operators for more accurate type checking (#37918)
Prior to this change, the unary + and - operators would be parsed as `x - 0` and `0 - x` respectively. The runtime semantics of these expressions are equivalent, however they may introduce inaccurate template type checking errors as the literal type is lost, for example: ```ts @Component({ template: `<button [disabled]="isAdjacent(-1)"></button>` }) export class Example { isAdjacent(direction: -1 | 1): boolean { return false; } } ``` would incorrectly report a type-check error: > error TS2345: Argument of type 'number' is not assignable to parameter of type '-1 | 1'. Additionally, the translated expression for the unary + operator would be considered as arithmetic expression with an incompatible left-hand side: > error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. To resolve this issues, the implicit transformation should be avoided. This commit adds a new unary AST node to represent these expressions, allowing for more accurate type-checking. Fixes #20845 Fixes #36178 PR Close #37918
This commit is contained in:
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {AbsoluteSourceSpan, AST, AstVisitor, ASTWithSource, Binary, BindingPipe, Chain, Conditional, FunctionCall, ImplicitReceiver, Interpolation, KeyedRead, KeyedWrite, LiteralArray, LiteralMap, LiteralPrimitive, MethodCall, NonNullAssert, ParseSpan, PrefixNot, PropertyRead, PropertyWrite, Quote, RecursiveAstVisitor, SafeMethodCall, SafePropertyRead} from '../../../src/expression_parser/ast';
|
||||
import {AST, AstVisitor, ASTWithSource, Binary, BindingPipe, Chain, Conditional, FunctionCall, ImplicitReceiver, Interpolation, KeyedRead, KeyedWrite, LiteralArray, LiteralMap, LiteralPrimitive, MethodCall, NonNullAssert, ParseSpan, PrefixNot, PropertyRead, PropertyWrite, Quote, RecursiveAstVisitor, SafeMethodCall, SafePropertyRead, Unary} from '../../../src/expression_parser/ast';
|
||||
import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from '../../../src/ml_parser/interpolation_config';
|
||||
|
||||
class Unparser implements AstVisitor {
|
||||
@ -35,6 +35,11 @@ class Unparser implements AstVisitor {
|
||||
this._visit(ast.value);
|
||||
}
|
||||
|
||||
visitUnary(ast: Unary, context: any) {
|
||||
this._expression += ast.operator;
|
||||
this._visit(ast.expr);
|
||||
}
|
||||
|
||||
visitBinary(ast: Binary, context: any) {
|
||||
this._visit(ast.left);
|
||||
this._expression += ` ${ast.operation} `;
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {AST, Binary, BindingPipe, Chain, Conditional, FunctionCall, ImplicitReceiver, Interpolation, KeyedRead, KeyedWrite, LiteralArray, LiteralMap, LiteralPrimitive, MethodCall, ParseSpan, PrefixNot, PropertyRead, PropertyWrite, Quote, RecursiveAstVisitor, SafeMethodCall, SafePropertyRead} from '../../../src/expression_parser/ast';
|
||||
import {AST, Binary, BindingPipe, Chain, Conditional, FunctionCall, ImplicitReceiver, Interpolation, KeyedRead, KeyedWrite, LiteralArray, LiteralMap, LiteralPrimitive, MethodCall, ParseSpan, PrefixNot, PropertyRead, PropertyWrite, Quote, RecursiveAstVisitor, SafeMethodCall, SafePropertyRead, Unary} from '../../../src/expression_parser/ast';
|
||||
|
||||
import {unparse} from './unparser';
|
||||
|
||||
@ -34,6 +34,10 @@ class ASTValidator extends RecursiveAstVisitor {
|
||||
this.parentSpan = oldParent;
|
||||
}
|
||||
|
||||
visitUnary(ast: Unary, context: any): any {
|
||||
this.validate(ast, () => super.visitUnary(ast, context));
|
||||
}
|
||||
|
||||
visitBinary(ast: Binary, context: any): any {
|
||||
this.validate(ast, () => super.visitBinary(ast, context));
|
||||
}
|
||||
|
Reference in New Issue
Block a user