Fixed issues with incomplete calls, cleaned some code up.

This commit is contained in:
Daniel Rosenwasser 2014-11-07 16:23:59 -08:00
parent 80b8062a01
commit 986a0b7343
19 changed files with 218 additions and 24 deletions

View File

@ -56,8 +56,6 @@ module ts {
return stringWriters.pop();
}
type CallLikeExpression = CallExpression | TaggedTemplateExpression;
/// fullTypeCheck denotes if this instance of the typechecker will be used to get semantic diagnostics.
/// If fullTypeCheck === true, then the typechecker should do every possible check to produce all errors
/// If fullTypeCheck === false, the typechecker can take shortcuts and skip checks that only produce errors.
@ -5204,20 +5202,30 @@ module ts {
function hasCorrectArity(node: CallLikeExpression, args: Expression[], signature: Signature) {
var adjustedArgCount: number;
var typeArguments: NodeArray<TypeNode>;
var callIsIncomplete = false;
var callIsIncomplete: boolean;
if (node.kind === SyntaxKind.TaggedTemplateExpression) {
var tagExpression = <TaggedTemplateExpression>node;
// Even if the call is incomplete, we'll have a missing expression as our last argument,
// so we can say the count is just the arg list length
adjustedArgCount = args.length;
typeArguments = undefined;
if (tagExpression.kind === SyntaxKind.TemplateExpression) {
if (tagExpression.template.kind === SyntaxKind.TemplateExpression) {
// If a tagged template expression lacks a tail literal, the call is incomplete.
var template = <TemplateExpression>tagExpression.template;
var lastSpan = lastOrUndefined(template.templateSpans);
// Specifically, a template only can end in a TemplateTail or a Missing literal.
var templateExpression = <TemplateExpression>tagExpression.template;
var lastSpan = lastOrUndefined(templateExpression.templateSpans);
Debug.assert(lastSpan !== undefined); // we should always have at least one span.
callIsIncomplete = lastSpan === undefined || lastSpan.literal.kind !== SyntaxKind.TemplateTail;
callIsIncomplete = lastSpan.literal.kind === SyntaxKind.Missing || isUnterminatedTemplateEnd(lastSpan.literal);
}
else {
// If the template didn't end in a backtick, or its beginning occurred right prior to EOF,
// then this might actually turn out to be a TemplateHead in the future;
// so we consider the call to be incomplete.
var templateLiteral = <LiteralExpression>tagExpression.template;
callIsIncomplete = isUnterminatedTemplateEnd(templateLiteral);
}
}
else {
@ -5228,17 +5236,17 @@ module ts {
return signature.minArgumentCount === 0;
}
else {
// For IDE scenarios we may have an incomplete call, so a trailing comma is tantamount to adding another argument.
adjustedArgCount = callExpression.arguments.hasTrailingComma ? args.length + 1 : args.length;
// For IDE scenarios we may have an incomplete call, so a trailing comma is tantamount to adding another argument.
adjustedArgCount = callExpression.arguments.hasTrailingComma ? args.length + 1 : args.length;
// If we are missing the close paren, the call is incomplete.
callIsIncomplete = (<CallExpression>callExpression).arguments.end === callExpression.end;
}
// If we are missing the close paren, the call is incomplete.
callIsIncomplete = (<CallExpression>callExpression).arguments.end === callExpression.end;
typeArguments = callExpression.typeArguments;
}
return checkArity(adjustedArgCount, typeArguments, callIsIncomplete, signature);
/**
@ -5420,7 +5428,9 @@ module ts {
}
function resolveCall(node: CallLikeExpression, signatures: Signature[], candidatesOutArray: Signature[]): Signature {
var typeArguments = (<CallExpression>node).typeArguments;
var isTaggedTemplate = node.kind === SyntaxKind.TaggedTemplateExpression;
var typeArguments = isTaggedTemplate ? undefined : (<CallExpression>node).typeArguments;
forEach(typeArguments, checkSourceElement);
var candidates = candidatesOutArray || [];
@ -5432,7 +5442,6 @@ module ts {
}
var args = getEffectiveCallArguments(node);
var isTaggedTemplate = node.kind === SyntaxKind.TaggedTemplateExpression;
// The following applies to any value of 'excludeArgument[i]':
// - true: the argument at 'i' is susceptible to a one-time permanent contextual typing.
@ -5440,8 +5449,8 @@ module ts {
// - false: the argument at 'i' *was* and *has been* permanently contextually typed.
//
// The idea is that we will perform type argument inference & assignability checking once
// without using the susceptible parameters, and once more for each susceptible parameter,
// contextually typing each as we go along.
// without using the susceptible parameters that are functions, and once more for each of those
// parameters, contextually typing each as we go along.
//
// For a tagged template, then the first argument be 'undefined' if necessary
// because it represents a TemplateStringsArray.
@ -5492,14 +5501,14 @@ module ts {
// is just important for choosing the best signature. So in the case where there is only one
// signature, the subtype pass is useless. So skipping it is an optimization.
if (candidates.length > 1) {
result = chooseOverload(candidates, subtypeRelation, excludeArgument);
result = chooseOverload(candidates, subtypeRelation);
}
if (!result) {
// Reinitialize these pointers for round two
candidateForArgumentError = undefined;
candidateForTypeArgumentError = undefined;
resultOfFailedInference = undefined;
result = chooseOverload(candidates, assignableRelation, excludeArgument);
result = chooseOverload(candidates, assignableRelation);
}
if (result) {
return result;
@ -5552,7 +5561,7 @@ module ts {
return resolveErrorCall(node);
function chooseOverload(candidates: Signature[], relation: Map<Ternary>, excludeArgument: boolean[]) {
function chooseOverload(candidates: Signature[], relation: Map<Ternary>) {
for (var i = 0; i < candidates.length; i++) {
if (!hasCorrectArity(node, args, candidates[i])) {
continue;
@ -5566,9 +5575,9 @@ module ts {
if (candidate.typeParameters) {
var typeArgumentTypes: Type[];
var typeArgumentsAreValid: boolean;
if ((<CallExpression>node).typeArguments) {
if (typeArguments) {
typeArgumentTypes = new Array<Type>(candidate.typeParameters.length);
typeArgumentsAreValid = checkTypeArguments(candidate, (<CallExpression>node).typeArguments, typeArgumentTypes, /*reportErrors*/ false)
typeArgumentsAreValid = checkTypeArguments(candidate, typeArguments, typeArgumentTypes, /*reportErrors*/ false)
}
else {
inferenceResult = inferTypeArguments(candidate, args, excludeArgument);
@ -5602,7 +5611,7 @@ module ts {
}
else {
candidateForTypeArgumentError = originalCandidate;
if (!(<CallExpression>node).typeArguments) {
if (!typeArguments) {
resultOfFailedInference = inferenceResult;
}
}

View File

@ -564,7 +564,6 @@ module ts {
return false;
}
export function isDeclaration(node: Node): boolean {
switch (node.kind) {
case SyntaxKind.TypeParameter:
@ -752,6 +751,20 @@ module ts {
return SyntaxKind.FirstTriviaToken <= token && token <= SyntaxKind.LastTriviaToken;
}
export function isUnterminatedTemplateEnd(node: LiteralExpression) {
Debug.assert(node.kind === SyntaxKind.NoSubstitutionTemplateLiteral || node.kind === SyntaxKind.TemplateTail);
var sourceText = getSourceFileOfNode(node).text;
// If we're not at the EOF, we know we must be terminated.
if (node.end !== sourceText.length) {
return false;
}
// If we didn't end in a backtick, we must still be in the middle of a template.
// If we did, make sure that it's not the *initial* backtick.
return sourceText.charCodeAt(node.end - 1) !== CharacterCodes.backtick || node.text.length === 0;
}
export function isModifier(token: SyntaxKind): boolean {
switch (token) {
case SyntaxKind.PublicKeyword:

View File

@ -445,6 +445,8 @@ module ts {
template: LiteralExpression | TemplateExpression;
}
export type CallLikeExpression = CallExpression | NewExpression | TaggedTemplateExpression;
export interface TypeAssertion extends Expression {
type: TypeNode;
operand: Expression;

View File

@ -0,0 +1,12 @@
tests/cases/compiler/taggedTemplatesWithIncompleteNoSubstitutionTemplate1.ts(6,15): error TS1126: Unexpected end of text.
==== tests/cases/compiler/taggedTemplatesWithIncompleteNoSubstitutionTemplate1.ts (1 errors) ====
function f(x: TemplateStringsArray, y: string, z: string) {
}
// Incomplete call, not enough parameters.
f `123qdawdrqw
!!! error TS1126: Unexpected end of text.

View File

@ -0,0 +1,12 @@
tests/cases/compiler/taggedTemplatesWithIncompleteNoSubstitutionTemplate2.ts(6,4): error TS1126: Unexpected end of text.
==== tests/cases/compiler/taggedTemplatesWithIncompleteNoSubstitutionTemplate2.ts (1 errors) ====
function f(x: TemplateStringsArray, y: string, z: string) {
}
// Incomplete call, not enough parameters, at EOF.
f `
!!! error TS1126: Unexpected end of text.

View File

@ -0,0 +1,12 @@
tests/cases/compiler/taggedTemplatesWithIncompleteTemplateExpressions1.ts(6,17): error TS1109: Expression expected.
==== tests/cases/compiler/taggedTemplatesWithIncompleteTemplateExpressions1.ts (1 errors) ====
function f(x: TemplateStringsArray, y: string, z: string) {
}
// Incomplete call, not enough parameters.
f `123qdawdrqw${
!!! error TS1109: Expression expected.

View File

@ -0,0 +1,15 @@
tests/cases/compiler/taggedTemplatesWithIncompleteTemplateExpressions2.ts(6,18): error TS1109: Expression expected.
tests/cases/compiler/taggedTemplatesWithIncompleteTemplateExpressions2.ts(6,21): error TS1109: Expression expected.
==== tests/cases/compiler/taggedTemplatesWithIncompleteTemplateExpressions2.ts (2 errors) ====
function f(x: TemplateStringsArray, y: string, z: string) {
}
// Incomplete call, enough parameters.
f `123qdawdrqw${ }${
~
!!! error TS1109: Expression expected.
!!! error TS1109: Expression expected.

View File

@ -0,0 +1,15 @@
tests/cases/compiler/taggedTemplatesWithIncompleteTemplateExpressions3.ts(6,23): error TS1109: Expression expected.
tests/cases/compiler/taggedTemplatesWithIncompleteTemplateExpressions3.ts(6,18): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.
==== tests/cases/compiler/taggedTemplatesWithIncompleteTemplateExpressions3.ts (2 errors) ====
function f(x: TemplateStringsArray, y: string, z: string) {
}
// Incomplete call, not enough parameters.
f `123qdawdrqw${ 1 }${
!!! error TS1109: Expression expected.
~
!!! error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.

View File

@ -0,0 +1,18 @@
tests/cases/compiler/taggedTemplatesWithIncompleteTemplateExpressions4.ts(6,24): error TS1109: Expression expected.
tests/cases/compiler/taggedTemplatesWithIncompleteTemplateExpressions4.ts(6,28): error TS1109: Expression expected.
tests/cases/compiler/taggedTemplatesWithIncompleteTemplateExpressions4.ts(6,1): error TS2346: Supplied parameters do not match any signature of call target.
==== tests/cases/compiler/taggedTemplatesWithIncompleteTemplateExpressions4.ts (3 errors) ====
function f(x: TemplateStringsArray, y: string, z: string) {
}
// Incomplete call, but too many parameters.
f `123qdawdrqw${ 1 }${ }${
~
!!! error TS1109: Expression expected.
!!! error TS1109: Expression expected.
~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2346: Supplied parameters do not match any signature of call target.

View File

@ -0,0 +1,15 @@
tests/cases/compiler/taggedTemplatesWithIncompleteTemplateExpressions5.ts(6,30): error TS1109: Expression expected.
tests/cases/compiler/taggedTemplatesWithIncompleteTemplateExpressions5.ts(6,1): error TS2346: Supplied parameters do not match any signature of call target.
==== tests/cases/compiler/taggedTemplatesWithIncompleteTemplateExpressions5.ts (2 errors) ====
function f(x: TemplateStringsArray, y: string, z: string) {
}
// Incomplete call, but too many parameters.
f `123qdawdrqw${ 1 }${ 2 }${
!!! error TS1109: Expression expected.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2346: Supplied parameters do not match any signature of call target.

View File

@ -0,0 +1,15 @@
tests/cases/compiler/taggedTemplatesWithIncompleteTemplateExpressions6.ts(6,23): error TS1109: Expression expected.
tests/cases/compiler/taggedTemplatesWithIncompleteTemplateExpressions6.ts(6,18): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.
==== tests/cases/compiler/taggedTemplatesWithIncompleteTemplateExpressions6.ts (2 errors) ====
function f(x: TemplateStringsArray, y: string, z: string) {
}
// Incomplete call, not enough parameters, at EOF.
f `123qdawdrqw${ 1 }${
!!! error TS1109: Expression expected.
~
!!! error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.

View File

@ -0,0 +1,7 @@
// @target: es6
function f(x: TemplateStringsArray, y: string, z: string) {
}
// Incomplete call, not enough parameters.
f `123qdawdrqw

View File

@ -0,0 +1,7 @@
// @target: es6
function f(x: TemplateStringsArray, y: string, z: string) {
}
// Incomplete call, not enough parameters, at EOF.
f `

View File

@ -0,0 +1,7 @@
// @target: es6
function f(x: TemplateStringsArray, y: string, z: string) {
}
// Incomplete call, not enough parameters.
f `123qdawdrqw${

View File

@ -0,0 +1,7 @@
// @target: es6
function f(x: TemplateStringsArray, y: string, z: string) {
}
// Incomplete call, enough parameters.
f `123qdawdrqw${ }${

View File

@ -0,0 +1,7 @@
// @target: es6
function f(x: TemplateStringsArray, y: string, z: string) {
}
// Incomplete call, not enough parameters.
f `123qdawdrqw${ 1 }${

View File

@ -0,0 +1,7 @@
// @target: es6
function f(x: TemplateStringsArray, y: string, z: string) {
}
// Incomplete call, but too many parameters.
f `123qdawdrqw${ 1 }${ }${

View File

@ -0,0 +1,7 @@
// @target: es6
function f(x: TemplateStringsArray, y: string, z: string) {
}
// Incomplete call, but too many parameters.
f `123qdawdrqw${ 1 }${ 2 }${

View File

@ -0,0 +1,7 @@
// @target: es6
function f(x: TemplateStringsArray, y: string, z: string) {
}
// Incomplete call, not enough parameters, at EOF.
f `123qdawdrqw${ 1 }${