Skip to content

Commit d5b2438

Browse files
committed
Merge branch 'master' into make-lib-symbols-unique
2 parents 77d654c + 2d9b30d commit d5b2438

28 files changed

+614
-125
lines changed

src/compiler/binder.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ namespace ts {
236236
if (symbolFlags & SymbolFlags.Value) {
237237
const { valueDeclaration } = symbol;
238238
if (!valueDeclaration ||
239-
(valueDeclaration.kind !== node.kind && valueDeclaration.kind === SyntaxKind.ModuleDeclaration)) {
239+
(valueDeclaration.kind !== node.kind && isEffectiveModuleDeclaration(valueDeclaration))) {
240240
// other kinds of value declarations take precedence over modules
241241
symbol.valueDeclaration = node;
242242
}

src/compiler/checker.ts

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -922,7 +922,7 @@ namespace ts {
922922
target.flags |= source.flags;
923923
if (source.valueDeclaration &&
924924
(!target.valueDeclaration ||
925-
(target.valueDeclaration.kind === SyntaxKind.ModuleDeclaration && source.valueDeclaration.kind !== SyntaxKind.ModuleDeclaration))) {
925+
isEffectiveModuleDeclaration(target.valueDeclaration) && !isEffectiveModuleDeclaration(source.valueDeclaration))) {
926926
// other kinds of value declarations take precedence over modules
927927
target.valueDeclaration = source.valueDeclaration;
928928
}
@@ -12181,6 +12181,19 @@ namespace ts {
1218112181
}
1218212182

1218312183
function getWidenedProperty(prop: Symbol, context: WideningContext | undefined): Symbol {
12184+
if (!(prop.flags & SymbolFlags.Property)) {
12185+
// Since get accessors already widen their return value there is no need to
12186+
// widen accessor based properties here.
12187+
return prop;
12188+
}
12189+
if (prop.flags & SymbolFlags.JSContainer) {
12190+
const node = prop.declarations && first(prop.declarations);
12191+
const init = getAssignedJavascriptInitializer(node);
12192+
if (init && init.kind !== SyntaxKind.ObjectLiteralExpression) {
12193+
// for JS special declarations, the only kind of initializer that will widen is object literals
12194+
return prop;
12195+
}
12196+
}
1218412197
const original = getTypeOfSymbol(prop);
1218512198
const propContext = context && createWideningContext(context, prop.escapedName, /*siblings*/ undefined);
1218612199
const widened = getWidenedTypeWithContext(original, propContext);
@@ -12201,9 +12214,7 @@ namespace ts {
1220112214
function getWidenedTypeOfObjectLiteral(type: Type, context: WideningContext | undefined): Type {
1220212215
const members = createSymbolTable();
1220312216
for (const prop of getPropertiesOfObjectType(type)) {
12204-
// Since get accessors already widen their return value there is no need to
12205-
// widen accessor based properties here.
12206-
members.set(prop.escapedName, prop.flags & SymbolFlags.Property ? getWidenedProperty(prop, context) : prop);
12217+
members.set(prop.escapedName, getWidenedProperty(prop, context));
1220712218
}
1220812219
if (context) {
1220912220
for (const prop of getPropertiesOfContext(context)) {
@@ -15992,10 +16003,10 @@ namespace ts {
1599216003
const decl = getDeclarationOfJSInitializer(node);
1599316004
if (decl) {
1599416005
// a JS object literal whose declaration's symbol has exports is a JS namespace
15995-
const symbol = getMergedSymbol(decl.symbol);
16006+
const symbol = getSymbolOfNode(decl);
1599616007
if (symbol && hasEntries(symbol.exports)) {
1599716008
propertiesTable = symbol.exports;
15998-
symbol.exports.forEach(symbol => propertiesArray.push(getMergedSymbol(symbol)));
16009+
symbol.exports.forEach(s => propertiesArray.push(getMergedSymbol(s)));
1599916010
return createObjectLiteralType();
1600016011
}
1600116012
}
@@ -20008,7 +20019,6 @@ namespace ts {
2000820019

2000920020
function checkObjectLiteralAssignment(node: ObjectLiteralExpression, sourceType: Type): Type {
2001020021
const properties = node.properties;
20011-
checkGrammarForDisallowedTrailingComma(properties, Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma);
2001220022
if (strictNullChecks && properties.length === 0) {
2001320023
return checkNonNullType(sourceType, node);
2001420024
}
@@ -20019,7 +20029,7 @@ namespace ts {
2001920029
}
2002020030

2002120031
/** Note: If property cannot be a SpreadAssignment, then allProperties does not need to be provided */
20022-
function checkObjectLiteralDestructuringPropertyAssignment(objectLiteralType: Type, property: ObjectLiteralElementLike, allProperties?: ReadonlyArray<ObjectLiteralElementLike>) {
20032+
function checkObjectLiteralDestructuringPropertyAssignment(objectLiteralType: Type, property: ObjectLiteralElementLike, allProperties?: NodeArray<ObjectLiteralElementLike>) {
2002320033
if (property.kind === SyntaxKind.PropertyAssignment || property.kind === SyntaxKind.ShorthandPropertyAssignment) {
2002420034
const name = property.name;
2002520035
if (name.kind === SyntaxKind.ComputedPropertyName) {
@@ -20059,6 +20069,7 @@ namespace ts {
2005920069
}
2006020070
}
2006120071
const type = getRestType(objectLiteralType, nonRestNames, objectLiteralType.symbol);
20072+
checkGrammarForDisallowedTrailingComma(allProperties, Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma);
2006220073
return checkDestructuringAssignment(property.expression, type);
2006320074
}
2006420075
else {
@@ -20068,7 +20079,6 @@ namespace ts {
2006820079

2006920080
function checkArrayLiteralAssignment(node: ArrayLiteralExpression, sourceType: Type, checkMode?: CheckMode): Type {
2007020081
const elements = node.elements;
20071-
checkGrammarForDisallowedTrailingComma(elements, Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma);
2007220082
if (languageVersion < ScriptTarget.ES2015 && compilerOptions.downlevelIteration) {
2007320083
checkExternalEmitHelpers(node, ExternalEmitHelpers.Read);
2007420084
}
@@ -20120,6 +20130,7 @@ namespace ts {
2012020130
error((<BinaryExpression>restExpression).operatorToken, Diagnostics.A_rest_element_cannot_have_an_initializer);
2012120131
}
2012220132
else {
20133+
checkGrammarForDisallowedTrailingComma(node.elements, Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma);
2012320134
return checkDestructuringAssignment(restExpression, createArrayType(elementType), checkMode);
2012420135
}
2012520136
}

src/compiler/parser.ts

Lines changed: 45 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -6486,54 +6486,42 @@ namespace ts {
64866486

64876487
const tagName = parseJSDocIdentifierName();
64886488
skipWhitespace();
6489-
if (!tagName) {
6490-
return;
6491-
}
64926489

64936490
let tag: JSDocTag | undefined;
6494-
if (tagName) {
6495-
switch (tagName.escapedText) {
6496-
case "augments":
6497-
case "extends":
6498-
tag = parseAugmentsTag(atToken, tagName);
6499-
break;
6500-
case "class":
6501-
case "constructor":
6502-
tag = parseClassTag(atToken, tagName);
6503-
break;
6504-
case "arg":
6505-
case "argument":
6506-
case "param":
6507-
return parseParameterOrPropertyTag(atToken, tagName, PropertyLikeParse.Parameter, indent);
6508-
case "return":
6509-
case "returns":
6510-
tag = parseReturnTag(atToken, tagName);
6511-
break;
6512-
case "template":
6513-
tag = parseTemplateTag(atToken, tagName);
6514-
break;
6515-
case "type":
6516-
tag = parseTypeTag(atToken, tagName);
6517-
break;
6518-
case "typedef":
6519-
tag = parseTypedefTag(atToken, tagName, indent);
6520-
break;
6521-
case "callback":
6522-
tag = parseCallbackTag(atToken, tagName, indent);
6523-
break;
6524-
default:
6525-
tag = parseUnknownTag(atToken, tagName);
6526-
break;
6527-
}
6528-
}
6529-
else {
6530-
tag = parseUnknownTag(atToken, tagName);
6491+
switch (tagName.escapedText) {
6492+
case "augments":
6493+
case "extends":
6494+
tag = parseAugmentsTag(atToken, tagName);
6495+
break;
6496+
case "class":
6497+
case "constructor":
6498+
tag = parseClassTag(atToken, tagName);
6499+
break;
6500+
case "arg":
6501+
case "argument":
6502+
case "param":
6503+
return parseParameterOrPropertyTag(atToken, tagName, PropertyLikeParse.Parameter, indent);
6504+
case "return":
6505+
case "returns":
6506+
tag = parseReturnTag(atToken, tagName);
6507+
break;
6508+
case "template":
6509+
tag = parseTemplateTag(atToken, tagName);
6510+
break;
6511+
case "type":
6512+
tag = parseTypeTag(atToken, tagName);
6513+
break;
6514+
case "typedef":
6515+
tag = parseTypedefTag(atToken, tagName, indent);
6516+
break;
6517+
case "callback":
6518+
tag = parseCallbackTag(atToken, tagName, indent);
6519+
break;
6520+
default:
6521+
tag = parseUnknownTag(atToken, tagName);
6522+
break;
65316523
}
65326524

6533-
if (!tag) {
6534-
// a badly malformed tag should not be added to the list of tags
6535-
return;
6536-
}
65376525
if (!tag.comment) {
65386526
// some tags, like typedef and callback, have already parsed their comments earlier
65396527
tag.comment = parseTagComments(indent + tag.end - tag.pos);
@@ -6763,11 +6751,11 @@ namespace ts {
67636751
}
67646752

67656753
function parsePropertyAccessEntityNameExpression() {
6766-
let node: Identifier | PropertyAccessEntityNameExpression = parseJSDocIdentifierName(/*createIfMissing*/ true);
6754+
let node: Identifier | PropertyAccessEntityNameExpression = parseJSDocIdentifierName();
67676755
while (parseOptional(SyntaxKind.DotToken)) {
67686756
const prop: PropertyAccessEntityNameExpression = createNode(SyntaxKind.PropertyAccessExpression, node.pos) as PropertyAccessEntityNameExpression;
67696757
prop.expression = node;
6770-
prop.name = parseJSDocIdentifierName()!; // TODO: GH#18217
6758+
prop.name = parseJSDocIdentifierName();
67716759
node = finishNode(prop);
67726760
}
67736761
return node;
@@ -6832,9 +6820,11 @@ namespace ts {
68326820

68336821
function parseJSDocTypeNameWithNamespace(nested?: boolean) {
68346822
const pos = scanner.getTokenPos();
6823+
if (!tokenIsIdentifierOrKeyword(token())) {
6824+
return undefined;
6825+
}
68356826
const typeNameOrNamespaceName = parseJSDocIdentifierName();
6836-
6837-
if (typeNameOrNamespaceName && parseOptional(SyntaxKind.DotToken)) {
6827+
if (parseOptional(SyntaxKind.DotToken)) {
68386828
const jsDocNamespaceNode = <JSDocNamespaceDeclaration>createNode(SyntaxKind.ModuleDeclaration, pos);
68396829
if (nested) {
68406830
jsDocNamespaceNode.flags |= NodeFlags.NestedNamespace;
@@ -6844,7 +6834,7 @@ namespace ts {
68446834
return finishNode(jsDocNamespaceNode);
68456835
}
68466836

6847-
if (typeNameOrNamespaceName && nested) {
6837+
if (nested) {
68486838
typeNameOrNamespaceName.isInJSDocNamespace = true;
68496839
}
68506840
return typeNameOrNamespaceName;
@@ -6954,9 +6944,6 @@ namespace ts {
69546944

69556945
const tagName = parseJSDocIdentifierName();
69566946
skipWhitespace();
6957-
if (!tagName) {
6958-
return false;
6959-
}
69606947
let t: PropertyLikeParse;
69616948
switch (tagName.escapedText) {
69626949
case "type":
@@ -6981,7 +6968,7 @@ namespace ts {
69816968
return tag;
69826969
}
69836970

6984-
function parseTemplateTag(atToken: AtToken, tagName: Identifier): JSDocTemplateTag | undefined {
6971+
function parseTemplateTag(atToken: AtToken, tagName: Identifier): JSDocTemplateTag {
69856972
// the template tag looks like '@template {Constraint} T,U,V'
69866973
let constraint: JSDocTypeExpression | undefined;
69876974
if (token() === SyntaxKind.OpenBraceToken) {
@@ -6993,11 +6980,7 @@ namespace ts {
69936980
do {
69946981
skipWhitespace();
69956982
const typeParameter = <TypeParameterDeclaration>createNode(SyntaxKind.TypeParameter);
6996-
if (!tokenIsIdentifierOrKeyword(token())) {
6997-
parseErrorAtCurrentToken(Diagnostics.Unexpected_token_A_type_parameter_name_was_expected_without_curly_braces);
6998-
return undefined;
6999-
}
7000-
typeParameter.name = parseJSDocIdentifierName()!;
6983+
typeParameter.name = parseJSDocIdentifierName(Diagnostics.Unexpected_token_A_type_parameter_name_was_expected_without_curly_braces);
70016984
skipWhitespace();
70026985
finishNode(typeParameter);
70036986
typeParameters.push(typeParameter);
@@ -7028,15 +7011,15 @@ namespace ts {
70287011
}
70297012

70307013
function parseJSDocEntityName(): EntityName {
7031-
let entity: EntityName = parseJSDocIdentifierName(/*createIfMissing*/ true);
7014+
let entity: EntityName = parseJSDocIdentifierName();
70327015
if (parseOptional(SyntaxKind.OpenBracketToken)) {
70337016
parseExpected(SyntaxKind.CloseBracketToken);
70347017
// Note that y[] is accepted as an entity name, but the postfix brackets are not saved for checking.
70357018
// Technically usejsdoc.org requires them for specifying a property of a type equivalent to Array<{ x: ...}>
70367019
// but it's not worth it to enforce that restriction.
70377020
}
70387021
while (parseOptional(SyntaxKind.DotToken)) {
7039-
const name = parseJSDocIdentifierName(/*createIfMissing*/ true);
7022+
const name = parseJSDocIdentifierName();
70407023
if (parseOptional(SyntaxKind.OpenBracketToken)) {
70417024
parseExpected(SyntaxKind.CloseBracketToken);
70427025
}
@@ -7045,17 +7028,9 @@ namespace ts {
70457028
return entity;
70467029
}
70477030

7048-
function parseJSDocIdentifierName(): Identifier | undefined;
7049-
function parseJSDocIdentifierName(createIfMissing: true): Identifier;
7050-
function parseJSDocIdentifierName(createIfMissing = false): Identifier | undefined {
7031+
function parseJSDocIdentifierName(message?: DiagnosticMessage): Identifier {
70517032
if (!tokenIsIdentifierOrKeyword(token())) {
7052-
if (createIfMissing) {
7053-
return createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Identifier_expected);
7054-
}
7055-
else {
7056-
parseErrorAtCurrentToken(Diagnostics.Identifier_expected);
7057-
return undefined;
7058-
}
7033+
return createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ !message, message || Diagnostics.Identifier_expected);
70597034
}
70607035

70617036
const pos = scanner.getTokenPos();

src/compiler/utilities.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,16 @@ namespace ts {
451451
return isModuleDeclaration(node) && isStringLiteral(node.name);
452452
}
453453

454+
/**
455+
* An effective module (namespace) declaration is either
456+
* 1. An actual declaration: namespace X { ... }
457+
* 2. A Javascript declaration, which is:
458+
* An identifier in a nested property access expression: Y in `X.Y.Z = { ... }`
459+
*/
460+
export function isEffectiveModuleDeclaration(node: Node) {
461+
return isModuleDeclaration(node) || isIdentifier(node);
462+
}
463+
454464
/** Given a symbol for a module, checks that it is a shorthand ambient module. */
455465
export function isShorthandAmbientModuleSymbol(moduleSymbol: Symbol): boolean {
456466
return isShorthandAmbientModule(moduleSymbol.valueDeclaration);

src/harness/evaluator.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,12 @@ namespace evaluator {
66
function compile(sourceText: string, options?: ts.CompilerOptions) {
77
const fs = vfs.createFromFileSystem(Harness.IO, /*ignoreCase*/ false);
88
fs.writeFileSync(sourceFile, sourceText);
9-
const compilerOptions: ts.CompilerOptions = { target: ts.ScriptTarget.ES5, module: ts.ModuleKind.CommonJS, lib: ["lib.esnext.d.ts"], ...options };
9+
const compilerOptions: ts.CompilerOptions = {
10+
target: ts.ScriptTarget.ES5,
11+
module: ts.ModuleKind.CommonJS,
12+
lib: ["lib.esnext.d.ts", "lib.dom.d.ts"],
13+
...options
14+
};
1015
const host = new fakes.CompilerHost(fs, compilerOptions);
1116
return compiler.compileFiles(host, [sourceFile], compilerOptions);
1217
}
@@ -30,6 +35,14 @@ namespace evaluator {
3035
function evaluate(result: compiler.CompilationResult, globals?: Record<string, any>) {
3136
globals = { Symbol: FakeSymbol, ...globals };
3237

38+
if (ts.some(result.diagnostics)) {
39+
assert.ok(/*value*/ false, "Syntax error in evaluation source text:\n" + ts.formatDiagnostics(result.diagnostics, {
40+
getCanonicalFileName: file => file,
41+
getCurrentDirectory: () => "",
42+
getNewLine: () => "\n"
43+
}));
44+
}
45+
3346
const output = result.getOutput(sourceFile, "js")!;
3447
assert.isDefined(output);
3548

0 commit comments

Comments
 (0)