Skip to content

Commit db89584

Browse files
Put semantically relevant tokens in the tree.
1 parent 8ad4a0a commit db89584

25 files changed

Lines changed: 175 additions & 151 deletions

src/compiler/checker.ts

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -756,7 +756,7 @@ module ts {
756756
//
757757
// x is an optional parameter, but it is a required property.
758758
return propertySymbol.valueDeclaration &&
759-
propertySymbol.valueDeclaration.flags & NodeFlags.QuestionMark &&
759+
hasQuestionToken(propertySymbol.valueDeclaration) &&
760760
propertySymbol.valueDeclaration.kind !== SyntaxKind.Parameter;
761761
}
762762

@@ -1441,7 +1441,7 @@ module ts {
14411441
writePunctuation(writer, SyntaxKind.DotDotDotToken);
14421442
}
14431443
appendSymbolNameOnly(p, writer);
1444-
if (p.valueDeclaration.flags & NodeFlags.QuestionMark || (<VariableDeclaration>p.valueDeclaration).initializer) {
1444+
if (hasQuestionToken(p.valueDeclaration) || (<VariableDeclaration>p.valueDeclaration).initializer) {
14451445
writePunctuation(writer, SyntaxKind.QuestionToken);
14461446
}
14471447
writePunctuation(writer, SyntaxKind.ColonToken);
@@ -2527,7 +2527,7 @@ module ts {
25272527
hasStringLiterals = true;
25282528
}
25292529
if (minArgumentCount < 0) {
2530-
if (param.initializer || param.flags & NodeFlags.QuestionMark || param.dotDotDotToken) {
2530+
if (param.initializer || param.questionToken || param.dotDotDotToken) {
25312531
minArgumentCount = i;
25322532
}
25332533
}
@@ -7020,20 +7020,23 @@ module ts {
70207020
return;
70217021
}
70227022

7023+
function getCanonicalOverload(overloads: Declaration[], implementation: FunctionLikeDeclaration) {
7024+
// Consider the canonical set of flags to be the flags of the bodyDeclaration or the first declaration
7025+
// Error on all deviations from this canonical set of flags
7026+
// The caveat is that if some overloads are defined in lib.d.ts, we don't want to
7027+
// report the errors on those. To achieve this, we will say that the implementation is
7028+
// the canonical signature only if it is in the same container as the first overload
7029+
var implementationSharesContainerWithFirstOverload = implementation !== undefined && implementation.parent === overloads[0].parent;
7030+
return implementationSharesContainerWithFirstOverload ? implementation : overloads[0];
7031+
}
7032+
70237033
function checkFlagAgreementBetweenOverloads(overloads: Declaration[], implementation: FunctionLikeDeclaration, flagsToCheck: NodeFlags, someOverloadFlags: NodeFlags, allOverloadFlags: NodeFlags): void {
70247034
// Error if some overloads have a flag that is not shared by all overloads. To find the
70257035
// deviations, we XOR someOverloadFlags with allOverloadFlags
70267036
var someButNotAllOverloadFlags = someOverloadFlags ^ allOverloadFlags;
70277037
if (someButNotAllOverloadFlags !== 0) {
7028-
// Consider the canonical set of flags to be the flags of the bodyDeclaration or the first declaration
7029-
// Error on all deviations from this canonical set of flags
7030-
// The caveat is that if some overloads are defined in lib.d.ts, we don't want to
7031-
// report the errors on those. To achieve this, we will say that the implementation is
7032-
// the canonical signature only if it is in the same container as the first overload
7033-
var implementationSharesContainerWithFirstOverload = implementation !== undefined && implementation.parent === overloads[0].parent;
7034-
var canonicalFlags = implementationSharesContainerWithFirstOverload
7035-
? getEffectiveDeclarationFlags(implementation, flagsToCheck)
7036-
: getEffectiveDeclarationFlags(overloads[0], flagsToCheck);
7038+
var canonicalFlags = getEffectiveDeclarationFlags(getCanonicalOverload(overloads, implementation), flagsToCheck);
7039+
70377040
forEach(overloads, o => {
70387041
var deviation = getEffectiveDeclarationFlags(o, flagsToCheck) ^ canonicalFlags;
70397042
if (deviation & NodeFlags.Export) {
@@ -7045,16 +7048,27 @@ module ts {
70457048
else if (deviation & (NodeFlags.Private | NodeFlags.Protected)) {
70467049
error(o.name, Diagnostics.Overload_signatures_must_all_be_public_private_or_protected);
70477050
}
7048-
else if (deviation & NodeFlags.QuestionMark) {
7051+
});
7052+
}
7053+
}
7054+
7055+
function checkQuestionTokenAgreementBetweenOverloads(overloads: Declaration[], implementation: FunctionLikeDeclaration, someHaveQuestionToken: boolean, allHaveQuestionToken: boolean): void {
7056+
if (someHaveQuestionToken !== allHaveQuestionToken) {
7057+
var canonicalHasQuestionToken = hasQuestionToken(getCanonicalOverload(overloads, implementation));
7058+
forEach(overloads, o => {
7059+
var deviation = hasQuestionToken(o) !== canonicalHasQuestionToken;
7060+
if (deviation) {
70497061
error(o.name, Diagnostics.Overload_signatures_must_all_be_optional_or_required);
70507062
}
70517063
});
70527064
}
70537065
}
70547066

7055-
var flagsToCheck: NodeFlags = NodeFlags.Export | NodeFlags.Ambient | NodeFlags.Private | NodeFlags.Protected | NodeFlags.QuestionMark;
7067+
var flagsToCheck: NodeFlags = NodeFlags.Export | NodeFlags.Ambient | NodeFlags.Private | NodeFlags.Protected;
70567068
var someNodeFlags: NodeFlags = 0;
70577069
var allNodeFlags = flagsToCheck;
7070+
var someHaveQuestionToken = false;
7071+
var allHaveQuestionToken = true;
70587072
var hasOverloads = false;
70597073
var bodyDeclaration: FunctionLikeDeclaration;
70607074
var lastSeenNonAmbientDeclaration: FunctionLikeDeclaration;
@@ -7128,6 +7142,8 @@ module ts {
71287142
var currentNodeFlags = getEffectiveDeclarationFlags(node, flagsToCheck);
71297143
someNodeFlags |= currentNodeFlags;
71307144
allNodeFlags &= currentNodeFlags;
7145+
someHaveQuestionToken = someHaveQuestionToken || hasQuestionToken(node);
7146+
allHaveQuestionToken = allHaveQuestionToken && hasQuestionToken(node);
71317147

71327148
if (node.body && bodyDeclaration) {
71337149
if (isConstructor) {
@@ -7176,6 +7192,8 @@ module ts {
71767192

71777193
if (hasOverloads) {
71787194
checkFlagAgreementBetweenOverloads(declarations, bodyDeclaration, flagsToCheck, someNodeFlags, allNodeFlags);
7195+
checkQuestionTokenAgreementBetweenOverloads(declarations, bodyDeclaration, someHaveQuestionToken, allHaveQuestionToken);
7196+
71797197
if (bodyDeclaration) {
71807198
var signatures = getSignaturesOfSymbol(symbol);
71817199
var bodySignature = getSignatureFromDeclaration(bodyDeclaration);

src/compiler/emitter.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -943,7 +943,7 @@ module ts {
943943
if (node.kind !== SyntaxKind.VariableDeclaration || resolver.isDeclarationVisible(node)) {
944944
writeTextOfNode(currentSourceFile, node.name);
945945
// If optional property emit ?
946-
if (node.kind === SyntaxKind.Property && (node.flags & NodeFlags.QuestionMark)) {
946+
if (node.kind === SyntaxKind.Property && hasQuestionToken(node)) {
947947
write("?");
948948
}
949949
if (node.kind === SyntaxKind.Property && node.parent.kind === SyntaxKind.TypeLiteral) {
@@ -1124,7 +1124,7 @@ module ts {
11241124
}
11251125
else {
11261126
writeTextOfNode(currentSourceFile, node.name);
1127-
if (node.flags & NodeFlags.QuestionMark) {
1127+
if (hasQuestionToken(node)) {
11281128
write("?");
11291129
}
11301130
}
@@ -1256,7 +1256,7 @@ module ts {
12561256
write("...");
12571257
}
12581258
writeTextOfNode(currentSourceFile, node.name);
1259-
if (node.initializer || (node.flags & NodeFlags.QuestionMark)) {
1259+
if (node.initializer || hasQuestionToken(node)) {
12601260
write("?");
12611261
}
12621262
decreaseIndent();

0 commit comments

Comments
 (0)