Support type predicate "asserts" with no "is" (#667)

This commit is contained in:
David Sherret 2020-02-14 20:44:02 -05:00 committed by GitHub
parent 1fc09caa2f
commit 4550f7e1af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 220 additions and 47 deletions

View File

@ -400,7 +400,7 @@ pub struct TsTypePredicate {
pub asserts: bool,
pub param_name: TsThisTypeOrIdent,
#[serde(rename = "typeAnnotation")]
pub type_ann: TsTypeAnn,
pub type_ann: Option<TsTypeAnn>,
}
#[ast_node]

View File

@ -264,14 +264,16 @@ impl<'a, I: Tokens> Parser<'a, I> {
) -> PResult<'a, TsTypePredicate> {
debug_assert!(self.input.syntax().typescript());
assert_and_bump!("is");
let param_name = TsThisTypeOrIdent::TsThisType(lhs);
let cur_pos = cur_pos!();
let type_ann = self.parse_ts_type_ann(
// eat_colon
false, cur_pos,
)?;
let type_ann = if eat!("is") {
let cur_pos = cur_pos!();
Some(self.parse_ts_type_ann(
// eat_colon
false, cur_pos,
)?)
} else {
None
};
Ok(TsTypePredicate {
span: span!(start),
@ -413,39 +415,40 @@ impl<'a, I: Tokens> Parser<'a, I> {
}
let type_pred_start = cur_pos!();
let type_pred_asserts = is!("asserts") && peeked_is!(IdentRef);
if type_pred_asserts {
let has_type_pred_asserts = is!("asserts") && peeked_is!(IdentRef);
if has_type_pred_asserts {
assert_and_bump!("asserts");
cur!(false)?;
}
let type_pred_var = if is!(IdentRef) && peeked_is!("is") {
p.try_parse_ts(|p| p.parse_ts_type_predicate_prefix())
let has_type_pred_is = is!(IdentRef)
&& peeked_is!("is")
&& !p.input.has_linebreak_between_cur_and_peeked();
let is_type_predicate = has_type_pred_asserts || has_type_pred_is;
if !is_type_predicate {
return p.parse_ts_type_ann(
// eat_colon
false,
return_token_start,
);
}
let type_pred_var = p.parse_ident_name()?;
let type_ann = if has_type_pred_is {
assert_and_bump!("is");
let pos = cur_pos!();
Some(p.parse_ts_type_ann(
// eat_colon
false, pos,
)?)
} else {
None
};
let type_pred_var = match type_pred_var {
Some(v) => v.into(),
None => {
return p.parse_ts_type_ann(
// eat_colon
false,
return_token_start,
);
}
};
let pos = cur_pos!();
let type_ann = p.parse_ts_type_ann(
// eat_colon
false, pos,
)?;
let node = Box::new(TsType::TsTypePredicate(TsTypePredicate {
span: span!(type_pred_start),
asserts: type_pred_asserts,
param_name: type_pred_var,
asserts: has_type_pred_asserts,
param_name: TsThisTypeOrIdent::Ident(type_pred_var),
type_ann,
}));
@ -456,19 +459,6 @@ impl<'a, I: Tokens> Parser<'a, I> {
})
}
fn parse_ts_type_predicate_prefix(&mut self) -> PResult<'a, Option<Ident>> {
debug_assert!(self.input.syntax().typescript());
let id = self.parse_ident_name()?;
if is!("is") && !self.input.had_line_break_before_cur() {
assert_and_bump!("is");
return Ok(Some(id));
}
Ok(None)
}
/// `tsTryParse`
fn try_parse_ts_bool<F>(&mut self, op: F) -> PResult<'a, bool>
where

View File

@ -2,4 +2,5 @@ class C {
f(): void {}
g(): this is {} { return true; }
h(): asserts this is {} { throw ""; }
i(): asserts this { throw ""; }
}

View File

@ -2,7 +2,7 @@
"type": "Module",
"span": {
"start": 0,
"end": 107,
"end": 143,
"ctxt": 0
},
"body": [
@ -22,7 +22,7 @@
"declare": false,
"span": {
"start": 0,
"end": 107,
"end": 143,
"ctxt": 0
},
"decorators": [],
@ -299,6 +299,96 @@
"accessibility": null,
"isAbstract": false,
"isOptional": false
},
{
"type": "ClassMethod",
"span": {
"start": 110,
"end": 141,
"ctxt": 0
},
"key": {
"type": "Identifier",
"span": {
"start": 110,
"end": 111,
"ctxt": 0
},
"value": "i",
"typeAnnotation": null,
"optional": false
},
"function": {
"params": [],
"decorators": [],
"span": {
"start": 110,
"end": 141,
"ctxt": 0
},
"body": {
"type": "BlockStatement",
"span": {
"start": 128,
"end": 141,
"ctxt": 0
},
"stmts": [
{
"type": "ThrowStatement",
"span": {
"start": 130,
"end": 139,
"ctxt": 0
},
"argument": {
"type": "StringLiteral",
"span": {
"start": 136,
"end": 138,
"ctxt": 0
},
"value": "",
"hasEscape": false
}
}
]
},
"generator": false,
"async": false,
"typeParameters": null,
"returnType": {
"type": "TsTypeAnnotation",
"span": {
"start": 113,
"end": 127,
"ctxt": 0
},
"typeAnnotation": {
"type": "TsTypePredicate",
"span": {
"start": 115,
"end": 127,
"ctxt": 0
},
"asserts": true,
"paramName": {
"type": "TsThisType",
"span": {
"start": 123,
"end": 127,
"ctxt": 0
}
},
"typeAnnotation": null
}
}
},
"kind": "method",
"isStatic": false,
"accessibility": null,
"isAbstract": false,
"isOptional": false
}
],
"superClass": null,

View File

@ -1,3 +1,4 @@
function f(x: any): x is boolean {}
(function(x: any): x is boolean {})
function g(x: any): asserts x is boolean {}
function h(x: any): asserts x {}

View File

@ -2,7 +2,7 @@
"type": "Module",
"span": {
"start": 0,
"end": 115,
"end": 148,
"ctxt": 0
},
"body": [
@ -331,6 +331,97 @@
}
}
}
},
{
"type": "FunctionDeclaration",
"identifier": {
"type": "Identifier",
"span": {
"start": 125,
"end": 126,
"ctxt": 0
},
"value": "h",
"typeAnnotation": null,
"optional": false
},
"declare": false,
"params": [
{
"type": "Identifier",
"span": {
"start": 127,
"end": 133,
"ctxt": 0
},
"value": "x",
"typeAnnotation": {
"type": "TsTypeAnnotation",
"span": {
"start": 128,
"end": 133,
"ctxt": 0
},
"typeAnnotation": {
"type": "TsKeywordType",
"span": {
"start": 130,
"end": 133,
"ctxt": 0
},
"kind": "any"
}
},
"optional": false
}
],
"decorators": [],
"span": {
"start": 116,
"end": 148,
"ctxt": 0
},
"body": {
"type": "BlockStatement",
"span": {
"start": 146,
"end": 148,
"ctxt": 0
},
"stmts": []
},
"generator": false,
"async": false,
"typeParameters": null,
"returnType": {
"type": "TsTypeAnnotation",
"span": {
"start": 134,
"end": 145,
"ctxt": 0
},
"typeAnnotation": {
"type": "TsTypePredicate",
"span": {
"start": 136,
"end": 145,
"ctxt": 0
},
"asserts": true,
"paramName": {
"type": "Identifier",
"span": {
"start": 144,
"end": 145,
"ctxt": 0
},
"value": "x",
"typeAnnotation": null,
"optional": false
},
"typeAnnotation": null
}
}
}
],
"interpreter": null