diff --git a/crates/stc_ts_errors/src/lib.rs b/crates/stc_ts_errors/src/lib.rs index bc0476ef2a..c8eabae678 100644 --- a/crates/stc_ts_errors/src/lib.rs +++ b/crates/stc_ts_errors/src/lib.rs @@ -1088,6 +1088,11 @@ pub enum Error { span: Span, }, + /// TS1359 + ExpectedIdentifierReservedKeyword { + span: Span, + }, + TS1166 { span: Span, }, @@ -1517,6 +1522,7 @@ impl Error { Error::TS2370 { .. } => 2370, Error::WrongOverloadSignature { .. } => 2394, Error::TS1166 { .. } => 1166, + Error::ExpectedIdentifierReservedKeyword { .. } => 1359, Error::TS1345 { .. } => 1345, Error::TS2353 { .. } => 2353, Error::ConstructorImplMissingOrNotFollowedByDecl { .. } => 2390, diff --git a/crates/stc_ts_file_analyzer/src/analyzer/function/mod.rs b/crates/stc_ts_file_analyzer/src/analyzer/function/mod.rs index b9abf2b2d5..caaa009648 100644 --- a/crates/stc_ts_file_analyzer/src/analyzer/function/mod.rs +++ b/crates/stc_ts_file_analyzer/src/analyzer/function/mod.rs @@ -3,7 +3,8 @@ use std::borrow::Cow; use itertools::{EitherOrBoth, Itertools}; use rnode::{Fold, FoldWith}; use stc_ts_ast_rnode::{ - RBindingIdent, RFnDecl, RFnExpr, RFunction, RIdent, RParamOrTsParamProp, RPat, RTsEntityName, + RBindingIdent, RFnDecl, RFnExpr, RFunction, RIdent, RParam, RParamOrTsParamProp, RPat, + RTsEntityName, }; use stc_ts_errors::{Error, Errors}; use stc_ts_type_ops::Fix; @@ -62,6 +63,7 @@ impl Analyzer<'_, '_> { // TODO(kdy1): Move this to parser let mut has_optional = false; for p in &f.params { + validate_parameter_name(child, &p, f.is_async, f.is_generator); if has_optional { match p.pat { RPat::Ident(RBindingIdent { @@ -478,6 +480,25 @@ impl Analyzer<'_, '_> { } } +// Check for reserved words used as identifiers (yield, await, etc.) +// +// TODO(@littledivy): Generalize this to work regardless of 'function' context. +fn validate_parameter_name(ctx: &mut Analyzer, p: &RParam, is_async: bool, is_generator: bool) { + match &p.pat { + RPat::Ident(ident) => { + if is_async && ident.id.sym == *"await" { + ctx.storage + .report(Error::ExpectedIdentifierReservedKeyword { span: p.span() }); + } + if is_generator && ident.id.sym == *"yield" { + ctx.storage + .report(Error::ExpectedIdentifierReservedKeyword { span: p.span() }); + } + } + _ => {} + } +} + #[validator] impl Analyzer<'_, '_> { /// NOTE: This method **should not call f.fold_children_with(self)** diff --git a/crates/stc_ts_type_checker/tests/conformance.pass.txt b/crates/stc_ts_type_checker/tests/conformance.pass.txt index 812d7e9c1d..2523740aea 100644 --- a/crates/stc_ts_type_checker/tests/conformance.pass.txt +++ b/crates/stc_ts_type_checker/tests/conformance.pass.txt @@ -52,6 +52,7 @@ async/es2017/functionDeclarations/asyncFunctionDeclaration1_es2017.ts async/es2017/functionDeclarations/asyncFunctionDeclaration2_es2017.ts async/es2017/functionDeclarations/asyncFunctionDeclaration3_es2017.ts async/es2017/functionDeclarations/asyncFunctionDeclaration4_es2017.ts +async/es2017/functionDeclarations/asyncFunctionDeclaration5_es2017.ts async/es2017/functionDeclarations/asyncFunctionDeclaration8_es2017.ts async/es5/asyncArrowFunction/arrowFunctionWithParameterNameAsync_es5.ts async/es5/asyncArrowFunction/asyncArrowFunction10_es5.ts diff --git a/crates/stc_ts_type_checker/tests/tsc.rs b/crates/stc_ts_type_checker/tests/tsc.rs index 81e0fa3f1c..4919bde8c4 100644 --- a/crates/stc_ts_type_checker/tests/tsc.rs +++ b/crates/stc_ts_type_checker/tests/tsc.rs @@ -216,6 +216,11 @@ fn create_test(path: PathBuf) -> Option> { if let Ok(errors) = load_expected_errors(&path) { for err in errors { + // Don't ignore certain TS1 tests + if err.code == "TS1359" { + continue; + } + if err.code.starts_with("TS1") && err.code.len() == 6 { return None; }