Skip to content

Commit a33dae3

Browse files
authored
Rework how default vs local name selection is done to be more correct (microsoft#21526)
1 parent 058b2f7 commit a33dae3

22 files changed

+494
-29
lines changed

src/compiler/checker.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2693,6 +2693,9 @@ namespace ts {
26932693
if (flags & SymbolFormatFlags.WriteTypeParametersOrArguments) {
26942694
nodeFlags |= NodeBuilderFlags.WriteTypeParametersInQualifiedName;
26952695
}
2696+
if (flags & SymbolFormatFlags.UseAliasDefinedOutsideCurrentScope) {
2697+
nodeFlags |= NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope;
2698+
}
26962699
const builder = flags & SymbolFormatFlags.AllowAnyNodeKind ? nodeBuilder.symbolToExpression : nodeBuilder.symbolToEntityName;
26972700
return writer ? symbolToStringWorker(writer).getText() : usingSingleLineStringWriter(symbolToStringWorker);
26982701

@@ -3454,7 +3457,14 @@ namespace ts {
34543457
function createEntityNameFromSymbolChain(chain: Symbol[], index: number): EntityName {
34553458
const typeParameterNodes = lookupTypeParameterNodes(chain, index, context);
34563459
const symbol = chain[index];
3460+
3461+
if (index === 0) {
3462+
context.flags |= NodeBuilderFlags.InInitialEntityName;
3463+
}
34573464
const symbolName = getNameOfSymbolAsWritten(symbol, context);
3465+
if (index === 0) {
3466+
context.flags ^= NodeBuilderFlags.InInitialEntityName;
3467+
}
34583468
const identifier = setEmitFlags(createIdentifier(symbolName, typeParameterNodes), EmitFlags.NoAsciiEscaping);
34593469
identifier.symbol = symbol;
34603470

@@ -3471,7 +3481,13 @@ namespace ts {
34713481
const typeParameterNodes = lookupTypeParameterNodes(chain, index, context);
34723482
const symbol = chain[index];
34733483

3484+
if (index === 0) {
3485+
context.flags |= NodeBuilderFlags.InInitialEntityName;
3486+
}
34743487
let symbolName = getNameOfSymbolAsWritten(symbol, context);
3488+
if (index === 0) {
3489+
context.flags ^= NodeBuilderFlags.InInitialEntityName;
3490+
}
34753491
let firstChar = symbolName.charCodeAt(0);
34763492
const canUsePropertyAccess = isIdentifierStart(firstChar, languageVersion);
34773493
if (index === 0 || canUsePropertyAccess) {
@@ -3584,6 +3600,10 @@ namespace ts {
35843600
symbolStack: Symbol[] | undefined;
35853601
}
35863602

3603+
function isDefaultBindingContext(location: Node) {
3604+
return location.kind === SyntaxKind.SourceFile || isAmbientModule(location);
3605+
}
3606+
35873607
/**
35883608
* Gets a human-readable name for a symbol.
35893609
* Should *not* be used for the right-hand side of a `.` -- use `symbolName(symbol)` for that instead.
@@ -3592,7 +3612,13 @@ namespace ts {
35923612
* It will also use a representation of a number as written instead of a decimal form, e.g. `0o11` instead of `9`.
35933613
*/
35943614
function getNameOfSymbolAsWritten(symbol: Symbol, context?: NodeBuilderContext): string {
3595-
if (context && context.flags & NodeBuilderFlags.WriteDefaultSymbolWithoutName && symbol.escapedName === InternalSymbolName.Default) {
3615+
if (context && symbol.escapedName === InternalSymbolName.Default && !(context.flags & NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope) &&
3616+
// If it's not the first part of an entity name, it must print as `default`
3617+
(!(context.flags & NodeBuilderFlags.InInitialEntityName) ||
3618+
// if the symbol is synthesized, it will only be referenced externally it must print as `default`
3619+
!symbol.declarations ||
3620+
// if not in the same binding context (source file, module declaration), it must print as `default`
3621+
(context.enclosingDeclaration && findAncestor(symbol.declarations[0], isDefaultBindingContext) !== findAncestor(context.enclosingDeclaration, isDefaultBindingContext)))) {
35963622
return "default";
35973623
}
35983624
if (symbol.declarations && symbol.declarations.length) {

src/compiler/declarationEmitter.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ namespace ts {
358358
}
359359
else {
360360
errorNameNode = declaration.name;
361-
const format = TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.UseStructuralFallback | TypeFormatFlags.WriteDefaultSymbolWithoutName |
361+
const format = TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.UseStructuralFallback |
362362
TypeFormatFlags.WriteClassExpressionAsTypeLiteral |
363363
(shouldUseResolverType ? TypeFormatFlags.AddUndefined : 0);
364364
resolver.writeTypeOfDeclaration(declaration, enclosingDeclaration, format, writer);
@@ -378,7 +378,7 @@ namespace ts {
378378
resolver.writeReturnTypeOfSignatureDeclaration(
379379
signature,
380380
enclosingDeclaration,
381-
TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.UseStructuralFallback | TypeFormatFlags.WriteClassExpressionAsTypeLiteral | TypeFormatFlags.WriteDefaultSymbolWithoutName,
381+
TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.UseStructuralFallback | TypeFormatFlags.WriteClassExpressionAsTypeLiteral,
382382
writer);
383383
errorNameNode = undefined;
384384
}
@@ -643,7 +643,7 @@ namespace ts {
643643
resolver.writeTypeOfExpression(
644644
expr,
645645
enclosingDeclaration,
646-
TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.UseStructuralFallback | TypeFormatFlags.WriteClassExpressionAsTypeLiteral | TypeFormatFlags.WriteDefaultSymbolWithoutName,
646+
TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.UseStructuralFallback | TypeFormatFlags.WriteClassExpressionAsTypeLiteral,
647647
writer);
648648
write(";");
649649
writeLine();

src/compiler/types.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2937,7 +2937,7 @@ namespace ts {
29372937
// Options
29382938
NoTruncation = 1 << 0, // Don't truncate result
29392939
WriteArrayAsGenericType = 1 << 1, // Write Array<T> instead T[]
2940-
WriteDefaultSymbolWithoutName = 1 << 2, // Write `default`-named symbols as `default` instead of how they were written
2940+
// empty space
29412941
UseStructuralFallback = 1 << 3, // When an alias cannot be named by its symbol, rather than report an error, fallback to a structural printout if possible
29422942
// empty space
29432943
WriteTypeArgumentsOfSignature = 1 << 5, // Write the type arguments instead of type parameters of the signature
@@ -2965,14 +2965,15 @@ namespace ts {
29652965
// State
29662966
InObjectTypeLiteral = 1 << 22,
29672967
InTypeAlias = 1 << 23, // Writing type in type alias declaration
2968+
InInitialEntityName = 1 << 24, // Set when writing the LHS of an entity name or entity name expression
29682969
}
29692970

29702971
// Ensure the shared flags between this and `NodeBuilderFlags` stay in alignment
29712972
export const enum TypeFormatFlags {
29722973
None = 0,
29732974
NoTruncation = 1 << 0, // Don't truncate typeToString result
29742975
WriteArrayAsGenericType = 1 << 1, // Write Array<T> instead T[]
2975-
WriteDefaultSymbolWithoutName = 1 << 2, // Write all `defaut`-named symbols as `default` instead of their written name
2976+
// hole because there's a hole in node builder flags
29762977
UseStructuralFallback = 1 << 3, // When an alias cannot be named by its symbol, rather than report an error, fallback to a structural printout if possible
29772978
// hole because there's a hole in node builder flags
29782979
WriteTypeArgumentsOfSignature = 1 << 5, // Write the type arguments instead of type parameters of the signature
@@ -3003,7 +3004,7 @@ namespace ts {
30033004
/** @deprecated */ WriteOwnNameForAnyLike = 0, // Does nothing
30043005

30053006
NodeBuilderFlagsMask =
3006-
NoTruncation | WriteArrayAsGenericType | WriteDefaultSymbolWithoutName | UseStructuralFallback | WriteTypeArgumentsOfSignature |
3007+
NoTruncation | WriteArrayAsGenericType | UseStructuralFallback | WriteTypeArgumentsOfSignature |
30073008
UseFullyQualifiedType | SuppressAnyReturnType | MultilineObjectLiterals | WriteClassExpressionAsTypeLiteral |
30083009
UseTypeOfFunction | OmitParameterModifiers | UseAliasDefinedOutsideCurrentScope | AllowUniqueESSymbolType | InTypeAlias,
30093010
}
@@ -3024,6 +3025,9 @@ namespace ts {
30243025

30253026
// Build symbol name using any nodes needed, instead of just components of an entity name
30263027
AllowAnyNodeKind = 0x00000004,
3028+
3029+
// Prefer aliases which are not directly visible
3030+
UseAliasDefinedOutsideCurrentScope = 0x00000008,
30273031
}
30283032

30293033
/* @internal */

src/services/signatureHelp.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,7 @@ namespace ts.SignatureHelp {
353353
return children[indexOfOpenerToken + 1];
354354
}
355355

356+
const signatureHelpNodeBuilderFlags = NodeBuilderFlags.OmitParameterModifiers | NodeBuilderFlags.IgnoreErrors;
356357
function createSignatureHelpItems(candidates: Signature[], resolvedSignature: Signature, argumentListInfo: ArgumentListInfo, typeChecker: TypeChecker): SignatureHelpItems {
357358
const { argumentCount, argumentsSpan: applicableSpan, invocation, argumentIndex } = argumentListInfo;
358359
const isTypeParameterList = argumentListInfo.kind === ArgumentListKind.TypeArguments;
@@ -378,9 +379,8 @@ namespace ts.SignatureHelp {
378379
signatureHelpParameters = typeParameters && typeParameters.length > 0 ? map(typeParameters, createSignatureHelpParameterForTypeParameter) : emptyArray;
379380
suffixDisplayParts.push(punctuationPart(SyntaxKind.GreaterThanToken));
380381
const parameterParts = mapToDisplayParts(writer => {
381-
const flags = NodeBuilderFlags.OmitParameterModifiers | NodeBuilderFlags.IgnoreErrors;
382-
const thisParameter = candidateSignature.thisParameter ? [typeChecker.symbolToParameterDeclaration(candidateSignature.thisParameter, invocation, flags)] : [];
383-
const params = createNodeArray([...thisParameter, ...map(candidateSignature.parameters, param => typeChecker.symbolToParameterDeclaration(param, invocation, flags))]);
382+
const thisParameter = candidateSignature.thisParameter ? [typeChecker.symbolToParameterDeclaration(candidateSignature.thisParameter, invocation, signatureHelpNodeBuilderFlags)] : [];
383+
const params = createNodeArray([...thisParameter, ...map(candidateSignature.parameters, param => typeChecker.symbolToParameterDeclaration(param, invocation, signatureHelpNodeBuilderFlags))]);
384384
printer.writeList(ListFormat.CallExpressionArguments, params, getSourceFileOfNode(getParseTreeNode(invocation)), writer);
385385
});
386386
addRange(suffixDisplayParts, parameterParts);
@@ -435,7 +435,7 @@ namespace ts.SignatureHelp {
435435

436436
function createSignatureHelpParameterForParameter(parameter: Symbol): SignatureHelpParameter {
437437
const displayParts = mapToDisplayParts(writer => {
438-
const param = typeChecker.symbolToParameterDeclaration(parameter, invocation, NodeBuilderFlags.OmitParameterModifiers | NodeBuilderFlags.IgnoreErrors);
438+
const param = typeChecker.symbolToParameterDeclaration(parameter, invocation, signatureHelpNodeBuilderFlags);
439439
printer.writeNode(EmitHint.Unspecified, param, getSourceFileOfNode(getParseTreeNode(invocation)), writer);
440440
});
441441

src/services/utilities.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1300,7 +1300,7 @@ namespace ts {
13001300

13011301
export function symbolToDisplayParts(typeChecker: TypeChecker, symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags?: SymbolFormatFlags): SymbolDisplayPart[] {
13021302
return mapToDisplayParts(writer => {
1303-
typeChecker.writeSymbol(symbol, enclosingDeclaration, meaning, flags, writer);
1303+
typeChecker.writeSymbol(symbol, enclosingDeclaration, meaning, flags | SymbolFormatFlags.UseAliasDefinedOutsideCurrentScope, writer);
13041304
});
13051305
}
13061306

tests/baselines/reference/api/tsserverlibrary.d.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1799,7 +1799,6 @@ declare namespace ts {
17991799
None = 0,
18001800
NoTruncation = 1,
18011801
WriteArrayAsGenericType = 2,
1802-
WriteDefaultSymbolWithoutName = 4,
18031802
UseStructuralFallback = 8,
18041803
WriteTypeArgumentsOfSignature = 32,
18051804
UseFullyQualifiedType = 64,
@@ -1821,12 +1820,12 @@ declare namespace ts {
18211820
IgnoreErrors = 3112960,
18221821
InObjectTypeLiteral = 4194304,
18231822
InTypeAlias = 8388608,
1823+
InInitialEntityName = 16777216,
18241824
}
18251825
enum TypeFormatFlags {
18261826
None = 0,
18271827
NoTruncation = 1,
18281828
WriteArrayAsGenericType = 2,
1829-
WriteDefaultSymbolWithoutName = 4,
18301829
UseStructuralFallback = 8,
18311830
WriteTypeArgumentsOfSignature = 32,
18321831
UseFullyQualifiedType = 64,
@@ -1844,13 +1843,14 @@ declare namespace ts {
18441843
InFirstTypeArgument = 4194304,
18451844
InTypeAlias = 8388608,
18461845
/** @deprecated */ WriteOwnNameForAnyLike = 0,
1847-
NodeBuilderFlagsMask = 9469295,
1846+
NodeBuilderFlagsMask = 9469291,
18481847
}
18491848
enum SymbolFormatFlags {
18501849
None = 0,
18511850
WriteTypeParametersOrArguments = 1,
18521851
UseOnlyExternalAliasing = 2,
18531852
AllowAnyNodeKind = 4,
1853+
UseAliasDefinedOutsideCurrentScope = 8,
18541854
}
18551855
/**
18561856
* @deprecated

tests/baselines/reference/api/typescript.d.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1799,7 +1799,6 @@ declare namespace ts {
17991799
None = 0,
18001800
NoTruncation = 1,
18011801
WriteArrayAsGenericType = 2,
1802-
WriteDefaultSymbolWithoutName = 4,
18031802
UseStructuralFallback = 8,
18041803
WriteTypeArgumentsOfSignature = 32,
18051804
UseFullyQualifiedType = 64,
@@ -1821,12 +1820,12 @@ declare namespace ts {
18211820
IgnoreErrors = 3112960,
18221821
InObjectTypeLiteral = 4194304,
18231822
InTypeAlias = 8388608,
1823+
InInitialEntityName = 16777216,
18241824
}
18251825
enum TypeFormatFlags {
18261826
None = 0,
18271827
NoTruncation = 1,
18281828
WriteArrayAsGenericType = 2,
1829-
WriteDefaultSymbolWithoutName = 4,
18301829
UseStructuralFallback = 8,
18311830
WriteTypeArgumentsOfSignature = 32,
18321831
UseFullyQualifiedType = 64,
@@ -1844,13 +1843,14 @@ declare namespace ts {
18441843
InFirstTypeArgument = 4194304,
18451844
InTypeAlias = 8388608,
18461845
/** @deprecated */ WriteOwnNameForAnyLike = 0,
1847-
NodeBuilderFlagsMask = 9469295,
1846+
NodeBuilderFlagsMask = 9469291,
18481847
}
18491848
enum SymbolFormatFlags {
18501849
None = 0,
18511850
WriteTypeParametersOrArguments = 1,
18521851
UseOnlyExternalAliasing = 2,
18531852
AllowAnyNodeKind = 4,
1853+
UseAliasDefinedOutsideCurrentScope = 8,
18541854
}
18551855
/**
18561856
* @deprecated

tests/baselines/reference/declarationEmitTypeofDefaultExport.symbols

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import * as a from "./a";
77
>a : Symbol(a, Decl(b.ts, 0, 6))
88

99
export default a.default;
10-
>a.default : Symbol(a.C, Decl(a.ts, 0, 0))
10+
>a.default : Symbol(a.default, Decl(a.ts, 0, 0))
1111
>a : Symbol(a, Decl(b.ts, 0, 6))
12-
>default : Symbol(a.C, Decl(a.ts, 0, 0))
12+
>default : Symbol(a.default, Decl(a.ts, 0, 0))
1313

tests/baselines/reference/declarationEmitTypeofDefaultExport.types

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import * as a from "./a";
77
>a : typeof a
88

99
export default a.default;
10-
>a.default : typeof a.C
10+
>a.default : typeof a.default
1111
>a : typeof a
12-
>default : typeof a.C
12+
>default : typeof a.default
1313

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//// [tests/cases/compiler/defaultDeclarationEmitDefaultImport.ts] ////
2+
3+
//// [root.ts]
4+
export function getSomething(): Something { return null as any }
5+
export default class Something {}
6+
//// [main.ts]
7+
import Thing, { getSomething } from "./root";
8+
export const instance = getSomething();
9+
10+
11+
//// [root.js]
12+
"use strict";
13+
exports.__esModule = true;
14+
function getSomething() { return null; }
15+
exports.getSomething = getSomething;
16+
var Something = /** @class */ (function () {
17+
function Something() {
18+
}
19+
return Something;
20+
}());
21+
exports["default"] = Something;
22+
//// [main.js]
23+
"use strict";
24+
exports.__esModule = true;
25+
var root_1 = require("./root");
26+
exports.instance = root_1.getSomething();
27+
28+
29+
//// [root.d.ts]
30+
export declare function getSomething(): Something;
31+
export default class Something {
32+
}
33+
//// [main.d.ts]
34+
import Thing from "./root";
35+
export declare const instance: Thing;

0 commit comments

Comments
 (0)