feat(semantic): check optional parameters (#2263)

This commit is contained in:
Dunqing 2024-02-02 15:54:04 +08:00 committed by GitHub
parent 8d99a15ac9
commit d71175e712
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 98 additions and 8 deletions

View file

@ -1602,6 +1602,10 @@ impl<'a> BindingPatternKind<'a> {
pub fn is_binding_identifier(&self) -> bool {
matches!(self, Self::BindingIdentifier(_))
}
pub fn is_assignment_pattern(&self) -> bool {
matches!(self, Self::AssignmentPattern(_))
}
}
#[derive(Debug, Hash)]

View file

@ -40,9 +40,25 @@ fn check_variable_declarator(decl: &VariableDeclarator, ctx: &SemanticBuilder<'_
}
fn check_formal_parameters(params: &FormalParameters, ctx: &SemanticBuilder<'_>) {
#[derive(Debug, Error, Diagnostic)]
#[error("A required parameter cannot follow an optional parameter.")]
#[diagnostic()]
struct RequiredParameterAfterOptionalParameter(#[label] Span);
if !params.is_empty() && params.kind == FormalParameterKind::Signature {
check_duplicate_bound_names(params, ctx);
}
let mut has_optional = false;
for item in &params.items {
// function a(optional?: number, required: number) { }
if has_optional && !item.pattern.optional && !item.pattern.kind.is_assignment_pattern() {
ctx.error(RequiredParameterAfterOptionalParameter(item.span));
}
if item.pattern.optional {
has_optional = true;
}
}
}
fn check_duplicate_bound_names<T: BoundNames>(bound_names: &T, ctx: &SemanticBuilder<'_>) {

View file

@ -1,7 +1,7 @@
parser_babel Summary:
AST Parsed : 2090/2096 (99.71%)
Positive Passed: 2088/2096 (99.62%)
Negative Passed: 1351/1500 (90.07%)
Positive Passed: 2086/2096 (99.52%)
Negative Passed: 1355/1500 (90.33%)
Expect Syntax Error: "annex-b/disabled/1.1-html-comments-close/input.js"
Expect Syntax Error: "annex-b/disabled/3.1-sloppy-labeled-functions/input.js"
Expect Syntax Error: "annex-b/disabled/3.1-sloppy-labeled-functions-if-body/input.js"
@ -71,7 +71,6 @@ Expect Syntax Error: "typescript/class/modifiers-index-signatures/input.ts"
Expect Syntax Error: "typescript/class/modifiers-invalid-order/input.ts"
Expect Syntax Error: "typescript/class/modifiers-override-errors/input.ts"
Expect Syntax Error: "typescript/class/parameter-properties-binding-patterns/input.ts"
Expect Syntax Error: "typescript/class/parameter-properties-not-constructor/input.ts"
Expect Syntax Error: "typescript/class/private-fields-modifier-abstract/input.ts"
Expect Syntax Error: "typescript/class/private-fields-modifier-private/input.ts"
Expect Syntax Error: "typescript/class/private-fields-modifier-protected/input.ts"
@ -94,9 +93,6 @@ Expect Syntax Error: "typescript/expect-plugin/export-type-named/input.js"
Expect Syntax Error: "typescript/export/double-declare/input.ts"
Expect Syntax Error: "typescript/export/equals-in-script/input.ts"
Expect Syntax Error: "typescript/function/empty-type-parameters/input.ts"
Expect Syntax Error: "typescript/function/parameter-properties/input.ts"
Expect Syntax Error: "typescript/function/pattern-optional-parameters/input.ts"
Expect Syntax Error: "typescript/function/pattern-optional-parameters-arrow/input.ts"
Expect Syntax Error: "typescript/import/equals-in-script/input.ts"
Expect Syntax Error: "typescript/import/equals-require-in-script/input.ts"
Expect Syntax Error: "typescript/import/export-import-type/input.ts"
@ -187,6 +183,22 @@ Expect to Parse: "typescript/class/constructor-with-modifier-names/input.ts"
4 │ }
╰────
Expect to Parse: "typescript/class/parameter-properties/input.ts"
× A required parameter cannot follow an optional parameter.
╭─[typescript/class/parameter-properties/input.ts:6:1]
6 │ private pi?: number,
7 │ public readonly pur,
· ───────────────────
8 │ // Also works on AssignmentPattern
╰────
Expect to Parse: "typescript/function/declare-pattern-parameters/input.ts"
× A required parameter cannot follow an optional parameter.
╭─[typescript/function/declare-pattern-parameters/input.ts:1:1]
1 │ declare function f([]?, {})
· ──
╰────
Expect to Parse: "typescript/interface/get-set-properties/input.ts"
× Expected `(` but found `:`
╭─[typescript/interface/get-set-properties/input.ts:1:1]
@ -9775,6 +9787,14 @@ Expect to Parse: "typescript/types/const-type-parameters-babel-7/input.ts"
╰────
help: Try insert a semicolon here
× A required parameter cannot follow an optional parameter.
╭─[typescript/class/parameter-properties-not-constructor/input.ts:6:1]
6 │ private pi?: number,
7 │ public readonly pur,
· ───────────────────
8 │ // Also works on AssignmentPattern
╰────
× Unexpected token
╭─[typescript/const/invalid-initializer-ambient-context/input.ts:1:1]
1 │ declare module N {
@ -9822,6 +9842,26 @@ Expect to Parse: "typescript/types/const-type-parameters-babel-7/input.ts"
· ───
╰────
× A required parameter cannot follow an optional parameter.
╭─[typescript/function/parameter-properties/input.ts:5:1]
5 │ private pi?: number,
6 │ public readonly pur,
· ───────────────────
7 │ readonly x = 0,
╰────
× A required parameter cannot follow an optional parameter.
╭─[typescript/function/pattern-optional-parameters/input.ts:1:1]
1 │ function f([]?, {}) {}
· ──
╰────
× A required parameter cannot follow an optional parameter.
╭─[typescript/function/pattern-optional-parameters-arrow/input.ts:1:1]
1 │ ([]?, {}) => {}
· ──
╰────
× Expected a semicolon or an implicit semicolon after a statement, but found none
╭─[typescript/interface/declare-new-line/input.ts:1:1]
1 │ declare interface

View file

@ -1,7 +1,7 @@
parser_typescript Summary:
AST Parsed : 5239/5243 (99.92%)
Positive Passed: 5232/5243 (99.79%)
Negative Passed: 1024/4879 (20.99%)
Negative Passed: 1025/4879 (21.01%)
Expect Syntax Error: "compiler/ClassDeclaration10.ts"
Expect Syntax Error: "compiler/ClassDeclaration11.ts"
Expect Syntax Error: "compiler/ClassDeclaration13.ts"
@ -3210,7 +3210,6 @@ Expect Syntax Error: "conformance/parser/ecmascript5/ParameterLists/parserParame
Expect Syntax Error: "conformance/parser/ecmascript5/ParameterLists/parserParameterList16.ts"
Expect Syntax Error: "conformance/parser/ecmascript5/ParameterLists/parserParameterList17.ts"
Expect Syntax Error: "conformance/parser/ecmascript5/ParameterLists/parserParameterList2.ts"
Expect Syntax Error: "conformance/parser/ecmascript5/ParameterLists/parserParameterList3.ts"
Expect Syntax Error: "conformance/parser/ecmascript5/ParameterLists/parserParameterList4.ts"
Expect Syntax Error: "conformance/parser/ecmascript5/ParameterLists/parserParameterList7.ts"
Expect Syntax Error: "conformance/parser/ecmascript5/ParameterLists/parserParameterList8.ts"
@ -6370,6 +6369,13 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
╰────
help: Try insert a semicolon here
× A required parameter cannot follow an optional parameter.
╭─[compiler/fatarrowfunctionsOptionalArgsErrors1.ts:1:1]
1 │ (arg1?, arg2) => 101;
· ────
2 │ (...arg?) => 102;
╰────
× A rest parameter cannot have an initializer
╭─[compiler/fatarrowfunctionsOptionalArgsErrors1.ts:3:1]
3 │ (...arg) => 103;
@ -15798,6 +15804,22 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
10 │ function fn5() { }
╰────
× A required parameter cannot follow an optional parameter.
╭─[conformance/functions/functionOverloadErrorsSyntax.ts:1:1]
1 │ //Function overload signature with optional parameter followed by non-optional parameter
2 │ function fn4a(x?: number, y: string);
· ─────────
3 │ function fn4a() { }
╰────
× A required parameter cannot follow an optional parameter.
╭─[conformance/functions/functionOverloadErrorsSyntax.ts:4:1]
4 │
5 │ function fn4b(n: string, x?: number, y: string);
· ─────────
6 │ function fn4b() { }
╰────
× Illegal 'use strict' directive in function with non-simple parameter list
╭─[conformance/functions/functionWithUseStrictAndSimpleParameterList_es2016.ts:3:1]
3 │ function a(a = 10) {
@ -17062,6 +17084,14 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
3 │ }
╰────
× A required parameter cannot follow an optional parameter.
╭─[conformance/parser/ecmascript5/ParameterLists/parserParameterList3.ts:1:1]
1 │ class C {
2 │ F(A?, B) { }
· ─
3 │ }
╰────
× Expected `)` but found `Identifier`
╭─[conformance/parser/ecmascript5/ParameterLists/parserParameterList5.ts:1:1]
1 │ function A(): (public B) => C {