fix(compiler): generate safe access strictNullChecks compatible code (#12800)

fixes #12795
This commit is contained in:
Chuck Jazdzewski 2016-11-11 17:12:17 -08:00 committed by Victor Berchet
parent 52be848f94
commit a965d11cce
3 changed files with 8 additions and 4 deletions

View File

@ -32,7 +32,8 @@ export enum BuiltinTypeName {
String, String,
Int, Int,
Number, Number,
Function Function,
Null
} }
export class BuiltinType extends Type { export class BuiltinType extends Type {
@ -73,7 +74,7 @@ export var INT_TYPE = new BuiltinType(BuiltinTypeName.Int);
export var NUMBER_TYPE = new BuiltinType(BuiltinTypeName.Number); export var NUMBER_TYPE = new BuiltinType(BuiltinTypeName.Number);
export var STRING_TYPE = new BuiltinType(BuiltinTypeName.String); export var STRING_TYPE = new BuiltinType(BuiltinTypeName.String);
export var FUNCTION_TYPE = new BuiltinType(BuiltinTypeName.Function); export var FUNCTION_TYPE = new BuiltinType(BuiltinTypeName.Function);
export var NULL_TYPE = new BuiltinType(BuiltinTypeName.Null);
export interface TypeVisitor { export interface TypeVisitor {
visitBuiltintType(type: BuiltinType, context: any): any; visitBuiltintType(type: BuiltinType, context: any): any;
@ -175,7 +176,8 @@ export abstract class Expression {
} }
isBlank(): Expression { isBlank(): Expression {
// Note: We use equals by purpose here to compare to null and undefined in JS. // Note: We use equals by purpose here to compare to null and undefined in JS.
return this.equals(NULL_EXPR); // We use the typed null to allow strictNullChecks to narrow types.
return this.equals(TYPED_NULL_EXPR);
} }
cast(type: Type): Expression { return new CastExpr(this, type); } cast(type: Type): Expression { return new CastExpr(this, type); }
toStmt(): Statement { return new ExpressionStatement(this); } toStmt(): Statement { return new ExpressionStatement(this); }
@ -451,6 +453,7 @@ export var SUPER_EXPR = new ReadVarExpr(BuiltinVar.Super);
export var CATCH_ERROR_VAR = new ReadVarExpr(BuiltinVar.CatchError); export var CATCH_ERROR_VAR = new ReadVarExpr(BuiltinVar.CatchError);
export var CATCH_STACK_VAR = new ReadVarExpr(BuiltinVar.CatchStack); export var CATCH_STACK_VAR = new ReadVarExpr(BuiltinVar.CatchStack);
export var NULL_EXPR = new LiteralExpr(null, null); export var NULL_EXPR = new LiteralExpr(null, null);
export var TYPED_NULL_EXPR = new LiteralExpr(null, NULL_TYPE);
//// Statements //// Statements
export enum StmtModifier { export enum StmtModifier {

View File

@ -69,7 +69,7 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
visitLiteralExpr(ast: o.LiteralExpr, ctx: EmitterVisitorContext): any { visitLiteralExpr(ast: o.LiteralExpr, ctx: EmitterVisitorContext): any {
const value = ast.value; const value = ast.value;
if (isBlank(value)) { if (isBlank(value) && ast.type != o.NULL_TYPE) {
ctx.print(`(${value} as any)`); ctx.print(`(${value} as any)`);
return null; return null;
} }

View File

@ -110,6 +110,7 @@ export function main() {
it('should support blank literals', () => { it('should support blank literals', () => {
expect(emitStmt(o.literal(null).toStmt())).toEqual('(null as any);'); expect(emitStmt(o.literal(null).toStmt())).toEqual('(null as any);');
expect(emitStmt(o.literal(undefined).toStmt())).toEqual('(undefined as any);'); expect(emitStmt(o.literal(undefined).toStmt())).toEqual('(undefined as any);');
expect(emitStmt(o.variable('a', null).isBlank().toStmt())).toEqual('(a == null);');
}); });
it('should support external identifiers', () => { it('should support external identifiers', () => {