From d761059e4d6bf4036c45347e3053c366989e38a4 Mon Sep 17 00:00:00 2001 From: Chuck Jazdzewski Date: Tue, 16 May 2017 16:36:51 -0700 Subject: [PATCH] fix(compiler-cli): allow '==' to compare nullable types (#16731) Fixes: #16729 * fix(compiler-cli): diagnose issues in conditional of ternary Fixes: #16730 --- .../src/diagnostics/expression_type.ts | 28 +++++++++++++++++-- .../expression_diagnostics_spec.ts | 12 +++++++- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/packages/compiler-cli/src/diagnostics/expression_type.ts b/packages/compiler-cli/src/diagnostics/expression_type.ts index cdecaa0f7d..9ee89e1bba 100644 --- a/packages/compiler-cli/src/diagnostics/expression_type.ts +++ b/packages/compiler-cli/src/diagnostics/expression_type.ts @@ -51,8 +51,29 @@ export class AstType implements AstVisitor { return kind; } - const leftType = this.getType(ast.left); - const rightType = this.getType(ast.right); + const getType = (ast: AST, operation: string): Symbol => { + const type = this.getType(ast); + if (type.nullable) { + switch (operation) { + case '&&': + case '||': + case '==': + case '!=': + case '===': + case '!==': + // Nullable allowed. + break; + default: + this.reportError(`The expression might be null`, ast); + break; + } + return this.query.getNonNullableType(type); + } + return type; + }; + + const leftType = getType(ast.left, ast.operation); + const rightType = getType(ast.right, ast.operation); const leftRawKind = this.query.getTypeKind(leftType); const rightRawKind = this.query.getTypeKind(rightType); const leftKind = normalize(leftRawKind, rightRawKind); @@ -166,6 +187,9 @@ export class AstType implements AstVisitor { visitConditional(ast: Conditional) { // The type of a conditional is the union of the true and false conditions. + if (this.diagnostics) { + visitAstChildren(ast, this); + } return this.query.getTypeUnion(this.getType(ast.trueExp), this.getType(ast.falseExp)); } diff --git a/packages/compiler-cli/test/diagnostics/expression_diagnostics_spec.ts b/packages/compiler-cli/test/diagnostics/expression_diagnostics_spec.ts index db2ceceacd..ae8be64e13 100644 --- a/packages/compiler-cli/test/diagnostics/expression_diagnostics_spec.ts +++ b/packages/compiler-cli/test/diagnostics/expression_diagnostics_spec.ts @@ -175,7 +175,16 @@ describe('expression diagnostics', () => { it('should reject an uncalled event handler', () => reject( '
{{person.name.first}}
', 'Unexpected callable expression')); - + describe('with comparisions between nullable and non-nullable', () => { + it('should accept ==', () => accept(`
{{e == 1 ? 'a' : 'b'}}
`)); + it('should accept ===', () => accept(`
{{e === 1 ? 'a' : 'b'}}
`)); + it('should accept !=', () => accept(`
{{e != 1 ? 'a' : 'b'}}
`)); + it('should accept !==', () => accept(`
{{e !== 1 ? 'a' : 'b'}}
`)); + it('should accept &&', () => accept(`
{{e && 1 ? 'a' : 'b'}}
`)); + it('should accept ||', () => accept(`
{{e || 1 ? 'a' : 'b'}}
`)); + it('should reject >', + () => reject(`
{{e > 1 ? 'a' : 'b'}}
`, 'The expression might be null')); + }); }); const FILES: Directory = { @@ -216,6 +225,7 @@ const FILES: Directory = { promised_people: Promise; private private_person: Person; private private_people: Person[]; + e?: number; getPerson(): Person { return this.person; } click() {}