Added parse, emit, and check for prefix bind

This commit is contained in:
Ron Buckton
2016-11-22 01:54:52 -05:00
parent aebb806955
commit 6246eb1fd8
7 changed files with 109 additions and 28 deletions
+1
View File
@@ -3243,6 +3243,7 @@ namespace ts {
break;
case SyntaxKind.BindExpression:
case SyntaxKind.BindToExpression:
transformFlags |= TransformFlags.AssertESNext;
break;
+50 -20
View File
@@ -12217,6 +12217,11 @@ namespace ts {
}
function checkBindExpression(node: BindExpression): Type {
const signatures = getResolvedPartialSignatures(node);
return createTypeFromSignatures(map(signatures, getSignatureWithoutThis));
}
function checkBindToExpression(node: BindToExpression): Type {
checkNonNullExpression(node.expression);
const signatures = getResolvedPartialSignatures(node);
return createTypeFromSignatures(map(signatures, getSignatureWithoutThis));
@@ -12376,7 +12381,9 @@ namespace ts {
callIsIncomplete = !!templateLiteral.isUnterminated;
}
}
else if (node.kind === SyntaxKind.Decorator || node.kind === SyntaxKind.BindExpression) {
else if (node.kind === SyntaxKind.Decorator
|| node.kind === SyntaxKind.BindExpression
|| node.kind === SyntaxKind.BindToExpression) {
typeArguments = undefined;
argCount = getEffectiveArgumentCount(node, /*args*/ undefined, signature);
}
@@ -12599,8 +12606,8 @@ namespace ts {
* Returns the this argument in calls like x.f(...) and x[f](...). Undefined otherwise.
*/
function getThisArgumentOfCall(node: CallLikeExpression): LeftHandSideExpression {
if (node.kind === SyntaxKind.CallExpression) {
const callee = (<CallExpression>node).expression;
if (node.kind === SyntaxKind.CallExpression || node.kind === SyntaxKind.BindExpression) {
const callee = node.expression;
if (callee.kind === SyntaxKind.PropertyAccessExpression) {
return (callee as PropertyAccessExpression).expression;
}
@@ -12608,7 +12615,7 @@ namespace ts {
return (callee as ElementAccessExpression).expression;
}
}
else if (node.kind === SyntaxKind.BindExpression) {
else if (node.kind === SyntaxKind.BindToExpression) {
return node.expression;
}
}
@@ -12633,7 +12640,9 @@ namespace ts {
});
}
}
else if (node.kind === SyntaxKind.Decorator || node.kind === SyntaxKind.BindExpression) {
else if (node.kind === SyntaxKind.Decorator
|| node.kind === SyntaxKind.BindToExpression
|| node.kind === SyntaxKind.BindExpression) {
// For a decorator, we return undefined as we will determine
// the number and types of arguments for a decorator using
// `getEffectiveArgumentCount` and `getEffectiveArgumentType` below.
@@ -12712,7 +12721,8 @@ namespace ts {
return 3;
}
}
else if (node.kind === SyntaxKind.BindExpression) {
else if (node.kind === SyntaxKind.BindToExpression
|| node.kind === SyntaxKind.BindExpression) {
return signature.minArgumentCount;
}
else {
@@ -12899,7 +12909,8 @@ namespace ts {
if (node.kind === SyntaxKind.Decorator) {
return getEffectiveDecoratorArgumentType(<Decorator>node, argIndex);
}
else if (node.kind === SyntaxKind.BindExpression) {
else if (node.kind === SyntaxKind.BindToExpression
|| node.kind === SyntaxKind.BindExpression) {
return unknownType;
}
else if (argIndex === 0 && node.kind === SyntaxKind.TaggedTemplateExpression) {
@@ -12917,6 +12928,7 @@ namespace ts {
function getEffectiveArgument(node: CallLikeExpression, args: Expression[], argIndex: number) {
// For a decorator or the first argument of a tagged template expression we return undefined.
if (node.kind === SyntaxKind.Decorator ||
node.kind === SyntaxKind.BindToExpression ||
node.kind === SyntaxKind.BindExpression ||
(argIndex === 0 && node.kind === SyntaxKind.TaggedTemplateExpression)) {
return undefined;
@@ -12943,16 +12955,9 @@ namespace ts {
}
function resolveCall(node: CallLikeExpression, signatures: Signature[], partialSignaturesOutArray: Signature[], candidatesOutArray: Signature[], headMessage?: DiagnosticMessage): Signature {
const isTaggedTemplate = node.kind === SyntaxKind.TaggedTemplateExpression;
const isDecorator = node.kind === SyntaxKind.Decorator;
const isPipeline = node.kind === SyntaxKind.BinaryExpression;
const isBind = node.kind === SyntaxKind.BindExpression;
let typeArguments: TypeNode[];
if (!isTaggedTemplate && !isDecorator && !isPipeline && !isBind) {
typeArguments = (<CallExpression>node).typeArguments;
if (node.kind === SyntaxKind.CallExpression || node.kind === SyntaxKind.NewExpression) {
typeArguments = node.typeArguments;
// We already perform checking on the type arguments on the class declaration itself.
if ((<CallExpression>node).expression.kind !== SyntaxKind.SuperKeyword) {
forEach(typeArguments, checkSourceElement);
@@ -12984,10 +12989,12 @@ namespace ts {
// For a decorator, no arguments are susceptible to contextual typing due to the fact
// decorators are applied to a declaration by the emitter, and not to an expression.
let excludeArgument: boolean[];
if (!isDecorator && !isBind) {
if (node.kind === SyntaxKind.CallExpression ||
node.kind === SyntaxKind.NewExpression ||
node.kind === SyntaxKind.TaggedTemplateExpression) {
// We do not need to call `getEffectiveArgumentCount` here as it only
// applies when calculating the number of arguments for a decorator.
for (let i = isTaggedTemplate ? 1 : 0; i < args.length; i++) {
for (let i = node.kind === SyntaxKind.TaggedTemplateExpression ? 1 : 0; i < args.length; i++) {
if (isContextSensitive(args[i])) {
if (!excludeArgument) {
excludeArgument = new Array(args.length);
@@ -13065,8 +13072,7 @@ namespace ts {
checkApplicableSignature(node, args, candidateForArgumentError, assignableRelation, /*excludeArgument*/ undefined, /*reportErrors*/ true);
}
else if (candidateForTypeArgumentError) {
if (!isTaggedTemplate && !isDecorator && typeArguments) {
const typeArguments = (<CallExpression>node).typeArguments;
if (typeArguments) {
checkTypeArguments(candidateForTypeArgumentError, typeArguments, map(typeArguments, getTypeFromTypeNode), /*reportErrors*/ true, headMessage);
}
else {
@@ -13485,6 +13491,26 @@ namespace ts {
}
function resolveBindExpression(node: BindExpression, partialSignaturesOutArray: Signature[], candidatesOutArray?: Signature[]): Signature {
const funcType = checkExpression(node.expression);
const apparentType = getApparentType(funcType);
if (apparentType === unknownType) {
return resolveErrorCall(node);
}
const callSignatures = getSignaturesOfType(apparentType, SignatureKind.Call);
const constructSignatures = getSignaturesOfType(apparentType, SignatureKind.Construct);
if (isUntypedFunctionCall(funcType, apparentType, callSignatures.length, constructSignatures.length)) {
return resolveUntypedCall(node);
}
if (!callSignatures.length) {
return resolveErrorCall(node);
}
return resolveCall(node, callSignatures, partialSignaturesOutArray, candidatesOutArray);
}
function resolveBindToExpression(node: BindToExpression, partialSignaturesOutArray: Signature[], candidatesOutArray?: Signature[]): Signature {
const funcType = checkExpression(node.targetExpression);
const apparentType = getApparentType(funcType);
if (apparentType === unknownType) {
@@ -13518,6 +13544,8 @@ namespace ts {
return resolvePipelineExpression(<PipelineExpression>node, candidatesOutArray);
case SyntaxKind.BindExpression:
return resolveBindExpression(<BindExpression>node, partialSignaturesOutArray, candidatesOutArray);
case SyntaxKind.BindToExpression:
return resolveBindToExpression(<BindToExpression>node, partialSignaturesOutArray, candidatesOutArray);
}
Debug.fail("Branch in 'resolveSignature' should be unreachable.");
}
@@ -15310,6 +15338,8 @@ namespace ts {
return checkIndexedAccess(<ElementAccessExpression>node);
case SyntaxKind.BindExpression:
return checkBindExpression(<BindExpression>node);
case SyntaxKind.BindToExpression:
return checkBindToExpression(<BindToExpression>node);
case SyntaxKind.CallExpression:
case SyntaxKind.NewExpression:
return checkCallExpression(<CallExpression>node);
+8 -1
View File
@@ -618,6 +618,8 @@ namespace ts {
return emitElementAccessExpression(<ElementAccessExpression>node);
case SyntaxKind.BindExpression:
return emitBindExpression(<BindExpression>node);
case SyntaxKind.BindToExpression:
return emitBindToExpression(<BindToExpression>node);
case SyntaxKind.CallExpression:
return emitCallExpression(<CallExpression>node);
case SyntaxKind.NewExpression:
@@ -1081,12 +1083,17 @@ namespace ts {
write("]");
}
function emitBindExpression(node: BindExpression) {
function emitBindToExpression(node: BindToExpression) {
emitExpression(node.expression);
write("::");
emitExpression(node.targetExpression);
}
function emitBindExpression(node: BindExpression) {
write("::");
emitExpression(node.expression);
}
function emitCallExpression(node: CallExpression) {
emitExpression(node.expression);
emitTypeArguments(node, node.typeArguments);
+15 -3
View File
@@ -162,8 +162,10 @@ namespace ts {
return visitNode(cbNode, (<ElementAccessExpression>node).expression) ||
visitNode(cbNode, (<ElementAccessExpression>node).argumentExpression);
case SyntaxKind.BindExpression:
return visitNode(cbNode, (<BindExpression>node).expression) ||
visitNode(cbNode, (<BindExpression>node).targetExpression);
return visitNode(cbNode, (<BindExpression>node).expression);
case SyntaxKind.BindToExpression:
return visitNode(cbNode, (<BindToExpression>node).expression) ||
visitNode(cbNode, (<BindToExpression>node).targetExpression);
case SyntaxKind.CallExpression:
case SyntaxKind.NewExpression:
return visitNode(cbNode, (<CallExpression>node).expression) ||
@@ -2781,6 +2783,7 @@ namespace ts {
case SyntaxKind.LessThanToken:
case SyntaxKind.AwaitKeyword:
case SyntaxKind.YieldKeyword:
case SyntaxKind.ColonColonToken:
// Yield/await always starts an expression. Either it is an identifier (in which case
// it is definitely an expression). Or it's a keyword (either because we're in
// a generator or async function, or in strict mode (or both)) and it started a yield or await expression.
@@ -3433,6 +3436,13 @@ namespace ts {
return finishNode(node);
}
function parseBindExpression() {
const node = <BindExpression>createNode(SyntaxKind.BindExpression);
nextToken();
node.expression = parseMemberExpressionOrHigher();
return finishNode(node);
}
function parseDeleteExpression() {
const node = <DeleteExpression>createNode(SyntaxKind.DeleteExpression);
nextToken();
@@ -4030,7 +4040,7 @@ namespace ts {
}
if (parseOptional(SyntaxKind.ColonColonToken)) {
const bindExpression = <BindExpression>createNode(SyntaxKind.BindExpression, expression.pos);
const bindExpression = <BindToExpression>createNode(SyntaxKind.BindToExpression, expression.pos);
bindExpression.expression = expression;
bindExpression.targetExpression = parseMemberExpressionOrHigher();
expression = finishNode(bindExpression);
@@ -4179,6 +4189,8 @@ namespace ts {
break;
case SyntaxKind.TemplateHead:
return parseTemplateExpression();
case SyntaxKind.ColonColonToken:
return parseBindExpression();
}
return parseIdentifier(Diagnostics.Expression_expected);
+24
View File
@@ -73,6 +73,8 @@ namespace ts {
return visitOperatorExpression(node as OperatorExpression);
case SyntaxKind.BindExpression:
return visitBindExpression(node as BindExpression);
case SyntaxKind.BindToExpression:
return visitBindToExpression(node as BindToExpression);
default:
return visitEachChild(node, visitor, context);
}
@@ -545,6 +547,28 @@ namespace ts {
}
function visitBindExpression(node: BindExpression) {
const operand = visitNode(node.expression, visitor, isExpression);
if (operand.kind === SyntaxKind.PropertyAccessExpression
|| operand.kind === SyntaxKind.ElementAccessExpression) {
const { target, thisArg } = createCallBinding(operand, hoistVariableDeclaration);
return createFunctionBind(
target,
thisArg,
[],
node
)
}
else {
return createFunctionBind(
operand,
createNull(),
[],
node
);
}
}
function visitBindToExpression(node: BindToExpression) {
const thisArg = createTempVariable(context.hoistVariableDeclaration);
return createComma(
createAssignment(
+10 -4
View File
@@ -234,7 +234,7 @@ namespace ts {
ObjectLiteralExpression,
PropertyAccessExpression,
ElementAccessExpression,
BindExpression,
BindToExpression,
CallExpression,
NewExpression,
TaggedTemplateExpression,
@@ -246,6 +246,7 @@ namespace ts {
TypeOfExpression,
VoidExpression,
AwaitExpression,
BindExpression,
PrefixUnaryExpression,
PostfixUnaryExpression,
BinaryExpression,
@@ -1419,12 +1420,17 @@ namespace ts {
| SuperElementAccessExpression
;
export interface BindExpression extends MemberExpression {
kind: SyntaxKind.BindExpression;
export interface BindToExpression extends MemberExpression {
kind: SyntaxKind.BindToExpression;
expression: LeftHandSideExpression;
targetExpression: MemberExpression;
}
export interface BindExpression extends PrimaryExpression {
kind: SyntaxKind.BindExpression;
expression: MemberExpression;
}
export interface CallExpression extends LeftHandSideExpression, Declaration {
kind: SyntaxKind.CallExpression;
expression: LeftHandSideExpression;
@@ -1456,7 +1462,7 @@ namespace ts {
template: TemplateLiteral;
}
export type CallLikeExpression = CallExpression | NewExpression | TaggedTemplateExpression | Decorator | PipelineExpression | BindExpression;
export type CallLikeExpression = CallExpression | NewExpression | TaggedTemplateExpression | Decorator | PipelineExpression | BindExpression | BindToExpression;
export interface PositionalElement extends Expression {
kind: SyntaxKind.PositionalElement;
+1
View File
@@ -3950,6 +3950,7 @@ namespace ts {
function isMemberExpressionKind(kind: SyntaxKind): boolean {
return kind === SyntaxKind.PropertyAccessExpression
|| kind === SyntaxKind.ElementAccessExpression
|| kind === SyntaxKind.BindToExpression
|| kind === SyntaxKind.BindExpression
|| kind === SyntaxKind.JsxElement
|| kind === SyntaxKind.JsxSelfClosingElement