diff --git a/tsc/internal/checker/grammarchecks.go b/tsc/internal/checker/grammarchecks.go index 1c7430f2060b9..ed3690563be2d 100644 --- a/tsc/internal/checker/grammarchecks.go +++ b/tsc/internal/checker/grammarchecks.go @@ -2171,6 +2171,9 @@ func (c *Checker) checkGrammarImportCallExpression(node *ast.Node) bool { if nodeAsCall.TypeArguments != nil { return c.grammarErrorOnNode(node, diagnostics.This_use_of_import_is_invalid_import_calls_can_be_written_but_they_must_have_parentheses_and_cannot_have_type_arguments) } + if nodeAsCall.QuestionDotToken != nil { + return c.grammarErrorOnNode(node, diagnostics.Calls_to_import_are_not_permitted_in_an_optional_chain) + } nodeArguments := nodeAsCall.Arguments argumentNodes := nodeArguments.Nodes diff --git a/tsc/internal/diagnostics/diagnostics_generated.go b/tsc/internal/diagnostics/diagnostics_generated.go index 44194d9cca924..a50bae5d1e1a3 100644 --- a/tsc/internal/diagnostics/diagnostics_generated.go +++ b/tsc/internal/diagnostics/diagnostics_generated.go @@ -4426,6 +4426,8 @@ var The_invalid_diagnostic_directive_is_in_supplemental_output_0_returned_by_the var Diagnostic_directive_0_returned_by_the_content_mapper_has_an_invalid_unusedExpectDirectiveIndex = &Message{code: 100068, category: CategoryMessage, key: "Diagnostic_directive_0_returned_by_the_content_mapper_has_an_invalid_unusedExpectDirectiveIndex_100068", text: "Diagnostic directive {0} returned by the content mapper has an invalid 'unusedExpectDirectiveIndex'."} +var Calls_to_import_are_not_permitted_in_an_optional_chain = &Message{code: 100069, category: CategoryError, key: "Calls_to_import_are_not_permitted_in_an_optional_chain_100069", text: "Calls to 'import()' are not permitted in an optional chain."} + func keyToMessage(key Key) *Message { switch key { case "Unterminated_string_literal_1002": @@ -8852,6 +8854,8 @@ func keyToMessage(key Key) *Message { return The_invalid_diagnostic_directive_is_in_supplemental_output_0_returned_by_the_content_mapper case "Diagnostic_directive_0_returned_by_the_content_mapper_has_an_invalid_unusedExpectDirectiveIndex_100068": return Diagnostic_directive_0_returned_by_the_content_mapper_has_an_invalid_unusedExpectDirectiveIndex + case "Calls_to_import_are_not_permitted_in_an_optional_chain_100069": + return Calls_to_import_are_not_permitted_in_an_optional_chain default: return nil } diff --git a/tsc/internal/diagnostics/extraDiagnosticMessages.json b/tsc/internal/diagnostics/extraDiagnosticMessages.json index 41c7b8d8abc35..e8e9db7e82578 100644 --- a/tsc/internal/diagnostics/extraDiagnosticMessages.json +++ b/tsc/internal/diagnostics/extraDiagnosticMessages.json @@ -338,5 +338,9 @@ "Diagnostic directive {0} returned by the content mapper has an invalid 'unusedExpectDirectiveIndex'.": { "category": "Message", "code": 100068 + }, + "Calls to 'import()' are not permitted in an optional chain.": { + "category": "Error", + "code": 100069 } } diff --git a/tsc/internal/diagnostics/loc_generated.go b/tsc/internal/diagnostics/loc_generated.go index 769956b1762a2..c57838c45276b 100644 --- a/tsc/internal/diagnostics/loc_generated.go +++ b/tsc/internal/diagnostics/loc_generated.go @@ -5,11 +5,10 @@ package diagnostics import ( "compress/gzip" _ "embed" - "strings" - "sync" - "github.com/microsoft/TypeScript/tsc/internal/json" "golang.org/x/text/language" + "strings" + "sync" ) var matcher = language.NewMatcher([]language.Tag{ diff --git a/tsc/internal/parser/parser.go b/tsc/internal/parser/parser.go index 8eef8b7a7da8d..a33bd55654412 100644 --- a/tsc/internal/parser/parser.go +++ b/tsc/internal/parser/parser.go @@ -5245,7 +5245,7 @@ func (p *Parser) parseLeftHandSideExpressionOrHigher() *ast.Expression { p.nextToken() // advance past the dot expression = p.finishNode(p.factory.NewMetaProperty(ast.KindImportKeyword, p.parseIdentifierName()), pos) if expression.Text() == "defer" { - if p.token == ast.KindOpenParenToken || p.token == ast.KindLessThanToken { + if p.token == ast.KindOpenParenToken || p.token == ast.KindLessThanToken || p.token == ast.KindQuestionDotToken { p.sourceFlags |= ast.NodeFlagsPossiblyContainsDynamicImport } } else { diff --git a/tsc/testdata/baselines/reference/conformance/importDeferOptionalChain.errors.txt b/tsc/testdata/baselines/reference/conformance/importDeferOptionalChain.errors.txt new file mode 100644 index 0000000000000..5dce7fa4638ff --- /dev/null +++ b/tsc/testdata/baselines/reference/conformance/importDeferOptionalChain.errors.txt @@ -0,0 +1,11 @@ +importDeferOptionalChain.ts(1,1): error TS100069: Calls to 'import()' are not permitted in an optional chain. +importDeferOptionalChain.ts(1,16): error TS2307: Cannot find module './a' or its corresponding type declarations. + + +==== importDeferOptionalChain.ts (2 errors) ==== + import.defer?.("./a"); + ~~~~~~~~~~~~~~~~~~~~~ +!!! error TS100069: Calls to 'import()' are not permitted in an optional chain. + ~~~~~ +!!! error TS2307: Cannot find module './a' or its corresponding type declarations. + \ No newline at end of file diff --git a/tsc/testdata/baselines/reference/conformance/importDeferOptionalChain.js b/tsc/testdata/baselines/reference/conformance/importDeferOptionalChain.js new file mode 100644 index 0000000000000..b53bd6104d5b6 --- /dev/null +++ b/tsc/testdata/baselines/reference/conformance/importDeferOptionalChain.js @@ -0,0 +1,9 @@ +//// [tests/cases/conformance/importDefer/importDeferOptionalChain.ts] //// + +//// [importDeferOptionalChain.ts] +import.defer?.("./a"); + + +//// [importDeferOptionalChain.js] +"use strict"; +import.defer?.("./a"); diff --git a/tsc/testdata/baselines/reference/conformance/importDeferOptionalChain.symbols b/tsc/testdata/baselines/reference/conformance/importDeferOptionalChain.symbols new file mode 100644 index 0000000000000..3fb2655dc86b0 --- /dev/null +++ b/tsc/testdata/baselines/reference/conformance/importDeferOptionalChain.symbols @@ -0,0 +1,6 @@ +//// [tests/cases/conformance/importDefer/importDeferOptionalChain.ts] //// + +=== importDeferOptionalChain.ts === + +import.defer?.("./a"); + diff --git a/tsc/testdata/baselines/reference/conformance/importDeferOptionalChain.types b/tsc/testdata/baselines/reference/conformance/importDeferOptionalChain.types new file mode 100644 index 0000000000000..e4fbf942fbaff --- /dev/null +++ b/tsc/testdata/baselines/reference/conformance/importDeferOptionalChain.types @@ -0,0 +1,8 @@ +//// [tests/cases/conformance/importDefer/importDeferOptionalChain.ts] //// + +=== importDeferOptionalChain.ts === +import.defer?.("./a"); +>import.defer?.("./a") : Promise +>defer : any +>"./a" : "./a" + diff --git a/tsc/testdata/tests/cases/conformance/importDefer/importDeferOptionalChain.ts b/tsc/testdata/tests/cases/conformance/importDefer/importDeferOptionalChain.ts new file mode 100644 index 0000000000000..b13867189205e --- /dev/null +++ b/tsc/testdata/tests/cases/conformance/importDefer/importDeferOptionalChain.ts @@ -0,0 +1,4 @@ +// @target: esnext +// @module: esnext + +import.defer?.("./a");