fix(compiler-cli): allow '==' to compare nullable types (#16731)
Fixes: #16729 * fix(compiler-cli): diagnose issues in conditional of ternary Fixes: #16730
This commit is contained in:
parent
c805082648
commit
d761059e4d
|
@ -51,8 +51,29 @@ export class AstType implements AstVisitor {
|
||||||
return kind;
|
return kind;
|
||||||
}
|
}
|
||||||
|
|
||||||
const leftType = this.getType(ast.left);
|
const getType = (ast: AST, operation: string): Symbol => {
|
||||||
const rightType = this.getType(ast.right);
|
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 leftRawKind = this.query.getTypeKind(leftType);
|
||||||
const rightRawKind = this.query.getTypeKind(rightType);
|
const rightRawKind = this.query.getTypeKind(rightType);
|
||||||
const leftKind = normalize(leftRawKind, rightRawKind);
|
const leftKind = normalize(leftRawKind, rightRawKind);
|
||||||
|
@ -166,6 +187,9 @@ export class AstType implements AstVisitor {
|
||||||
|
|
||||||
visitConditional(ast: Conditional) {
|
visitConditional(ast: Conditional) {
|
||||||
// The type of a conditional is the union of the true and false conditions.
|
// 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));
|
return this.query.getTypeUnion(this.getType(ast.trueExp), this.getType(ast.falseExp));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -175,7 +175,16 @@ describe('expression diagnostics', () => {
|
||||||
it('should reject an uncalled event handler',
|
it('should reject an uncalled event handler',
|
||||||
() => reject(
|
() => reject(
|
||||||
'<div (click)="click">{{person.name.first}}</div>', 'Unexpected callable expression'));
|
'<div (click)="click">{{person.name.first}}</div>', 'Unexpected callable expression'));
|
||||||
|
describe('with comparisions between nullable and non-nullable', () => {
|
||||||
|
it('should accept ==', () => accept(`<div>{{e == 1 ? 'a' : 'b'}}</div>`));
|
||||||
|
it('should accept ===', () => accept(`<div>{{e === 1 ? 'a' : 'b'}}</div>`));
|
||||||
|
it('should accept !=', () => accept(`<div>{{e != 1 ? 'a' : 'b'}}</div>`));
|
||||||
|
it('should accept !==', () => accept(`<div>{{e !== 1 ? 'a' : 'b'}}</div>`));
|
||||||
|
it('should accept &&', () => accept(`<div>{{e && 1 ? 'a' : 'b'}}</div>`));
|
||||||
|
it('should accept ||', () => accept(`<div>{{e || 1 ? 'a' : 'b'}}</div>`));
|
||||||
|
it('should reject >',
|
||||||
|
() => reject(`<div>{{e > 1 ? 'a' : 'b'}}</div>`, 'The expression might be null'));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const FILES: Directory = {
|
const FILES: Directory = {
|
||||||
|
@ -216,6 +225,7 @@ const FILES: Directory = {
|
||||||
promised_people: Promise<Person[]>;
|
promised_people: Promise<Person[]>;
|
||||||
private private_person: Person;
|
private private_person: Person;
|
||||||
private private_people: Person[];
|
private private_people: Person[];
|
||||||
|
e?: number;
|
||||||
|
|
||||||
getPerson(): Person { return this.person; }
|
getPerson(): Person { return this.person; }
|
||||||
click() {}
|
click() {}
|
||||||
|
|
Loading…
Reference in New Issue