mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-04 21:53:42 -06:00
Fixed contextual typing for tagged template expressions.
This commit is contained in:
parent
ed9234ed32
commit
b65a422c7a
@ -4813,17 +4813,25 @@ module ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// In a typed function call, an argument expression is contextually typed by the type of the corresponding parameter.
|
||||
function getContextualTypeForArgument(node: Expression): Type {
|
||||
var callExpression = <CallExpression>node.parent;
|
||||
var argIndex = indexOf(callExpression.arguments, node);
|
||||
// In a typed function call, an argument or substitution expression is contextually typed by the type of the corresponding parameter.
|
||||
function getContextualTypeForArgument(callTarget: CallLikeExpression, arg: Expression): Type {
|
||||
var args = getEffectiveCallArguments(callTarget);
|
||||
var argIndex = indexOf(args, arg);
|
||||
if (argIndex >= 0) {
|
||||
var signature = getResolvedSignature(callExpression);
|
||||
var signature = getResolvedSignature(callTarget);
|
||||
return getTypeAtPosition(signature, argIndex);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getContextualTypeForSubstitutionExpression(template: TemplateExpression, substitutionExpression: Expression) {
|
||||
if (template.parent.kind === SyntaxKind.TaggedTemplateExpression) {
|
||||
return getContextualTypeForArgument(<TaggedTemplateExpression>template.parent, substitutionExpression);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getContextualTypeForBinaryOperand(node: Expression): Type {
|
||||
var binaryExpression = <BinaryExpression>node.parent;
|
||||
var operator = binaryExpression.operator;
|
||||
@ -4959,7 +4967,7 @@ module ts {
|
||||
return getContextualTypeForReturnExpression(node);
|
||||
case SyntaxKind.CallExpression:
|
||||
case SyntaxKind.NewExpression:
|
||||
return getContextualTypeForArgument(node);
|
||||
return getContextualTypeForArgument(<CallExpression>parent, node);
|
||||
case SyntaxKind.TypeAssertionExpression:
|
||||
return getTypeFromTypeNode((<TypeAssertion>parent).type);
|
||||
case SyntaxKind.BinaryExpression:
|
||||
@ -4970,6 +4978,11 @@ module ts {
|
||||
return getContextualTypeForElementExpression(node);
|
||||
case SyntaxKind.ConditionalExpression:
|
||||
return getContextualTypeForConditionalOperand(node);
|
||||
case SyntaxKind.TemplateExpression:
|
||||
return getContextualTypeForSubstitutionExpression(<TemplateExpression>parent.parent, node);
|
||||
case SyntaxKind.TemplateSpan:
|
||||
Debug.assert(parent.parent.kind === SyntaxKind.TemplateExpression);
|
||||
return getContextualTypeForSubstitutionExpression(<TemplateExpression>parent.parent, node);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
@ -5571,7 +5584,7 @@ module ts {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the effective arguments for an expression that works like a function invokation.
|
||||
* Returns the effective arguments for an expression that works like a function invocation.
|
||||
*
|
||||
* If 'node' is a CallExpression or a NewExpression, then its argument list is returned.
|
||||
* If 'node' is a TaggedTemplateExpression, a new argument list is constructed from the substitution
|
||||
|
||||
45
tests/baselines/reference/taggedTemplateContextualTyping.js
Normal file
45
tests/baselines/reference/taggedTemplateContextualTyping.js
Normal file
@ -0,0 +1,45 @@
|
||||
//// [taggedTemplateContextualTyping.ts]
|
||||
|
||||
function tempTag1<T>(templateStrs: TemplateStringsArray, f: (x: T) => T, x: T): T;
|
||||
function tempTag1<T>(templateStrs: TemplateStringsArray, f: (x: T) => T, h: (y: T) => T, x: T): T;
|
||||
function tempTag1<T>(...rest: any[]): T {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
tempTag1 `${ x => x }${ 10 }`;
|
||||
tempTag1 `${ x => x }${ y => y }${ 10 }`;
|
||||
tempTag1 `${ x => x }${ (y: number) => y }${ undefined }`;
|
||||
tempTag1 `${ (x: number) => x }${ y => y }${ undefined }`;
|
||||
|
||||
function tempTag2(templateStrs: TemplateStringsArray, f: (x: number) => number, x: number): number;
|
||||
function tempTag2(templateStrs: TemplateStringsArray, f: (x: string) => string, h: (y: string) => string, x: string): string;
|
||||
function tempTag2(...rest: any[]): any {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
tempTag2 `${ x => x }${ 0 }`;
|
||||
tempTag2 `${ x => x }${ y => y }${ "hello" }`;
|
||||
tempTag2 `${ x => x }${ 0 }`;
|
||||
|
||||
//// [taggedTemplateContextualTyping.js]
|
||||
function tempTag1() {
|
||||
var rest = [];
|
||||
for (var _i = 0; _i < arguments.length; _i++) {
|
||||
rest[_i - 0] = arguments[_i];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
tempTag1 `${function (x) { return x; }}${10}`;
|
||||
tempTag1 `${function (x) { return x; }}${function (y) { return y; }}${10}`;
|
||||
tempTag1 `${function (x) { return x; }}${function (y) { return y; }}${undefined}`;
|
||||
tempTag1 `${function (x) { return x; }}${function (y) { return y; }}${undefined}`;
|
||||
function tempTag2() {
|
||||
var rest = [];
|
||||
for (var _i = 0; _i < arguments.length; _i++) {
|
||||
rest[_i - 0] = arguments[_i];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
tempTag2 `${function (x) { return x; }}${0}`;
|
||||
tempTag2 `${function (x) { return x; }}${function (y) { return y; }}${"hello"}`;
|
||||
tempTag2 `${function (x) { return x; }}${0}`;
|
||||
124
tests/baselines/reference/taggedTemplateContextualTyping.types
Normal file
124
tests/baselines/reference/taggedTemplateContextualTyping.types
Normal file
@ -0,0 +1,124 @@
|
||||
=== tests/cases/conformance/expressions/contextualTyping/taggedTemplateContextualTyping.ts ===
|
||||
|
||||
function tempTag1<T>(templateStrs: TemplateStringsArray, f: (x: T) => T, x: T): T;
|
||||
>tempTag1 : { <T>(templateStrs: TemplateStringsArray, f: (x: T) => T, x: T): T; <T>(templateStrs: TemplateStringsArray, f: (x: T) => T, h: (y: T) => T, x: T): T; }
|
||||
>T : T
|
||||
>templateStrs : TemplateStringsArray
|
||||
>TemplateStringsArray : TemplateStringsArray
|
||||
>f : (x: T) => T
|
||||
>x : T
|
||||
>T : T
|
||||
>T : T
|
||||
>x : T
|
||||
>T : T
|
||||
>T : T
|
||||
|
||||
function tempTag1<T>(templateStrs: TemplateStringsArray, f: (x: T) => T, h: (y: T) => T, x: T): T;
|
||||
>tempTag1 : { <T>(templateStrs: TemplateStringsArray, f: (x: T) => T, x: T): T; <T>(templateStrs: TemplateStringsArray, f: (x: T) => T, h: (y: T) => T, x: T): T; }
|
||||
>T : T
|
||||
>templateStrs : TemplateStringsArray
|
||||
>TemplateStringsArray : TemplateStringsArray
|
||||
>f : (x: T) => T
|
||||
>x : T
|
||||
>T : T
|
||||
>T : T
|
||||
>h : (y: T) => T
|
||||
>y : T
|
||||
>T : T
|
||||
>T : T
|
||||
>x : T
|
||||
>T : T
|
||||
>T : T
|
||||
|
||||
function tempTag1<T>(...rest: any[]): T {
|
||||
>tempTag1 : { <T>(templateStrs: TemplateStringsArray, f: (x: T) => T, x: T): T; <T>(templateStrs: TemplateStringsArray, f: (x: T) => T, h: (y: T) => T, x: T): T; }
|
||||
>T : T
|
||||
>rest : any[]
|
||||
>T : T
|
||||
|
||||
return undefined;
|
||||
>undefined : undefined
|
||||
}
|
||||
|
||||
tempTag1 `${ x => x }${ 10 }`;
|
||||
>tempTag1 : { <T>(templateStrs: TemplateStringsArray, f: (x: T) => T, x: T): T; <T>(templateStrs: TemplateStringsArray, f: (x: T) => T, h: (y: T) => T, x: T): T; }
|
||||
>x => x : (x: number) => number
|
||||
>x : number
|
||||
>x : number
|
||||
|
||||
tempTag1 `${ x => x }${ y => y }${ 10 }`;
|
||||
>tempTag1 : { <T>(templateStrs: TemplateStringsArray, f: (x: T) => T, x: T): T; <T>(templateStrs: TemplateStringsArray, f: (x: T) => T, h: (y: T) => T, x: T): T; }
|
||||
>x => x : (x: number) => number
|
||||
>x : number
|
||||
>x : number
|
||||
>y => y : (y: number) => number
|
||||
>y : number
|
||||
>y : number
|
||||
|
||||
tempTag1 `${ x => x }${ (y: number) => y }${ undefined }`;
|
||||
>tempTag1 : { <T>(templateStrs: TemplateStringsArray, f: (x: T) => T, x: T): T; <T>(templateStrs: TemplateStringsArray, f: (x: T) => T, h: (y: T) => T, x: T): T; }
|
||||
>x => x : (x: number) => number
|
||||
>x : number
|
||||
>x : number
|
||||
>(y: number) => y : (y: number) => number
|
||||
>y : number
|
||||
>y : number
|
||||
>undefined : undefined
|
||||
|
||||
tempTag1 `${ (x: number) => x }${ y => y }${ undefined }`;
|
||||
>tempTag1 : { <T>(templateStrs: TemplateStringsArray, f: (x: T) => T, x: T): T; <T>(templateStrs: TemplateStringsArray, f: (x: T) => T, h: (y: T) => T, x: T): T; }
|
||||
>(x: number) => x : (x: number) => number
|
||||
>x : number
|
||||
>x : number
|
||||
>y => y : (y: number) => number
|
||||
>y : number
|
||||
>y : number
|
||||
>undefined : undefined
|
||||
|
||||
function tempTag2(templateStrs: TemplateStringsArray, f: (x: number) => number, x: number): number;
|
||||
>tempTag2 : { (templateStrs: TemplateStringsArray, f: (x: number) => number, x: number): number; (templateStrs: TemplateStringsArray, f: (x: string) => string, h: (y: string) => string, x: string): string; }
|
||||
>templateStrs : TemplateStringsArray
|
||||
>TemplateStringsArray : TemplateStringsArray
|
||||
>f : (x: number) => number
|
||||
>x : number
|
||||
>x : number
|
||||
|
||||
function tempTag2(templateStrs: TemplateStringsArray, f: (x: string) => string, h: (y: string) => string, x: string): string;
|
||||
>tempTag2 : { (templateStrs: TemplateStringsArray, f: (x: number) => number, x: number): number; (templateStrs: TemplateStringsArray, f: (x: string) => string, h: (y: string) => string, x: string): string; }
|
||||
>templateStrs : TemplateStringsArray
|
||||
>TemplateStringsArray : TemplateStringsArray
|
||||
>f : (x: string) => string
|
||||
>x : string
|
||||
>h : (y: string) => string
|
||||
>y : string
|
||||
>x : string
|
||||
|
||||
function tempTag2(...rest: any[]): any {
|
||||
>tempTag2 : { (templateStrs: TemplateStringsArray, f: (x: number) => number, x: number): number; (templateStrs: TemplateStringsArray, f: (x: string) => string, h: (y: string) => string, x: string): string; }
|
||||
>rest : any[]
|
||||
|
||||
return undefined;
|
||||
>undefined : undefined
|
||||
}
|
||||
|
||||
tempTag2 `${ x => x }${ 0 }`;
|
||||
>tempTag2 : { (templateStrs: TemplateStringsArray, f: (x: number) => number, x: number): number; (templateStrs: TemplateStringsArray, f: (x: string) => string, h: (y: string) => string, x: string): string; }
|
||||
>x => x : (x: number) => number
|
||||
>x : number
|
||||
>x : number
|
||||
|
||||
tempTag2 `${ x => x }${ y => y }${ "hello" }`;
|
||||
>tempTag2 : { (templateStrs: TemplateStringsArray, f: (x: number) => number, x: number): number; (templateStrs: TemplateStringsArray, f: (x: string) => string, h: (y: string) => string, x: string): string; }
|
||||
>x => x : (x: string) => string
|
||||
>x : string
|
||||
>x : string
|
||||
>y => y : (y: string) => string
|
||||
>y : string
|
||||
>y : string
|
||||
|
||||
tempTag2 `${ x => x }${ 0 }`;
|
||||
>tempTag2 : { (templateStrs: TemplateStringsArray, f: (x: number) => number, x: number): number; (templateStrs: TemplateStringsArray, f: (x: string) => string, h: (y: string) => string, x: string): string; }
|
||||
>x => x : (x: number) => number
|
||||
>x : number
|
||||
>x : number
|
||||
|
||||
@ -0,0 +1,22 @@
|
||||
// @target: ES6
|
||||
|
||||
function tempTag1<T>(templateStrs: TemplateStringsArray, f: (x: T) => T, x: T): T;
|
||||
function tempTag1<T>(templateStrs: TemplateStringsArray, f: (x: T) => T, h: (y: T) => T, x: T): T;
|
||||
function tempTag1<T>(...rest: any[]): T {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
tempTag1 `${ x => x }${ 10 }`;
|
||||
tempTag1 `${ x => x }${ y => y }${ 10 }`;
|
||||
tempTag1 `${ x => x }${ (y: number) => y }${ undefined }`;
|
||||
tempTag1 `${ (x: number) => x }${ y => y }${ undefined }`;
|
||||
|
||||
function tempTag2(templateStrs: TemplateStringsArray, f: (x: number) => number, x: number): number;
|
||||
function tempTag2(templateStrs: TemplateStringsArray, f: (x: string) => string, h: (y: string) => string, x: string): string;
|
||||
function tempTag2(...rest: any[]): any {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
tempTag2 `${ x => x }${ 0 }`;
|
||||
tempTag2 `${ x => x }${ y => y }${ "hello" }`;
|
||||
tempTag2 `${ x => x }${ 0 }`;
|
||||
@ -0,0 +1,44 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
////function tempTag1<T>(templateStrs: TemplateStringsArray, f: (x: T) => T, x: T): T;
|
||||
////function tempTag1<T>(templateStrs: TemplateStringsArray, f: (x: T) => T, h: (y: T) => T, x: T): T;
|
||||
////function tempTag1<T>(...rest: any[]): T {
|
||||
//// return undefined;
|
||||
////}
|
||||
////
|
||||
////tempTag1 `${ x => /*0*/x }${ 10 }`;
|
||||
////tempTag1 `${ x => /*1*/x }${ x => /*2*/x }${ 10 }`;
|
||||
////tempTag1 `${ x => /*3*/x }${ (x: number) => /*4*/x }${ undefined }`;
|
||||
////tempTag1 `${ (x: number) => /*5*/x }${ x => /*6*/x }${ undefined }`;
|
||||
////
|
||||
////function tempTag2(templateStrs: TemplateStringsArray, f: (x: number) => number, x: number): number;
|
||||
////function tempTag2(templateStrs: TemplateStringsArray, f: (x: string) => string, h: (y: string) => string, x: string): string;
|
||||
////function tempTag2(...rest: any[]): any {
|
||||
//// return undefined;
|
||||
////}
|
||||
////
|
||||
////tempTag2 `${ x => /*7*/x }${ 0 }`;
|
||||
////tempTag2 `${ x => /*8*/x }${ undefined }`;
|
||||
////tempTag2 `${ x => /*9*/x }${ x => /*10*/x }${ "hello" }`;
|
||||
////tempTag2 `${ x => /*11*/x }${ undefined }${ "hello" }`;
|
||||
|
||||
// The first group of parameters, [0, 8], should all be contextually typed as 'number'.
|
||||
// The second group, [9, 11], should be typed as 'string'.
|
||||
var numTypedVariableCount = 9;
|
||||
var strTypedVariableCount = 3;
|
||||
|
||||
var markers = test.markers();
|
||||
|
||||
if (numTypedVariableCount + strTypedVariableCount !== markers.length) {
|
||||
throw "Unexpected number of markers in file.";
|
||||
}
|
||||
|
||||
for (var i = 0; i < numTypedVariableCount; i++) {
|
||||
goTo.marker("" + i);
|
||||
verify.quickInfoIs("(parameter) x: number");
|
||||
}
|
||||
|
||||
for (var i = 0; i < strTypedVariableCount; i++) {
|
||||
goTo.marker("" + (i + numTypedVariableCount));
|
||||
verify.quickInfoIs("(parameter) x: string");
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user