From 5b2696b71123c8ab289e7d9e95b619d5dc2c8333 Mon Sep 17 00:00:00 2001 From: magic-akari Date: Sat, 23 Dec 2023 22:09:14 +0800 Subject: [PATCH] refactor(parser): report `this` parameter error (#1788) - follow up: #1728 --- crates/oxc_parser/src/diagnostics.rs | 15 ++++++++++++++ crates/oxc_parser/src/js/class.rs | 13 ++++++++++++- crates/oxc_parser/src/js/function.rs | 19 ++++++++---------- crates/oxc_parser/src/ts/types.rs | 28 +++++++++++++++++---------- tasks/coverage/parser_typescript.snap | 24 +++++++++++++++++++++++ 5 files changed, 77 insertions(+), 22 deletions(-) diff --git a/crates/oxc_parser/src/diagnostics.rs b/crates/oxc_parser/src/diagnostics.rs index 27d7c4e01..8277557a0 100644 --- a/crates/oxc_parser/src/diagnostics.rs +++ b/crates/oxc_parser/src/diagnostics.rs @@ -257,6 +257,16 @@ pub struct GetterParameters(#[label] pub Span); #[diagnostic()] pub struct SetterParameters(#[label] pub Span); +#[derive(Debug, Error, Diagnostic)] +#[error("TS2681: A constructor cannot have a `this` parameter.")] +#[diagnostic()] +pub struct TSConstructorThisParameter(#[label] pub Span); + +#[derive(Debug, Error, Diagnostic)] +#[error("TS2730: An arrow function cannot have a `this` parameter.")] +#[diagnostic()] +pub struct TSArrowFunctionThisParameter(#[label] pub Span); + #[derive(Debug, Error, Diagnostic)] #[error("'super' can only be used with function calls or in property accesses")] #[diagnostic(help("replace with `super()` or `super.prop` or `super[prop]`"))] @@ -316,3 +326,8 @@ pub struct UsingDeclarationNotAllowedInForInStatement(#[label] pub Span); #[error("Using declarations must have an initializer.")] #[diagnostic()] pub struct UsingDeclarationsMustBeInitialized(#[label] pub Span); + +#[derive(Debug, Error, Diagnostic)] +#[error("TS1089: `static` modifier cannot appear on a constructor declaration.")] +#[diagnostic()] +pub struct StaticConstructor(#[label] pub Span); diff --git a/crates/oxc_parser/src/js/class.rs b/crates/oxc_parser/src/js/class.rs index 039f59813..15835ce44 100644 --- a/crates/oxc_parser/src/js/class.rs +++ b/crates/oxc_parser/src/js/class.rs @@ -1,7 +1,7 @@ use oxc_allocator::{Box, Vec}; use oxc_ast::{ast::*, syntax_directed_operations::PropName}; use oxc_diagnostics::Result; -use oxc_span::Span; +use oxc_span::{GetSpan, Span}; use super::list::ClassElements; use crate::{diagnostics, lexer::Kind, list::NormalList, Parser, StatementContext}; @@ -365,6 +365,17 @@ impl<'a> Parser<'a> { self.error(diagnostics::SetterParameters(value.params.span)); } + if kind == MethodDefinitionKind::Constructor { + if let Some(this_param) = &value.this_param { + // class Foo { constructor(this: number) {} } + self.error(diagnostics::TSConstructorThisParameter(this_param.span)); + } + + if r#static { + self.error(diagnostics::StaticConstructor(key.span())); + } + } + let method_definition = MethodDefinition { span: self.end_span(span), key, diff --git a/crates/oxc_parser/src/js/function.rs b/crates/oxc_parser/src/js/function.rs index 23dfbe4bf..153321df6 100644 --- a/crates/oxc_parser/src/js/function.rs +++ b/crates/oxc_parser/src/js/function.rs @@ -68,15 +68,6 @@ impl<'a> Parser<'a> { pub(crate) fn parse_formal_parameters( &mut self, params_kind: FormalParameterKind, - ) -> Result>> { - let span = self.start_span(); - let list = FormalParameterList::parse(self)?; - Ok(self.ast.formal_parameters(self.end_span(span), params_kind, list.elements, list.rest)) - } - - pub(crate) fn parse_formal_parameters_with_ts_this( - &mut self, - params_kind: FormalParameterKind, ) -> Result<(Option>, Box<'a, FormalParameters<'a>>)> { let span = self.start_span(); let list: FormalParameterList<'_> = FormalParameterList::parse(self)?; @@ -101,7 +92,7 @@ impl<'a> Parser<'a> { let type_parameters = self.parse_ts_type_parameters()?; let (this_param, params) = - self.parse_formal_parameters_with_ts_this(FormalParameterKind::FormalParameter)?; + self.parse_formal_parameters(FormalParameterKind::FormalParameter)?; let return_type = self.parse_ts_return_type_annotation()?; @@ -476,7 +467,13 @@ impl<'a> Parser<'a> { let type_parameters = self.parse_ts_type_parameters()?; - let params = self.parse_formal_parameters(FormalParameterKind::ArrowFormalParameters)?; + let (this_param, params) = + self.parse_formal_parameters(FormalParameterKind::ArrowFormalParameters)?; + + if let Some(this_param) = this_param { + // const x = (this: number) => {}; + self.error(diagnostics::TSArrowFunctionThisParameter(this_param.span)); + } let return_type = self.parse_ts_return_type_annotation()?; diff --git a/crates/oxc_parser/src/ts/types.rs b/crates/oxc_parser/src/ts/types.rs index 8bd58bb64..c77828916 100644 --- a/crates/oxc_parser/src/ts/types.rs +++ b/crates/oxc_parser/src/ts/types.rs @@ -784,7 +784,13 @@ impl<'a> Parser<'a> { let r#abstract = self.eat(Kind::Abstract); self.expect(Kind::New)?; let type_parameters = self.parse_ts_type_parameters()?; - let params = self.parse_formal_parameters(FormalParameterKind::Signature)?; + let (this_param, params) = self.parse_formal_parameters(FormalParameterKind::Signature)?; + + if let Some(this_param) = this_param { + // type Foo = new (this: number) => any; + self.error(diagnostics::TSConstructorThisParameter(this_param.span)); + } + self.expect(Kind::Arrow)?; let return_type_span = self.start_span(); let return_type = self.parse_ts_return_type()?; @@ -802,8 +808,7 @@ impl<'a> Parser<'a> { fn parse_ts_function_type(&mut self) -> Result> { let span = self.start_span(); let type_parameters = self.parse_ts_type_parameters()?; - let (this_param, params) = - self.parse_formal_parameters_with_ts_this(FormalParameterKind::Signature)?; + let (this_param, params) = self.parse_formal_parameters(FormalParameterKind::Signature)?; self.expect(Kind::Arrow)?; let return_type_span = self.start_span(); let return_type = self.parse_ts_return_type()?; @@ -920,8 +925,7 @@ impl<'a> Parser<'a> { pub(crate) fn parse_ts_call_signature_member(&mut self) -> Result> { let span = self.start_span(); let type_parameters = self.parse_ts_type_parameters()?; - let (this_patam, params) = - self.parse_formal_parameters_with_ts_this(FormalParameterKind::Signature)?; + let (this_patam, params) = self.parse_formal_parameters(FormalParameterKind::Signature)?; let return_type = self.parse_ts_return_type_annotation()?; self.bump(Kind::Comma); self.bump(Kind::Semicolon); @@ -938,8 +942,7 @@ impl<'a> Parser<'a> { let span = self.start_span(); self.expect(Kind::Get)?; let (key, computed) = self.parse_property_name()?; - let (this_param, params) = - self.parse_formal_parameters_with_ts_this(FormalParameterKind::Signature)?; + let (this_param, params) = self.parse_formal_parameters(FormalParameterKind::Signature)?; let return_type = self.parse_ts_return_type_annotation()?; self.bump(Kind::Comma); self.bump(Kind::Semicolon); @@ -960,8 +963,7 @@ impl<'a> Parser<'a> { let span = self.start_span(); self.expect(Kind::Set)?; let (key, computed) = self.parse_property_name()?; - let (this_param, params) = - self.parse_formal_parameters_with_ts_this(FormalParameterKind::Signature)?; + let (this_param, params) = self.parse_formal_parameters(FormalParameterKind::Signature)?; let return_type = self.parse_ts_return_type_annotation()?; self.bump(Kind::Comma); self.bump(Kind::Semicolon); @@ -1034,7 +1036,13 @@ impl<'a> Parser<'a> { self.expect(Kind::New)?; let type_parameters = self.parse_ts_type_parameters()?; - let params = self.parse_formal_parameters(FormalParameterKind::Signature)?; + let (this_param, params) = self.parse_formal_parameters(FormalParameterKind::Signature)?; + + if let Some(this_param) = this_param { + // interface Foo { new(this: number): Foo } + self.error(diagnostics::TSConstructorThisParameter(this_param.span)); + } + let return_type = self.parse_ts_return_type_annotation()?; self.bump(Kind::Comma); self.bump(Kind::Semicolon); diff --git a/tasks/coverage/parser_typescript.snap b/tasks/coverage/parser_typescript.snap index 9b3e27150..3b252459d 100644 --- a/tasks/coverage/parser_typescript.snap +++ b/tasks/coverage/parser_typescript.snap @@ -19592,6 +19592,30 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 3 │ let o8 = { ...*o }; ╰──── + × TS2681: A constructor cannot have a `this` parameter. + ╭─[conformance/types/thisType/thisTypeInFunctionsNegative.ts:159:1] + 159 │ class ThisConstructor { + 160 │ constructor(this: ThisConstructor, private n: number) { + · ───────────────────── + 161 │ } + ╰──── + + × TS2681: A constructor cannot have a `this` parameter. + ╭─[conformance/types/thisType/thisTypeInFunctionsNegative.ts:163:1] + 163 │ interface ThisConstructorInterface { + 164 │ new(this: ThisConstructor, n: number); + · ───────────────────── + 165 │ } + ╰──── + + × TS2681: A constructor cannot have a `this` parameter. + ╭─[conformance/types/thisType/thisTypeInFunctionsNegative.ts:165:1] + 165 │ } + 166 │ var thisConstructorType: new (this: number) => number; + · ──────────── + 167 │ function notFirst(a: number, this: C): number { return this.n; } + ╰──── + × Expected `,` but found `this` ╭─[conformance/types/thisType/thisTypeInFunctionsNegative.ts:169:1] 169 │ ///// parse errors /////