fix(es/parser): Emit an error for multiple constructors with body (#4031)

This commit is contained in:
Austaras 2022-03-16 00:18:19 +08:00 committed by GitHub
parent 60df339915
commit 120d2a534e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 33 additions and 5 deletions

View File

@ -169,6 +169,7 @@ pub enum SyntaxError {
PrivateNameModifier(JsWord), PrivateNameModifier(JsWord),
ReadOnlyMethod, ReadOnlyMethod,
GeneratorConstructor, GeneratorConstructor,
DuplicateConstructor,
TsBindingPatCannotBeOptional, TsBindingPatCannotBeOptional,
SuperCallOptional, SuperCallOptional,
@ -422,6 +423,7 @@ impl SyntaxError {
SyntaxError::PropertyNamedConstructor => { SyntaxError::PropertyNamedConstructor => {
"Classes may not have a non-static field named 'constructor'".into() "Classes may not have a non-static field named 'constructor'".into()
} }
SyntaxError::DuplicateConstructor => "A class can only have one constructor".into(),
SyntaxError::PrivateNameModifier(modifier) => format!( SyntaxError::PrivateNameModifier(modifier) => format!(
"'{}' modifier cannot be used with a private identifier", "'{}' modifier cannot be used with a private identifier",
modifier modifier

View File

@ -316,6 +316,7 @@ impl<'a, I: Tokens> Parser<I> {
fn parse_class_body(&mut self) -> PResult<Vec<ClassMember>> { fn parse_class_body(&mut self) -> PResult<Vec<ClassMember>> {
let mut elems = vec![]; let mut elems = vec![];
let mut has_constructor_with_body = false;
while !eof!(self) && !is!(self, '}') { while !eof!(self) && !is!(self, '}') {
if eat_exact!(self, ';') { if eat_exact!(self, ';') {
let span = self.input.prev_span(); let span = self.input.prev_span();
@ -328,7 +329,22 @@ impl<'a, I: Tokens> Parser<I> {
allow_direct_super: true, allow_direct_super: true,
..self.ctx() ..self.ctx()
}); });
elems.push(p.parse_class_member()?); let elem = p.parse_class_member()?;
if !p.ctx().in_declare {
if let ClassMember::Constructor(Constructor {
body: Some(..),
span,
..
}) = elem
{
if has_constructor_with_body {
p.emit_err(span, SyntaxError::DuplicateConstructor);
}
has_constructor_with_body = true;
}
}
elems.push(elem);
} }
Ok(elems) Ok(elems)
} }
@ -706,6 +722,14 @@ impl<'a, I: Tokens> Parser<I> {
let body: Option<_> = let body: Option<_> =
self.parse_fn_body(false, false, params.is_simple_parameter_list())?; self.parse_fn_body(false, false, params.is_simple_parameter_list())?;
if body.is_none() {
for param in params.iter() {
if param.is_ts_param_prop() {
self.emit_err(param.span(), SyntaxError::TS2369)
}
}
}
if self.syntax().typescript() && body.is_none() { if self.syntax().typescript() && body.is_none() {
// Declare constructors cannot have assignment pattern in parameters // Declare constructors cannot have assignment pattern in parameters
for p in &params { for p in &params {

View File

@ -10,3 +10,9 @@
3 | constructor(override public v: string) 3 | constructor(override public v: string)
: ^^^^^^^^^^^^^^^^ : ^^^^^^^^^^^^^^^^
`---- `----
x A parameter property is only allowed in a constructor implementation
,-[$DIR/tests/typescript-errors/class/override-parameter-property/input.ts:3:3]
3 | constructor(override public v: string)
: ^^^^^^^^^^^^^^^^^^^^^^^^^
`----

View File

@ -24,7 +24,6 @@ function charCode(s: string): number {
export class TextProtoReader { export class TextProtoReader {
constructor(readonly r: BufReader) { } constructor(readonly r: BufReader) { }
constructor(readonly r: BufReader) { }
/** readLine() reads a single line from the TextProtoReader, /** readLine() reads a single line from the TextProtoReader,
* eliding the final \n or \r\n from the returned string. * eliding the final \n or \r\n from the returned string.

View File

@ -354,9 +354,6 @@ function charCode(s) {
return s.charCodeAt(0); return s.charCodeAt(0);
} }
class TextProtoReader { class TextProtoReader {
constructor(r){
this.r = r;
}
constructor(r){ constructor(r){
this.r = r; this.r = r;
} }