Skip to content

Commit a69c6d0

Browse files
nicolo-ribaudoryzokukenNicolò Ribaudo
authored
Add support for import defer proposal (#60757)
Co-authored-by: Ujjwal Sharma <ryzokuken@disroot.org> Co-authored-by: Nicolò Ribaudo <hell@nicr.dev>
1 parent cd34199 commit a69c6d0

File tree

138 files changed

+2710
-292
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

138 files changed

+2710
-292
lines changed

src/compiler/checker.ts

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10247,7 +10247,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1024710247
factory.createImportDeclaration(
1024810248
/*modifiers*/ undefined,
1024910249
factory.createImportClause(
10250-
/*isTypeOnly*/ false,
10250+
/*phaseModifier*/ undefined,
1025110251
/*name*/ undefined,
1025210252
factory.createNamedImports([factory.createImportSpecifier(
1025310253
/*isTypeOnly*/ false,
@@ -10344,7 +10344,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1034410344
addResult(
1034510345
factory.createImportDeclaration(
1034610346
/*modifiers*/ undefined,
10347-
factory.createImportClause(isTypeOnly, factory.createIdentifier(localName), /*namedBindings*/ undefined),
10347+
factory.createImportClause(
10348+
/* phaseModifier */ isTypeOnly ? SyntaxKind.TypeKeyword : undefined,
10349+
factory.createIdentifier(localName),
10350+
/*namedBindings*/ undefined,
10351+
),
1034810352
specifier,
1034910353
attributes,
1035010354
),
@@ -10360,7 +10364,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1036010364
addResult(
1036110365
factory.createImportDeclaration(
1036210366
/*modifiers*/ undefined,
10363-
factory.createImportClause(isTypeOnly, /*name*/ undefined, factory.createNamespaceImport(factory.createIdentifier(localName))),
10367+
factory.createImportClause(
10368+
/* phaseModifier */ isTypeOnly ? SyntaxKind.TypeKeyword : undefined,
10369+
/*name*/ undefined,
10370+
factory.createNamespaceImport(factory.createIdentifier(localName)),
10371+
),
1036410372
specifier,
1036510373
(node as ImportClause).parent.attributes,
1036610374
),
@@ -10389,7 +10397,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1038910397
factory.createImportDeclaration(
1039010398
/*modifiers*/ undefined,
1039110399
factory.createImportClause(
10392-
isTypeOnly,
10400+
/* phaseModifier */ isTypeOnly ? SyntaxKind.TypeKeyword : undefined,
1039310401
/*name*/ undefined,
1039410402
factory.createNamedImports([
1039510403
factory.createImportSpecifier(
@@ -38014,6 +38022,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3801438022
}
3801538023

3801638024
if (node.keywordToken === SyntaxKind.ImportKeyword) {
38025+
if (node.name.escapedText === "defer") {
38026+
Debug.assert(!isCallExpression(node.parent) || node.parent.expression !== node, "Trying to get the type of `import.defer` in `import.defer(...)`");
38027+
return errorType;
38028+
}
3801738029
return checkImportMetaProperty(node);
3801838030
}
3801938031

@@ -41452,7 +41464,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4145241464
}
4145341465
// Optimize for the common case of a call to a function with a single non-generic call
4145441466
// signature where we can just fetch the return type without checking the arguments.
41455-
if (isCallExpression(expr) && expr.expression.kind !== SyntaxKind.SuperKeyword && !isRequireCall(expr, /*requireStringLiteralLikeArgument*/ true) && !isSymbolOrSymbolForCall(expr)) {
41467+
if (isCallExpression(expr) && expr.expression.kind !== SyntaxKind.SuperKeyword && !isRequireCall(expr, /*requireStringLiteralLikeArgument*/ true) && !isSymbolOrSymbolForCall(expr) && !isImportCall(expr)) {
4145641468
return isCallChain(expr) ? getReturnTypeOfSingleNonGenericSignatureOfCallChain(expr) :
4145741469
getReturnTypeOfSingleNonGenericCallSignature(checkNonNullExpression(expr.expression));
4145841470
}
@@ -41606,8 +41618,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4160641618
case SyntaxKind.ElementAccessExpression:
4160741619
return checkIndexedAccess(node as ElementAccessExpression, checkMode);
4160841620
case SyntaxKind.CallExpression:
41609-
if ((node as CallExpression).expression.kind === SyntaxKind.ImportKeyword) {
41610-
return checkImportCallExpression(node as ImportCall);
41621+
if (isImportCall(node)) {
41622+
return checkImportCallExpression(node);
4161141623
}
4161241624
// falls through
4161341625
case SyntaxKind.NewExpression:
@@ -49877,6 +49889,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4987749889
return isExportAssignment(node.parent) ? Debug.checkDefined(node.parent.symbol) : undefined;
4987849890

4987949891
case SyntaxKind.ImportKeyword:
49892+
if (isMetaProperty(node.parent) && node.parent.name.escapedText === "defer") {
49893+
return undefined;
49894+
}
49895+
// falls through
4988049896
case SyntaxKind.NewKeyword:
4988149897
return isMetaProperty(node.parent) ? checkMetaPropertyKeyword(node.parent).symbol : undefined;
4988249898
case SyntaxKind.InstanceOfKeyword:
@@ -52851,7 +52867,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
5285152867
break;
5285252868
case SyntaxKind.ImportKeyword:
5285352869
if (escapedText !== "meta") {
52854-
return grammarErrorOnNode(node.name, Diagnostics._0_is_not_a_valid_meta_property_for_keyword_1_Did_you_mean_2, unescapeLeadingUnderscores(node.name.escapedText), tokenToString(node.keywordToken), "meta");
52870+
const isCallee = isCallExpression(node.parent) && node.parent.expression === node;
52871+
if (escapedText === "defer") {
52872+
if (!isCallee) {
52873+
return grammarErrorAtPos(node, node.end, 0, Diagnostics._0_expected, "(");
52874+
}
52875+
}
52876+
else {
52877+
if (isCallee) {
52878+
return grammarErrorOnNode(node.name, Diagnostics._0_is_not_a_valid_meta_property_for_keyword_import_Did_you_mean_meta_or_defer, unescapeLeadingUnderscores(node.name.escapedText));
52879+
}
52880+
return grammarErrorOnNode(node.name, Diagnostics._0_is_not_a_valid_meta_property_for_keyword_1_Did_you_mean_2, unescapeLeadingUnderscores(node.name.escapedText), tokenToString(node.keywordToken), "meta");
52881+
}
5285552882
}
5285652883
break;
5285752884
}
@@ -53110,11 +53137,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
5311053137
}
5311153138

5311253139
function checkGrammarImportClause(node: ImportClause): boolean {
53113-
if (node.isTypeOnly && node.name && node.namedBindings) {
53114-
return grammarErrorOnNode(node, Diagnostics.A_type_only_import_can_specify_a_default_import_or_named_bindings_but_not_both);
53140+
if (node.phaseModifier === SyntaxKind.TypeKeyword) {
53141+
if (node.name && node.namedBindings) {
53142+
return grammarErrorOnNode(node, Diagnostics.A_type_only_import_can_specify_a_default_import_or_named_bindings_but_not_both);
53143+
}
53144+
if (node.namedBindings?.kind === SyntaxKind.NamedImports) {
53145+
return checkGrammarNamedImportsOrExports(node.namedBindings);
53146+
}
5311553147
}
53116-
if (node.isTypeOnly && node.namedBindings?.kind === SyntaxKind.NamedImports) {
53117-
return checkGrammarNamedImportsOrExports(node.namedBindings);
53148+
else if (node.phaseModifier === SyntaxKind.DeferKeyword) {
53149+
if (node.name) {
53150+
return grammarErrorOnNode(node, Diagnostics.Default_imports_are_not_allowed_in_a_deferred_import);
53151+
}
53152+
if (node.namedBindings?.kind === SyntaxKind.NamedImports) {
53153+
return grammarErrorOnNode(node, Diagnostics.Named_imports_are_not_allowed_in_a_deferred_import);
53154+
}
53155+
if (moduleKind !== ModuleKind.ESNext && moduleKind !== ModuleKind.Preserve) {
53156+
return grammarErrorOnNode(node, Diagnostics.Deferred_imports_are_only_supported_when_the_module_flag_is_set_to_esnext_or_preserve);
53157+
}
5311853158
}
5311953159
return false;
5312053160
}
@@ -53137,7 +53177,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
5313753177
return grammarErrorOnNode(node, Diagnostics.ESM_syntax_is_not_allowed_in_a_CommonJS_module_when_verbatimModuleSyntax_is_enabled);
5313853178
}
5313953179

53140-
if (moduleKind === ModuleKind.ES2015) {
53180+
if (node.expression.kind === SyntaxKind.MetaProperty) {
53181+
if (moduleKind !== ModuleKind.ESNext && moduleKind !== ModuleKind.Preserve) {
53182+
return grammarErrorOnNode(node, Diagnostics.Deferred_imports_are_only_supported_when_the_module_flag_is_set_to_esnext_or_preserve);
53183+
}
53184+
}
53185+
else if (moduleKind === ModuleKind.ES2015) {
5314153186
return grammarErrorOnNode(node, Diagnostics.Dynamic_imports_are_only_supported_when_the_module_flag_is_set_to_es2020_es2022_esnext_commonjs_amd_system_umd_node16_node18_or_nodenext);
5314253187
}
5314353188

src/compiler/diagnosticMessages.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8487,5 +8487,21 @@
84878487
"String literal import and export names are not supported when the '--module' flag is set to 'es2015' or 'es2020'.": {
84888488
"category": "Error",
84898489
"code": 18057
8490+
},
8491+
"Default imports are not allowed in a deferred import.": {
8492+
"category": "Error",
8493+
"code": 18058
8494+
},
8495+
"Named imports are not allowed in a deferred import.": {
8496+
"category": "Error",
8497+
"code": 18059
8498+
},
8499+
"Deferred imports are only supported when the '--module' flag is set to 'esnext' or 'preserve'.": {
8500+
"category": "Error",
8501+
"code": 18060
8502+
},
8503+
"'{0}' is not a valid meta-property for keyword 'import'. Did you mean 'meta' or 'defer'?": {
8504+
"category": "Error",
8505+
"code": 18061
84908506
}
84918507
}

src/compiler/emitter.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3686,8 +3686,8 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
36863686
}
36873687

36883688
function emitImportClause(node: ImportClause) {
3689-
if (node.isTypeOnly) {
3690-
emitTokenWithComment(SyntaxKind.TypeKeyword, node.pos, writeKeyword, node);
3689+
if (node.phaseModifier !== undefined) {
3690+
emitTokenWithComment(node.phaseModifier, node.pos, writeKeyword, node);
36913691
writeSpace();
36923692
}
36933693
emit(node.name);

src/compiler/factory/nodeFactory.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ import {
135135
ImportClause,
136136
ImportDeclaration,
137137
ImportEqualsDeclaration,
138+
ImportPhaseModifierSyntaxKind,
138139
ImportSpecifier,
139140
ImportTypeAssertionContainer,
140141
ImportTypeNode,
@@ -4723,26 +4724,33 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
47234724
}
47244725

47254726
// @api
4726-
function createImportClause(isTypeOnly: boolean, name: Identifier | undefined, namedBindings: NamedImportBindings | undefined): ImportClause {
4727+
function createImportClause(phaseModifier: ImportPhaseModifierSyntaxKind | boolean | undefined, name: Identifier | undefined, namedBindings: NamedImportBindings | undefined): ImportClause {
47274728
const node = createBaseDeclaration<ImportClause>(SyntaxKind.ImportClause);
4728-
node.isTypeOnly = isTypeOnly;
4729+
if (typeof phaseModifier === "boolean") {
4730+
phaseModifier = phaseModifier ? SyntaxKind.TypeKeyword : undefined;
4731+
}
4732+
node.isTypeOnly = phaseModifier === SyntaxKind.TypeKeyword;
4733+
node.phaseModifier = phaseModifier;
47294734
node.name = name;
47304735
node.namedBindings = namedBindings;
47314736
node.transformFlags |= propagateChildFlags(node.name) |
47324737
propagateChildFlags(node.namedBindings);
4733-
if (isTypeOnly) {
4738+
if (phaseModifier === SyntaxKind.TypeKeyword) {
47344739
node.transformFlags |= TransformFlags.ContainsTypeScript;
47354740
}
47364741
node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context
47374742
return node;
47384743
}
47394744

47404745
// @api
4741-
function updateImportClause(node: ImportClause, isTypeOnly: boolean, name: Identifier | undefined, namedBindings: NamedImportBindings | undefined) {
4742-
return node.isTypeOnly !== isTypeOnly
4746+
function updateImportClause(node: ImportClause, phaseModifier: ImportPhaseModifierSyntaxKind | boolean | undefined, name: Identifier | undefined, namedBindings: NamedImportBindings | undefined) {
4747+
if (typeof phaseModifier === "boolean") {
4748+
phaseModifier = phaseModifier ? SyntaxKind.TypeKeyword : undefined;
4749+
}
4750+
return node.phaseModifier !== phaseModifier
47434751
|| node.name !== name
47444752
|| node.namedBindings !== namedBindings
4745-
? update(createImportClause(isTypeOnly, name, namedBindings), node)
4753+
? update(createImportClause(phaseModifier, name, namedBindings), node)
47464754
: node;
47474755
}
47484756

src/compiler/factory/utilities.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -730,7 +730,7 @@ export function createExternalHelpersImportDeclarationIfNeeded(nodeFactory: Node
730730

731731
const externalHelpersImportDeclaration = nodeFactory.createImportDeclaration(
732732
/*modifiers*/ undefined,
733-
nodeFactory.createImportClause(/*isTypeOnly*/ false, /*name*/ undefined, namedBindings),
733+
nodeFactory.createImportClause(/*phaseModifier*/ undefined, /*name*/ undefined, namedBindings),
734734
nodeFactory.createStringLiteral(externalHelpersModuleNameText),
735735
/*attributes*/ undefined,
736736
);

0 commit comments

Comments
 (0)