mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-30 01:04:49 -05:00
Merge pull request #1931 from Microsoft/spreadCall
Support spread operator in call expressions
This commit is contained in:
@@ -5822,10 +5822,74 @@ module ts {
|
||||
return unknownSignature;
|
||||
}
|
||||
|
||||
// Re-order candidate signatures into the result array. Assumes the result array to be empty.
|
||||
// The candidate list orders groups in reverse, but within a group signatures are kept in declaration order
|
||||
// A nit here is that we reorder only signatures that belong to the same symbol,
|
||||
// so order how inherited signatures are processed is still preserved.
|
||||
// interface A { (x: string): void }
|
||||
// interface B extends A { (x: 'foo'): string }
|
||||
// var b: B;
|
||||
// b('foo') // <- here overloads should be processed as [(x:'foo'): string, (x: string): void]
|
||||
function reorderCandidates(signatures: Signature[], result: Signature[]): void {
|
||||
var lastParent: Node;
|
||||
var lastSymbol: Symbol;
|
||||
var cutoffIndex: number = 0;
|
||||
var index: number;
|
||||
var specializedIndex: number = -1;
|
||||
var spliceIndex: number;
|
||||
Debug.assert(!result.length);
|
||||
for (var i = 0; i < signatures.length; i++) {
|
||||
var signature = signatures[i];
|
||||
var symbol = signature.declaration && getSymbolOfNode(signature.declaration);
|
||||
var parent = signature.declaration && signature.declaration.parent;
|
||||
if (!lastSymbol || symbol === lastSymbol) {
|
||||
if (lastParent && parent === lastParent) {
|
||||
index++;
|
||||
}
|
||||
else {
|
||||
lastParent = parent;
|
||||
index = cutoffIndex;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// current declaration belongs to a different symbol
|
||||
// set cutoffIndex so re-orderings in the future won't change result set from 0 to cutoffIndex
|
||||
index = cutoffIndex = result.length;
|
||||
lastParent = parent;
|
||||
}
|
||||
lastSymbol = symbol;
|
||||
|
||||
// specialized signatures always need to be placed before non-specialized signatures regardless
|
||||
// of the cutoff position; see GH#1133
|
||||
if (signature.hasStringLiterals) {
|
||||
specializedIndex++;
|
||||
spliceIndex = specializedIndex;
|
||||
// The cutoff index always needs to be greater than or equal to the specialized signature index
|
||||
// in order to prevent non-specialized signatures from being added before a specialized
|
||||
// signature.
|
||||
cutoffIndex++;
|
||||
}
|
||||
else {
|
||||
spliceIndex = index;
|
||||
}
|
||||
|
||||
result.splice(spliceIndex, 0, signature);
|
||||
}
|
||||
}
|
||||
|
||||
function getSpreadArgumentIndex(args: Expression[]): number {
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
if (args[i].kind === SyntaxKind.SpreadElementExpression) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
function hasCorrectArity(node: CallLikeExpression, args: Expression[], signature: Signature) {
|
||||
var adjustedArgCount: number;
|
||||
var typeArguments: NodeArray<TypeNode>;
|
||||
var callIsIncomplete: boolean;
|
||||
var adjustedArgCount: number; // Apparent number of arguments we will have in this call
|
||||
var typeArguments: NodeArray<TypeNode>; // Type arguments (undefined if none)
|
||||
var callIsIncomplete: boolean; // In incomplete call we want to be lenient when we have too few arguments
|
||||
|
||||
if (node.kind === SyntaxKind.TaggedTemplateExpression) {
|
||||
var tagExpression = <TaggedTemplateExpression>node;
|
||||
@@ -5870,35 +5934,29 @@ module ts {
|
||||
typeArguments = callExpression.typeArguments;
|
||||
}
|
||||
|
||||
Debug.assert(adjustedArgCount !== undefined, "'adjustedArgCount' undefined");
|
||||
Debug.assert(callIsIncomplete !== undefined, "'callIsIncomplete' undefined");
|
||||
|
||||
return checkArity(adjustedArgCount, typeArguments, callIsIncomplete, signature);
|
||||
|
||||
/**
|
||||
* @param adjustedArgCount The "apparent" number of arguments that we will have in this call.
|
||||
* @param typeArguments Type arguments node of the call if it exists; undefined otherwise.
|
||||
* @param callIsIncomplete Whether or not a call is unfinished, and we should be "lenient" when we have too few arguments.
|
||||
* @param signature The signature whose arity we are comparing.
|
||||
*/
|
||||
function checkArity(adjustedArgCount: number, typeArguments: NodeArray<TypeNode>, callIsIncomplete: boolean, signature: Signature): boolean {
|
||||
// Too many arguments implies incorrect arity.
|
||||
if (!signature.hasRestParameter && adjustedArgCount > signature.parameters.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the user supplied type arguments, but the number of type arguments does not match
|
||||
// the declared number of type parameters, the call has an incorrect arity.
|
||||
var hasRightNumberOfTypeArgs = !typeArguments ||
|
||||
(signature.typeParameters && typeArguments.length === signature.typeParameters.length);
|
||||
if (!hasRightNumberOfTypeArgs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the call is incomplete, we should skip the lower bound check.
|
||||
var hasEnoughArguments = adjustedArgCount >= signature.minArgumentCount;
|
||||
return callIsIncomplete || hasEnoughArguments;
|
||||
// If the user supplied type arguments, but the number of type arguments does not match
|
||||
// the declared number of type parameters, the call has an incorrect arity.
|
||||
var hasRightNumberOfTypeArgs = !typeArguments ||
|
||||
(signature.typeParameters && typeArguments.length === signature.typeParameters.length);
|
||||
if (!hasRightNumberOfTypeArgs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If spread arguments are present, check that they correspond to a rest parameter. If so, no
|
||||
// further checking is necessary.
|
||||
var spreadArgIndex = getSpreadArgumentIndex(args);
|
||||
if (spreadArgIndex >= 0) {
|
||||
return signature.hasRestParameter && spreadArgIndex >= signature.parameters.length - 1;
|
||||
}
|
||||
|
||||
// Too many arguments implies incorrect arity.
|
||||
if (!signature.hasRestParameter && adjustedArgCount > signature.parameters.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the call is incomplete, we should skip the lower bound check.
|
||||
var hasEnoughArguments = adjustedArgCount >= signature.minArgumentCount;
|
||||
return callIsIncomplete || hasEnoughArguments;
|
||||
}
|
||||
|
||||
// If type has a single call signature and no other members, return that signature. Otherwise, return undefined.
|
||||
@@ -5931,18 +5989,20 @@ module ts {
|
||||
// We perform two passes over the arguments. In the first pass we infer from all arguments, but use
|
||||
// wildcards for all context sensitive function expressions.
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
if (args[i].kind === SyntaxKind.OmittedExpression) {
|
||||
continue;
|
||||
var arg = args[i];
|
||||
if (arg.kind !== SyntaxKind.OmittedExpression) {
|
||||
var paramType = getTypeAtPosition(signature, arg.kind === SyntaxKind.SpreadElementExpression ? -1 : i);
|
||||
if (i === 0 && args[i].parent.kind === SyntaxKind.TaggedTemplateExpression) {
|
||||
var argType = globalTemplateStringsArrayType;
|
||||
}
|
||||
else {
|
||||
// For context sensitive arguments we pass the identityMapper, which is a signal to treat all
|
||||
// context sensitive function expressions as wildcards
|
||||
var mapper = excludeArgument && excludeArgument[i] !== undefined ? identityMapper : inferenceMapper;
|
||||
var argType = checkExpressionWithContextualType(arg, paramType, mapper);
|
||||
}
|
||||
inferTypes(context, argType, paramType);
|
||||
}
|
||||
var parameterType = getTypeAtPosition(signature, i);
|
||||
if (i === 0 && args[i].parent.kind === SyntaxKind.TaggedTemplateExpression) {
|
||||
inferTypes(context, globalTemplateStringsArrayType, parameterType);
|
||||
continue;
|
||||
}
|
||||
// For context sensitive arguments we pass the identityMapper, which is a signal to treat all
|
||||
// context sensitive function expressions as wildcards
|
||||
var mapper = excludeArgument && excludeArgument[i] !== undefined ? identityMapper : inferenceMapper;
|
||||
inferTypes(context, checkExpressionWithContextualType(args[i], parameterType, mapper), parameterType);
|
||||
}
|
||||
|
||||
// In the second pass we visit only context sensitive arguments, and only those that aren't excluded, this
|
||||
@@ -5950,13 +6010,11 @@ module ts {
|
||||
// as we construct types for contextually typed parameters)
|
||||
if (excludeArgument) {
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
if (args[i].kind === SyntaxKind.OmittedExpression) {
|
||||
continue;
|
||||
}
|
||||
// No need to special-case tagged templates; their excludeArgument value will be 'undefined'.
|
||||
// No need to check for omitted args and template expressions, their exlusion value is always undefined
|
||||
if (excludeArgument[i] === false) {
|
||||
var parameterType = getTypeAtPosition(signature, i);
|
||||
inferTypes(context, checkExpressionWithContextualType(args[i], parameterType, inferenceMapper), parameterType);
|
||||
var arg = args[i];
|
||||
var paramType = getTypeAtPosition(signature, arg.kind === SyntaxKind.SpreadElementExpression ? -1 : i);
|
||||
inferTypes(context, checkExpressionWithContextualType(arg, paramType, inferenceMapper), paramType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5994,37 +6052,24 @@ module ts {
|
||||
return typeArgumentsAreAssignable;
|
||||
}
|
||||
|
||||
function checkApplicableSignature(node: CallLikeExpression, args: Node[], signature: Signature, relation: Map<RelationComparisonResult>, excludeArgument: boolean[], reportErrors: boolean) {
|
||||
function checkApplicableSignature(node: CallLikeExpression, args: Expression[], signature: Signature, relation: Map<RelationComparisonResult>, excludeArgument: boolean[], reportErrors: boolean) {
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
var arg = args[i];
|
||||
var argType: Type;
|
||||
|
||||
if (arg.kind === SyntaxKind.OmittedExpression) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var paramType = getTypeAtPosition(signature, i);
|
||||
|
||||
if (i === 0 && node.kind === SyntaxKind.TaggedTemplateExpression) {
|
||||
// A tagged template expression has something of a
|
||||
// "virtual" parameter with the "cooked" strings array type.
|
||||
argType = globalTemplateStringsArrayType;
|
||||
}
|
||||
else {
|
||||
// String literals get string literal types unless we're reporting errors
|
||||
argType = arg.kind === SyntaxKind.StringLiteral && !reportErrors
|
||||
? getStringLiteralType(<LiteralExpression>arg)
|
||||
: checkExpressionWithContextualType(<LiteralExpression>arg, paramType, excludeArgument && excludeArgument[i] ? identityMapper : undefined);
|
||||
}
|
||||
|
||||
// Use argument expression as error location when reporting errors
|
||||
var isValidArgument = checkTypeRelatedTo(argType, paramType, relation, reportErrors ? arg : undefined,
|
||||
Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1);
|
||||
if (!isValidArgument) {
|
||||
return false;
|
||||
if (arg.kind !== SyntaxKind.OmittedExpression) {
|
||||
// Check spread elements against rest type (from arity check we know spread argument corresponds to a rest parameter)
|
||||
var paramType = getTypeAtPosition(signature, arg.kind === SyntaxKind.SpreadElementExpression ? -1 : i);
|
||||
// A tagged template expression provides a special first argument, and string literals get string literal types
|
||||
// unless we're reporting errors
|
||||
var argType = i === 0 && node.kind === SyntaxKind.TaggedTemplateExpression ? globalTemplateStringsArrayType :
|
||||
arg.kind === SyntaxKind.StringLiteral && !reportErrors ? getStringLiteralType(<LiteralExpression>arg) :
|
||||
checkExpressionWithContextualType(arg, paramType, excludeArgument && excludeArgument[i] ? identityMapper : undefined);
|
||||
// Use argument expression as error location when reporting errors
|
||||
if (!checkTypeRelatedTo(argType, paramType, relation, reportErrors ? arg : undefined,
|
||||
Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -6091,8 +6136,8 @@ module ts {
|
||||
}
|
||||
|
||||
var candidates = candidatesOutArray || [];
|
||||
// collectCandidates fills up the candidates array directly
|
||||
collectCandidates();
|
||||
// reorderCandidates fills up the candidates array directly
|
||||
reorderCandidates(signatures, candidates);
|
||||
if (!candidates.length) {
|
||||
error(node, Diagnostics.Supplied_parameters_do_not_match_any_signature_of_call_target);
|
||||
return resolveErrorCall(node);
|
||||
@@ -6282,60 +6327,6 @@ module ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// The candidate list orders groups in reverse, but within a group signatures are kept in declaration order
|
||||
// A nit here is that we reorder only signatures that belong to the same symbol,
|
||||
// so order how inherited signatures are processed is still preserved.
|
||||
// interface A { (x: string): void }
|
||||
// interface B extends A { (x: 'foo'): string }
|
||||
// var b: B;
|
||||
// b('foo') // <- here overloads should be processed as [(x:'foo'): string, (x: string): void]
|
||||
function collectCandidates(): void {
|
||||
var result = candidates;
|
||||
var lastParent: Node;
|
||||
var lastSymbol: Symbol;
|
||||
var cutoffIndex: number = 0;
|
||||
var index: number;
|
||||
var specializedIndex: number = -1;
|
||||
var spliceIndex: number;
|
||||
Debug.assert(!result.length);
|
||||
for (var i = 0; i < signatures.length; i++) {
|
||||
var signature = signatures[i];
|
||||
var symbol = signature.declaration && getSymbolOfNode(signature.declaration);
|
||||
var parent = signature.declaration && signature.declaration.parent;
|
||||
if (!lastSymbol || symbol === lastSymbol) {
|
||||
if (lastParent && parent === lastParent) {
|
||||
index++;
|
||||
}
|
||||
else {
|
||||
lastParent = parent;
|
||||
index = cutoffIndex;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// current declaration belongs to a different symbol
|
||||
// set cutoffIndex so re-orderings in the future won't change result set from 0 to cutoffIndex
|
||||
index = cutoffIndex = result.length;
|
||||
lastParent = parent;
|
||||
}
|
||||
lastSymbol = symbol;
|
||||
|
||||
// specialized signatures always need to be placed before non-specialized signatures regardless
|
||||
// of the cutoff position; see GH#1133
|
||||
if (signature.hasStringLiterals) {
|
||||
specializedIndex++;
|
||||
spliceIndex = specializedIndex;
|
||||
// The cutoff index always needs to be greater than or equal to the specialized signature index
|
||||
// in order to prevent non-specialized signatures from being added before a specialized
|
||||
// signature.
|
||||
cutoffIndex++;
|
||||
}
|
||||
else {
|
||||
spliceIndex = index;
|
||||
}
|
||||
|
||||
result.splice(spliceIndex, 0, signature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resolveCallExpression(node: CallExpression, candidatesOutArray: Signature[]): Signature {
|
||||
@@ -6391,6 +6382,13 @@ module ts {
|
||||
}
|
||||
|
||||
function resolveNewExpression(node: NewExpression, candidatesOutArray: Signature[]): Signature {
|
||||
if (node.arguments && languageVersion < ScriptTarget.ES6) {
|
||||
var spreadIndex = getSpreadArgumentIndex(node.arguments);
|
||||
if (spreadIndex >= 0) {
|
||||
error(node.arguments[spreadIndex], Diagnostics.Spread_operator_in_new_expressions_is_only_available_when_targeting_ECMAScript_6_and_higher);
|
||||
}
|
||||
}
|
||||
|
||||
var expressionType = checkExpression(node.expression);
|
||||
// TS 1.0 spec: 4.11
|
||||
// If ConstructExpr is of type Any, Args can be any argument
|
||||
@@ -6536,9 +6534,14 @@ module ts {
|
||||
}
|
||||
|
||||
function getTypeAtPosition(signature: Signature, pos: number): Type {
|
||||
if (pos >= 0) {
|
||||
return signature.hasRestParameter ?
|
||||
pos < signature.parameters.length - 1 ? getTypeOfSymbol(signature.parameters[pos]) : getRestTypeOfSignature(signature) :
|
||||
pos < signature.parameters.length ? getTypeOfSymbol(signature.parameters[pos]) : anyType;
|
||||
}
|
||||
return signature.hasRestParameter ?
|
||||
pos < signature.parameters.length - 1 ? getTypeOfSymbol(signature.parameters[pos]) : getRestTypeOfSignature(signature) :
|
||||
pos < signature.parameters.length ? getTypeOfSymbol(signature.parameters[pos]) : anyType;
|
||||
getTypeOfSymbol(signature.parameters[signature.parameters.length - 1]) :
|
||||
anyArrayType;
|
||||
}
|
||||
|
||||
function assignContextualParameterTypes(signature: Signature, context: Signature, mapper: TypeMapper) {
|
||||
|
||||
@@ -303,6 +303,7 @@ module ts {
|
||||
this_cannot_be_referenced_in_a_computed_property_name: { code: 2465, category: DiagnosticCategory.Error, key: "'this' cannot be referenced in a computed property name." },
|
||||
super_cannot_be_referenced_in_a_computed_property_name: { code: 2466, category: DiagnosticCategory.Error, key: "'super' cannot be referenced in a computed property name." },
|
||||
A_computed_property_name_cannot_reference_a_type_parameter_from_its_containing_type: { code: 2466, category: DiagnosticCategory.Error, key: "A computed property name cannot reference a type parameter from its containing type." },
|
||||
Spread_operator_in_new_expressions_is_only_available_when_targeting_ECMAScript_6_and_higher: { code: 2468, category: DiagnosticCategory.Error, key: "Spread operator in 'new' expressions is only available when targeting ECMAScript 6 and higher." },
|
||||
Import_declaration_0_is_using_private_name_1: { code: 4000, category: DiagnosticCategory.Error, key: "Import declaration '{0}' is using private name '{1}'." },
|
||||
Type_parameter_0_of_exported_class_has_or_is_using_private_name_1: { code: 4002, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using private name '{1}'." },
|
||||
Type_parameter_0_of_exported_interface_has_or_is_using_private_name_1: { code: 4004, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported interface has or is using private name '{1}'." },
|
||||
|
||||
@@ -1204,6 +1204,10 @@
|
||||
"category": "Error",
|
||||
"code": 2466
|
||||
},
|
||||
"Spread operator in 'new' expressions is only available when targeting ECMAScript 6 and higher.": {
|
||||
"category": "Error",
|
||||
"code": 2468
|
||||
},
|
||||
|
||||
"Import declaration '{0}' is using private name '{1}'.": {
|
||||
"category": "Error",
|
||||
|
||||
@@ -1994,7 +1994,7 @@ module ts {
|
||||
break;
|
||||
}
|
||||
// _a .. _h, _j ... _z, _0, _1, ...
|
||||
name = "_" + (tempCount < 25 ? String.fromCharCode(tempCount + (tempCount < 8 ? 0: 1) + CharacterCodes.a) : tempCount - 25);
|
||||
name = "_" + (tempCount < 25 ? String.fromCharCode(tempCount + (tempCount < 8 ? 0 : 1) + CharacterCodes.a) : tempCount - 25);
|
||||
tempCount++;
|
||||
}
|
||||
var result = <Identifier>createNode(SyntaxKind.Identifier);
|
||||
@@ -2423,22 +2423,10 @@ module ts {
|
||||
return true;
|
||||
}
|
||||
|
||||
function emitArrayLiteral(node: ArrayLiteralExpression) {
|
||||
var elements = node.elements;
|
||||
var length = elements.length;
|
||||
if (length === 0) {
|
||||
write("[]");
|
||||
return;
|
||||
}
|
||||
if (languageVersion >= ScriptTarget.ES6) {
|
||||
write("[");
|
||||
emitList(elements, 0, elements.length, /*multiLine*/(node.flags & NodeFlags.MultiLine) !== 0,
|
||||
/*trailingComma*/ elements.hasTrailingComma);
|
||||
write("]");
|
||||
return;
|
||||
}
|
||||
function emitListWithSpread(elements: Expression[], multiLine: boolean, trailingComma: boolean) {
|
||||
var pos = 0;
|
||||
var group = 0;
|
||||
var length = elements.length;
|
||||
while (pos < length) {
|
||||
// Emit using the pattern <group0>.concat(<group1>, <group2>, ...)
|
||||
if (group === 1) {
|
||||
@@ -2459,8 +2447,7 @@ module ts {
|
||||
i++;
|
||||
}
|
||||
write("[");
|
||||
emitList(elements, pos, i - pos, /*multiLine*/ (node.flags & NodeFlags.MultiLine) !== 0,
|
||||
/*trailingComma*/ elements.hasTrailingComma);
|
||||
emitList(elements, pos, i - pos, multiLine, trailingComma && i === length);
|
||||
write("]");
|
||||
pos = i;
|
||||
}
|
||||
@@ -2471,6 +2458,23 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
function emitArrayLiteral(node: ArrayLiteralExpression) {
|
||||
var elements = node.elements;
|
||||
if (elements.length === 0) {
|
||||
write("[]");
|
||||
}
|
||||
else if (languageVersion >= ScriptTarget.ES6) {
|
||||
write("[");
|
||||
emitList(elements, 0, elements.length, /*multiLine*/ (node.flags & NodeFlags.MultiLine) !== 0,
|
||||
/*trailingComma*/ elements.hasTrailingComma);
|
||||
write("]");
|
||||
}
|
||||
else {
|
||||
emitListWithSpread(elements, /*multiLine*/ (node.flags & NodeFlags.MultiLine) !== 0,
|
||||
/*trailingComma*/ elements.hasTrailingComma);
|
||||
}
|
||||
}
|
||||
|
||||
function emitObjectLiteral(node: ObjectLiteralExpression) {
|
||||
write("{");
|
||||
var properties = node.properties;
|
||||
@@ -2565,7 +2569,80 @@ module ts {
|
||||
write("]");
|
||||
}
|
||||
|
||||
function hasSpreadElement(elements: Expression[]) {
|
||||
return forEach(elements, e => e.kind === SyntaxKind.SpreadElementExpression);
|
||||
}
|
||||
|
||||
function skipParentheses(node: Expression): Expression {
|
||||
while (node.kind === SyntaxKind.ParenthesizedExpression || node.kind === SyntaxKind.TypeAssertionExpression) {
|
||||
node = (<ParenthesizedExpression | TypeAssertion>node).expression;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
function emitCallTarget(node: Expression): Expression {
|
||||
if (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.ThisKeyword || node.kind === SyntaxKind.SuperKeyword) {
|
||||
emit(node);
|
||||
return node;
|
||||
}
|
||||
var temp = createTempVariable(node);
|
||||
recordTempDeclaration(temp);
|
||||
write("(");
|
||||
emit(temp);
|
||||
write(" = ");
|
||||
emit(node);
|
||||
write(")");
|
||||
return temp;
|
||||
}
|
||||
|
||||
function emitCallWithSpread(node: CallExpression) {
|
||||
var target: Expression;
|
||||
var expr = skipParentheses(node.expression);
|
||||
if (expr.kind === SyntaxKind.PropertyAccessExpression) {
|
||||
// Target will be emitted as "this" argument
|
||||
target = emitCallTarget((<PropertyAccessExpression>expr).expression);
|
||||
write(".");
|
||||
emit((<PropertyAccessExpression>expr).name);
|
||||
}
|
||||
else if (expr.kind === SyntaxKind.ElementAccessExpression) {
|
||||
// Target will be emitted as "this" argument
|
||||
target = emitCallTarget((<PropertyAccessExpression>expr).expression);
|
||||
write("[");
|
||||
emit((<ElementAccessExpression>expr).argumentExpression);
|
||||
write("]");
|
||||
}
|
||||
else if (expr.kind === SyntaxKind.SuperKeyword) {
|
||||
target = expr;
|
||||
write("_super");
|
||||
}
|
||||
else {
|
||||
emit(node.expression);
|
||||
}
|
||||
write(".apply(");
|
||||
if (target) {
|
||||
if (target.kind === SyntaxKind.SuperKeyword) {
|
||||
// Calls of form super(...) and super.foo(...)
|
||||
emitThis(target);
|
||||
}
|
||||
else {
|
||||
// Calls of form obj.foo(...)
|
||||
emit(target);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Calls of form foo(...)
|
||||
write("void 0");
|
||||
}
|
||||
write(", ");
|
||||
emitListWithSpread(node.arguments, /*multiLine*/ false, /*trailingComma*/ false);
|
||||
write(")");
|
||||
}
|
||||
|
||||
function emitCallExpression(node: CallExpression) {
|
||||
if (languageVersion < ScriptTarget.ES6 && hasSpreadElement(node.arguments)) {
|
||||
emitCallWithSpread(node);
|
||||
return;
|
||||
}
|
||||
var superCall = false;
|
||||
if (node.expression.kind === SyntaxKind.SuperKeyword) {
|
||||
write("_super");
|
||||
|
||||
@@ -1516,7 +1516,6 @@ module ts {
|
||||
case ParsingContext.TypeParameters:
|
||||
return isIdentifier();
|
||||
case ParsingContext.ArgumentExpressions:
|
||||
return token === SyntaxKind.CommaToken || isStartOfExpression();
|
||||
case ParsingContext.ArrayLiteralMembers:
|
||||
return token === SyntaxKind.CommaToken || token === SyntaxKind.DotDotDotToken || isStartOfExpression();
|
||||
case ParsingContext.Parameters:
|
||||
@@ -3605,12 +3604,6 @@ module ts {
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
function parseAssignmentExpressionOrOmittedExpression(): Expression {
|
||||
return token === SyntaxKind.CommaToken
|
||||
? <Expression>createNode(SyntaxKind.OmittedExpression)
|
||||
: parseAssignmentExpressionOrHigher();
|
||||
}
|
||||
|
||||
function parseSpreadElement(): Expression {
|
||||
var node = <SpreadElementExpression>createNode(SyntaxKind.SpreadElementExpression);
|
||||
parseExpected(SyntaxKind.DotDotDotToken);
|
||||
@@ -3618,19 +3611,21 @@ module ts {
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
function parseArrayLiteralElement(): Expression {
|
||||
return token === SyntaxKind.DotDotDotToken ? parseSpreadElement() : parseAssignmentExpressionOrOmittedExpression();
|
||||
function parseArgumentOrArrayLiteralElement(): Expression {
|
||||
return token === SyntaxKind.DotDotDotToken ? parseSpreadElement() :
|
||||
token === SyntaxKind.CommaToken ? <Expression>createNode(SyntaxKind.OmittedExpression) :
|
||||
parseAssignmentExpressionOrHigher();
|
||||
}
|
||||
|
||||
function parseArgumentExpression(): Expression {
|
||||
return allowInAnd(parseAssignmentExpressionOrOmittedExpression);
|
||||
return allowInAnd(parseArgumentOrArrayLiteralElement);
|
||||
}
|
||||
|
||||
function parseArrayLiteralExpression(): ArrayLiteralExpression {
|
||||
var node = <ArrayLiteralExpression>createNode(SyntaxKind.ArrayLiteralExpression);
|
||||
parseExpected(SyntaxKind.OpenBracketToken);
|
||||
if (scanner.hasPrecedingLineBreak()) node.flags |= NodeFlags.MultiLine;
|
||||
node.elements = parseDelimitedList(ParsingContext.ArrayLiteralMembers, parseArrayLiteralElement);
|
||||
node.elements = parseDelimitedList(ParsingContext.ArrayLiteralMembers, parseArgumentOrArrayLiteralElement);
|
||||
parseExpected(SyntaxKind.CloseBracketToken);
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user