Skip to content

Commit f239bbc

Browse files
committed
Merge pull request #2550 from Microsoft/separateCompilation
Relax import/export elision rules for separate compilation
2 parents ed381fe + 1bdcaa3 commit f239bbc

File tree

55 files changed

+578
-16
lines changed

Some content is hidden

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

55 files changed

+578
-16
lines changed

Diff for: src/compiler/checker.ts

+23-6
Original file line numberDiff line numberDiff line change
@@ -713,8 +713,14 @@ module ts {
713713
function markExportAsReferenced(node: ImportEqualsDeclaration | ExportAssignment | ExportSpecifier) {
714714
let symbol = getSymbolOfNode(node);
715715
let target = resolveAlias(symbol);
716-
if (target && target !== unknownSymbol && target.flags & SymbolFlags.Value && !isConstEnumOrConstEnumOnlyModule(target)) {
717-
markAliasSymbolAsReferenced(symbol);
716+
if (target) {
717+
let markAlias =
718+
(target === unknownSymbol && compilerOptions.separateCompilation) ||
719+
(target !== unknownSymbol && (target.flags & SymbolFlags.Value) && !isConstEnumOrConstEnumOnlyModule(target));
720+
721+
if (markAlias) {
722+
markAliasSymbolAsReferenced(symbol);
723+
}
718724
}
719725
}
720726

@@ -9747,7 +9753,9 @@ module ts {
97479753

97489754
checkKindsOfPropertyMemberOverrides(type, baseType);
97499755
}
9756+
}
97509757

9758+
if (type.baseTypes.length || (baseTypeNode && compilerOptions.separateCompilation)) {
97519759
// Check that base type can be evaluated as expression
97529760
checkExpressionOrQualifiedName(baseTypeNode.typeName);
97539761
}
@@ -10151,6 +10159,11 @@ module ts {
1015110159

1015210160
computeEnumMemberValues(node);
1015310161

10162+
let enumIsConst = isConst(node);
10163+
if (compilerOptions.separateCompilation && enumIsConst && isInAmbientContext(node)) {
10164+
error(node.name, Diagnostics.Ambient_const_enums_are_not_allowed_when_the_separateCompilation_flag_is_provided);
10165+
}
10166+
1015410167
// Spec 2014 - Section 9.3:
1015510168
// It isn't possible for one enum declaration to continue the automatic numbering sequence of another,
1015610169
// and when an enum type has multiple declarations, only one declaration is permitted to omit a value
@@ -10161,7 +10174,6 @@ module ts {
1016110174
let firstDeclaration = getDeclarationOfKind(enumSymbol, node.kind);
1016210175
if (node === firstDeclaration) {
1016310176
if (enumSymbol.declarations.length > 1) {
10164-
let enumIsConst = isConst(node);
1016510177
// check that const is placed\omitted on all enum declarations
1016610178
forEach(enumSymbol.declarations, decl => {
1016710179
if (isConstEnumDeclaration(decl) !== enumIsConst) {
@@ -10223,7 +10235,7 @@ module ts {
1022310235
if (symbol.flags & SymbolFlags.ValueModule
1022410236
&& symbol.declarations.length > 1
1022510237
&& !isInAmbientContext(node)
10226-
&& isInstantiatedModule(node, compilerOptions.preserveConstEnums)) {
10238+
&& isInstantiatedModule(node, compilerOptions.preserveConstEnums || compilerOptions.separateCompilation)) {
1022710239
let classOrFunc = getFirstNonAmbientClassOrFunctionDeclaration(symbol);
1022810240
if (classOrFunc) {
1022910241
if (getSourceFileOfNode(node) !== getSourceFileOfNode(classOrFunc)) {
@@ -11266,13 +11278,18 @@ module ts {
1126611278
// parent is not source file or it is not reference to internal module
1126711279
return false;
1126811280
}
11269-
return isAliasResolvedToValue(getSymbolOfNode(node));
11281+
11282+
var isValue = isAliasResolvedToValue(getSymbolOfNode(node));
11283+
return isValue && node.moduleReference && !nodeIsMissing(node.moduleReference);
1127011284
}
1127111285

1127211286
function isAliasResolvedToValue(symbol: Symbol): boolean {
1127311287
let target = resolveAlias(symbol);
11288+
if (target === unknownSymbol && compilerOptions.separateCompilation) {
11289+
return true;
11290+
}
1127411291
// const enums and modules that contain only const enums are not considered values from the emit perespective
11275-
return target !== unknownSymbol && target.flags & SymbolFlags.Value && !isConstEnumOrConstEnumOnlyModule(target);
11292+
return target !== unknownSymbol && target && target.flags & SymbolFlags.Value && !isConstEnumOrConstEnumOnlyModule(target);
1127611293
}
1127711294

1127811295
function isConstEnumOrConstEnumOnlyModule(s: Symbol): boolean {

Diff for: src/compiler/commandLineParser.ts

+4
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ module ts {
109109
type: "boolean",
110110
description: Diagnostics.Do_not_emit_comments_to_output,
111111
},
112+
{
113+
name: "separateCompilation",
114+
type: "boolean",
115+
},
112116
{
113117
name: "sourceMap",
114118
type: "boolean",

Diff for: src/compiler/diagnosticInformationMap.generated.ts

+7
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@ module ts {
165165
Decorators_are_only_available_when_targeting_ECMAScript_5_and_higher: { code: 1205, category: DiagnosticCategory.Error, key: "Decorators are only available when targeting ECMAScript 5 and higher." },
166166
Decorators_are_not_valid_here: { code: 1206, category: DiagnosticCategory.Error, key: "Decorators are not valid here." },
167167
Decorators_cannot_be_applied_to_multiple_get_Slashset_accessors_of_the_same_name: { code: 1207, category: DiagnosticCategory.Error, key: "Decorators cannot be applied to multiple get/set accessors of the same name." },
168+
Cannot_compile_non_external_modules_when_the_separateCompilation_flag_is_provided: { code: 1208, category: DiagnosticCategory.Error, key: "Cannot compile non-external modules when the '--separateCompilation' flag is provided." },
169+
Ambient_const_enums_are_not_allowed_when_the_separateCompilation_flag_is_provided: { code: 1209, category: DiagnosticCategory.Error, key: "Ambient const enums are not allowed when the '--separateCompilation' flag is provided." },
168170
Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." },
169171
Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: { code: 2301, category: DiagnosticCategory.Error, key: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor." },
170172
Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." },
@@ -434,6 +436,11 @@ module ts {
434436
Option_noEmit_cannot_be_specified_with_option_out_or_outDir: { code: 5040, category: DiagnosticCategory.Error, key: "Option 'noEmit' cannot be specified with option 'out' or 'outDir'." },
435437
Option_noEmit_cannot_be_specified_with_option_declaration: { code: 5041, category: DiagnosticCategory.Error, key: "Option 'noEmit' cannot be specified with option 'declaration'." },
436438
Option_project_cannot_be_mixed_with_source_files_on_a_command_line: { code: 5042, category: DiagnosticCategory.Error, key: "Option 'project' cannot be mixed with source files on a command line." },
439+
Option_sourceMap_cannot_be_specified_with_option_separateCompilation: { code: 5043, category: DiagnosticCategory.Error, key: "Option 'sourceMap' cannot be specified with option 'separateCompilation'." },
440+
Option_declaration_cannot_be_specified_with_option_separateCompilation: { code: 5044, category: DiagnosticCategory.Error, key: "Option 'declaration' cannot be specified with option 'separateCompilation'." },
441+
Option_noEmitOnError_cannot_be_specified_with_option_separateCompilation: { code: 5045, category: DiagnosticCategory.Error, key: "Option 'noEmitOnError' cannot be specified with option 'separateCompilation'." },
442+
Option_out_cannot_be_specified_with_option_separateCompilation: { code: 5046, category: DiagnosticCategory.Error, key: "Option 'out' cannot be specified with option 'separateCompilation'." },
443+
Option_separateCompilation_can_only_be_used_when_either_option_module_is_provided_or_option_target_is_ES6_or_higher: { code: 5047, category: DiagnosticCategory.Error, key: "Option 'separateCompilation' can only be used when either option'--module' is provided or option 'target' is 'ES6' or higher." },
437444
Concatenate_and_emit_output_to_single_file: { code: 6001, category: DiagnosticCategory.Message, key: "Concatenate and emit output to single file." },
438445
Generates_corresponding_d_ts_file: { code: 6002, category: DiagnosticCategory.Message, key: "Generates corresponding '.d.ts' file." },
439446
Specifies_the_location_where_debugger_should_locate_map_files_instead_of_generated_locations: { code: 6003, category: DiagnosticCategory.Message, key: "Specifies the location where debugger should locate map files instead of generated locations." },

Diff for: src/compiler/diagnosticMessages.json

+28-1
Original file line numberDiff line numberDiff line change
@@ -651,7 +651,14 @@
651651
"category": "Error",
652652
"code": 1207
653653
},
654-
654+
"Cannot compile non-external modules when the '--separateCompilation' flag is provided.": {
655+
"category": "Error",
656+
"code": 1208
657+
},
658+
"Ambient const enums are not allowed when the '--separateCompilation' flag is provided.": {
659+
"category": "Error",
660+
"code": 1209
661+
},
655662
"Duplicate identifier '{0}'.": {
656663
"category": "Error",
657664
"code": 2300
@@ -1729,6 +1736,26 @@
17291736
"category": "Error",
17301737
"code": 5042
17311738
},
1739+
"Option 'sourceMap' cannot be specified with option 'separateCompilation'.": {
1740+
"category": "Error",
1741+
"code": 5043
1742+
},
1743+
"Option 'declaration' cannot be specified with option 'separateCompilation'.": {
1744+
"category": "Error",
1745+
"code": 5044
1746+
},
1747+
"Option 'noEmitOnError' cannot be specified with option 'separateCompilation'.": {
1748+
"category": "Error",
1749+
"code": 5045
1750+
},
1751+
"Option 'out' cannot be specified with option 'separateCompilation'.": {
1752+
"category": "Error",
1753+
"code": 5046
1754+
},
1755+
"Option 'separateCompilation' can only be used when either option'--module' is provided or option 'target' is 'ES6' or higher.": {
1756+
"category": "Error",
1757+
"code": 5047
1758+
},
17321759
"Concatenate and emit output to single file.": {
17331760
"category": "Message",
17341761
"code": 6001

Diff for: src/compiler/emitter.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -1641,6 +1641,11 @@ module ts {
16411641
}
16421642

16431643
function tryEmitConstantValue(node: PropertyAccessExpression | ElementAccessExpression): boolean {
1644+
if (compilerOptions.separateCompilation) {
1645+
// do not inline enum values in separate compilation mode
1646+
return false;
1647+
}
1648+
16441649
let constantValue = resolver.getConstantValue(node);
16451650
if (constantValue !== undefined) {
16461651
write(constantValue.toString());
@@ -3872,7 +3877,7 @@ module ts {
38723877

38733878
function shouldEmitEnumDeclaration(node: EnumDeclaration) {
38743879
let isConstEnum = isConst(node);
3875-
return !isConstEnum || compilerOptions.preserveConstEnums;
3880+
return !isConstEnum || compilerOptions.preserveConstEnums || compilerOptions.separateCompilation;
38763881
}
38773882

38783883
function emitEnumDeclaration(node: EnumDeclaration) {
@@ -3964,7 +3969,7 @@ module ts {
39643969
}
39653970

39663971
function shouldEmitModuleDeclaration(node: ModuleDeclaration) {
3967-
return isInstantiatedModule(node, compilerOptions.preserveConstEnums);
3972+
return isInstantiatedModule(node, compilerOptions.preserveConstEnums || compilerOptions.separateCompilation);
39683973
}
39693974

39703975
function emitModuleDeclaration(node: ModuleDeclaration) {

Diff for: src/compiler/program.ts

+33-6
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,24 @@ module ts {
454454
}
455455

456456
function verifyCompilerOptions() {
457+
if (options.separateCompilation) {
458+
if (options.sourceMap) {
459+
diagnostics.add(createCompilerDiagnostic(Diagnostics.Option_sourceMap_cannot_be_specified_with_option_separateCompilation));
460+
}
461+
462+
if (options.declaration) {
463+
diagnostics.add(createCompilerDiagnostic(Diagnostics.Option_declaration_cannot_be_specified_with_option_separateCompilation));
464+
}
465+
466+
if (options.noEmitOnError) {
467+
diagnostics.add(createCompilerDiagnostic(Diagnostics.Option_noEmitOnError_cannot_be_specified_with_option_separateCompilation));
468+
}
469+
470+
if (options.out) {
471+
diagnostics.add(createCompilerDiagnostic(Diagnostics.Option_out_cannot_be_specified_with_option_separateCompilation));
472+
}
473+
}
474+
457475
if (!options.sourceMap && (options.mapRoot || options.sourceRoot)) {
458476
// Error to specify --mapRoot or --sourceRoot without mapSourceFiles
459477
if (options.mapRoot) {
@@ -468,24 +486,33 @@ module ts {
468486
let languageVersion = options.target || ScriptTarget.ES3;
469487

470488
let firstExternalModuleSourceFile = forEach(files, f => isExternalModule(f) ? f : undefined);
471-
if (firstExternalModuleSourceFile && !options.module) {
489+
if (options.separateCompilation) {
472490
if (!options.module && languageVersion < ScriptTarget.ES6) {
473-
// We cannot use createDiagnosticFromNode because nodes do not have parents yet
474-
let span = getErrorSpanForNode(firstExternalModuleSourceFile, firstExternalModuleSourceFile.externalModuleIndicator);
475-
diagnostics.add(createFileDiagnostic(firstExternalModuleSourceFile, span.start, span.length, Diagnostics.Cannot_compile_external_modules_unless_the_module_flag_is_provided));
491+
diagnostics.add(createCompilerDiagnostic(Diagnostics.Option_separateCompilation_can_only_be_used_when_either_option_module_is_provided_or_option_target_is_ES6_or_higher));
476492
}
493+
494+
let firstNonExternalModuleSourceFile = forEach(files, f => !isExternalModule(f) && !isDeclarationFile(f) ? f : undefined);
495+
if (firstNonExternalModuleSourceFile) {
496+
let span = getErrorSpanForNode(firstNonExternalModuleSourceFile, firstNonExternalModuleSourceFile);
497+
diagnostics.add(createFileDiagnostic(firstNonExternalModuleSourceFile, span.start, span.length, Diagnostics.Cannot_compile_non_external_modules_when_the_separateCompilation_flag_is_provided));
498+
}
499+
}
500+
else if (firstExternalModuleSourceFile && languageVersion < ScriptTarget.ES6 && !options.module) {
501+
// We cannot use createDiagnosticFromNode because nodes do not have parents yet
502+
let span = getErrorSpanForNode(firstExternalModuleSourceFile, firstExternalModuleSourceFile.externalModuleIndicator);
503+
diagnostics.add(createFileDiagnostic(firstExternalModuleSourceFile, span.start, span.length, Diagnostics.Cannot_compile_external_modules_unless_the_module_flag_is_provided));
477504
}
478505

479506
// Cannot specify module gen target when in es6 or above
480507
if (options.module && languageVersion >= ScriptTarget.ES6) {
481508
diagnostics.add(createCompilerDiagnostic(Diagnostics.Cannot_compile_external_modules_into_amd_or_commonjs_when_targeting_es6_or_higher));
482509
}
483510

484-
// there has to be common source directory if user specified --outdir || --sourcRoot
511+
// there has to be common source directory if user specified --outdir || --sourceRoot
485512
// if user specified --mapRoot, there needs to be common source directory if there would be multiple files being emitted
486513
if (options.outDir || // there is --outDir specified
487514
options.sourceRoot || // there is --sourceRoot specified
488-
(options.mapRoot && // there is --mapRoot Specified and there would be multiple js files generated
515+
(options.mapRoot && // there is --mapRoot specified and there would be multiple js files generated
489516
(!options.out || firstExternalModuleSourceFile !== undefined))) {
490517

491518
let commonPathComponents: string[];

Diff for: src/compiler/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1585,6 +1585,7 @@ module ts {
15851585
target?: ScriptTarget;
15861586
version?: boolean;
15871587
watch?: boolean;
1588+
separateCompilation?: boolean;
15881589
/* @internal */ stripInternal?: boolean;
15891590
[option: string]: string | number | boolean;
15901591
}

Diff for: src/compiler/utilities.ts

+7
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,13 @@ module ts {
274274
export function getErrorSpanForNode(sourceFile: SourceFile, node: Node): TextSpan {
275275
let errorNode = node;
276276
switch (node.kind) {
277+
case SyntaxKind.SourceFile:
278+
let pos = skipTrivia(sourceFile.text, 0, /*stopAfterLineBreak*/ false);
279+
if (pos === sourceFile.text.length) {
280+
// file is empty - return span for the beginning of the file
281+
return createTextSpan(0, 0);
282+
}
283+
return getSpanOfTokenAtPosition(sourceFile, pos);
277284
// This list is a work in progress. Add missing node kinds to improve their error
278285
// spans.
279286
case SyntaxKind.VariableDeclaration:

Diff for: src/harness/harness.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -1052,6 +1052,10 @@ module Harness {
10521052
options.preserveConstEnums = setting.value === 'true';
10531053
break;
10541054

1055+
case 'separatecompilation':
1056+
options.separateCompilation = setting.value === 'true';
1057+
break;
1058+
10551059
case 'suppressimplicitanyindexerrors':
10561060
options.suppressImplicitAnyIndexErrors = setting.value === 'true';
10571061
break;
@@ -1451,7 +1455,12 @@ module Harness {
14511455
var optionRegex = /^[\/]{2}\s*@(\w+)\s*:\s*(\S*)/gm; // multiple matches on multiple lines
14521456

14531457
// List of allowed metadata names
1454-
var fileMetadataNames = ["filename", "comments", "declaration", "module", "nolib", "sourcemap", "target", "out", "outdir", "noemitonerror", "noimplicitany", "noresolve", "newline", "newlines", "emitbom", "errortruncation", "usecasesensitivefilenames", "preserveconstenums", "includebuiltfile", "suppressimplicitanyindexerrors", "stripinternal"];
1458+
var fileMetadataNames = ["filename", "comments", "declaration", "module",
1459+
"nolib", "sourcemap", "target", "out", "outdir", "noemitonerror",
1460+
"noimplicitany", "noresolve", "newline", "newlines", "emitbom",
1461+
"errortruncation", "usecasesensitivefilenames", "preserveconstenums",
1462+
"includebuiltfile", "suppressimplicitanyindexerrors", "stripinternal",
1463+
"separatecompilation"];
14551464

14561465
function extractCompilerSettings(content: string): CompilerSetting[] {
14571466

0 commit comments

Comments
 (0)