Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 31 additions & 3 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8520,6 +8520,20 @@ namespace ts {
function getContextuallyTypedParameterType(parameter: ParameterDeclaration): Type {
const func = parameter.parent;
if (isContextSensitiveFunctionOrObjectLiteralMethod(func)) {
const iife = getImmediatelyInvokedFunctionExpression(func);
if (iife) {
const indexOfParameter = indexOf(func.parameters, parameter);
if (iife.arguments && indexOfParameter < iife.arguments.length) {
if (parameter.dotDotDotToken) {
const restTypes: Type[] = [];
for (let i = indexOfParameter; i < iife.arguments.length; i++) {
restTypes.push(getTypeOfExpression(iife.arguments[i]));
}
return createArrayType(getUnionType(restTypes));
}
return checkExpression(iife.arguments[indexOfParameter]);
}
}
const contextualSignature = getContextualSignature(func);
if (contextualSignature) {
const funcHasRestParameters = hasRestParameter(func);
Expand All @@ -8540,6 +8554,20 @@ namespace ts {
return undefined;
}

function getImmediatelyInvokedFunctionExpression(func: FunctionExpression | MethodDeclaration) {
if (isFunctionExpressionOrArrowFunction(func)) {
let prev: Node = func;
let parent: Node = func.parent;
while (parent.kind === SyntaxKind.ParenthesizedExpression) {
prev = parent;
parent = parent.parent;
}
if (parent.kind === SyntaxKind.CallExpression && (parent as CallExpression).expression === prev) {
return parent as CallExpression;
}
}
}

// In a variable, parameter or property declaration with a type annotation,
// the contextual type of an initializer expression is the type of the variable, parameter or property.
// Otherwise, in a parameter declaration of a contextually typed function expression,
Expand Down Expand Up @@ -8898,9 +8926,9 @@ namespace ts {
}

function getContextualTypeForFunctionLikeDeclaration(node: FunctionExpression | MethodDeclaration) {
return isObjectLiteralMethod(node)
? getContextualTypeForObjectLiteralMethod(node)
: getApparentTypeOfContextualType(node);
return isObjectLiteralMethod(node) ?
getContextualTypeForObjectLiteralMethod(node) :
getApparentTypeOfContextualType(node);
}

// Return the contextual signature for a given expression node. A contextual type provides a
Expand Down
104 changes: 104 additions & 0 deletions tests/baselines/reference/contextuallyTypedIife.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
//// [contextuallyTypedIife.ts]
// arrow
(jake => { })("build");
// function expression
(function (cats) { })("lol");
// Lots of Irritating Superfluous Parentheses
(function (x) { } ("!"));
((((function (y) { }))))("-");
// multiple arguments
((a, b, c) => { })("foo", 101, false);
// default parameters
((m = 10) => m + 1)(12);
((n = 10) => n + 1)();
// optional parameters
((j?) => j + 1)(12);
((k?) => k + 1)();
((l, o?) => l + o)(12); // o should be any
// rest parameters
((...numbers) => numbers.every(n => n > 0))(5,6,7);
((...mixed) => mixed.every(n => !!n))(5,'oops','oh no');
((...noNumbers) => noNumbers.some(n => n > 0))();
((first, ...rest) => first ? [] : rest.map(n => n > 0))(8,9,10);
// destructuring parameters (with defaults too!)
(({ q }) => q)({ q : 13 });
(({ p = 14 }) => p)({ p : 15 });
(({ r = 17 } = { r: 18 }) => r)({r : 19});
(({ u = 22 } = { u: 23 }) => u)();
// contextually typed parameters.
let twelve = (f => f(12))(i => i);
let eleven = (o => o.a(11))({ a: function(n) { return n; } });


//// [contextuallyTypedIife.js]
// arrow
(function (jake) { })("build");
// function expression
(function (cats) { })("lol");
// Lots of Irritating Superfluous Parentheses
(function (x) { }("!"));
((((function (y) { }))))("-");
// multiple arguments
(function (a, b, c) { })("foo", 101, false);
// default parameters
(function (m) {
if (m === void 0) { m = 10; }
return m + 1;
})(12);
(function (n) {
if (n === void 0) { n = 10; }
return n + 1;
})();
// optional parameters
(function (j) { return j + 1; })(12);
(function (k) { return k + 1; })();
(function (l, o) { return l + o; })(12); // o should be any
// rest parameters
(function () {
var numbers = [];
for (var _i = 0; _i < arguments.length; _i++) {
numbers[_i - 0] = arguments[_i];
}
return numbers.every(function (n) { return n > 0; });
})(5, 6, 7);
(function () {
var mixed = [];
for (var _i = 0; _i < arguments.length; _i++) {
mixed[_i - 0] = arguments[_i];
}
return mixed.every(function (n) { return !!n; });
})(5, 'oops', 'oh no');
(function () {
var noNumbers = [];
for (var _i = 0; _i < arguments.length; _i++) {
noNumbers[_i - 0] = arguments[_i];
}
return noNumbers.some(function (n) { return n > 0; });
})();
(function (first) {
var rest = [];
for (var _i = 1; _i < arguments.length; _i++) {
rest[_i - 1] = arguments[_i];
}
return first ? [] : rest.map(function (n) { return n > 0; });
})(8, 9, 10);
// destructuring parameters (with defaults too!)
(function (_a) {
var q = _a.q;
return q;
})({ q: 13 });
(function (_a) {
var _b = _a.p, p = _b === void 0 ? 14 : _b;
return p;
})({ p: 15 });
(function (_a) {
var _b = (_a === void 0 ? { r: 18 } : _a).r, r = _b === void 0 ? 17 : _b;
return r;
})({ r: 19 });
(function (_a) {
var _b = (_a === void 0 ? { u: 23 } : _a).u, u = _b === void 0 ? 22 : _b;
return u;
})();
// contextually typed parameters.
var twelve = (function (f) { return f(12); })(function (i) { return i; });
var eleven = (function (o) { return o.a(11); })({ a: function (n) { return n; } });
121 changes: 121 additions & 0 deletions tests/baselines/reference/contextuallyTypedIife.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
=== tests/cases/conformance/expressions/functions/contextuallyTypedIife.ts ===
// arrow
(jake => { })("build");
>jake : Symbol(jake, Decl(contextuallyTypedIife.ts, 1, 1))

// function expression
(function (cats) { })("lol");
>cats : Symbol(cats, Decl(contextuallyTypedIife.ts, 3, 11))

// Lots of Irritating Superfluous Parentheses
(function (x) { } ("!"));
>x : Symbol(x, Decl(contextuallyTypedIife.ts, 5, 11))

((((function (y) { }))))("-");
>y : Symbol(y, Decl(contextuallyTypedIife.ts, 6, 14))

// multiple arguments
((a, b, c) => { })("foo", 101, false);
>a : Symbol(a, Decl(contextuallyTypedIife.ts, 8, 2))
>b : Symbol(b, Decl(contextuallyTypedIife.ts, 8, 4))
>c : Symbol(c, Decl(contextuallyTypedIife.ts, 8, 7))

// default parameters
((m = 10) => m + 1)(12);
>m : Symbol(m, Decl(contextuallyTypedIife.ts, 10, 2))
>m : Symbol(m, Decl(contextuallyTypedIife.ts, 10, 2))

((n = 10) => n + 1)();
>n : Symbol(n, Decl(contextuallyTypedIife.ts, 11, 2))
>n : Symbol(n, Decl(contextuallyTypedIife.ts, 11, 2))

// optional parameters
((j?) => j + 1)(12);
>j : Symbol(j, Decl(contextuallyTypedIife.ts, 13, 2))
>j : Symbol(j, Decl(contextuallyTypedIife.ts, 13, 2))

((k?) => k + 1)();
>k : Symbol(k, Decl(contextuallyTypedIife.ts, 14, 2))
>k : Symbol(k, Decl(contextuallyTypedIife.ts, 14, 2))

((l, o?) => l + o)(12); // o should be any
>l : Symbol(l, Decl(contextuallyTypedIife.ts, 15, 2))
>o : Symbol(o, Decl(contextuallyTypedIife.ts, 15, 4))
>l : Symbol(l, Decl(contextuallyTypedIife.ts, 15, 2))
>o : Symbol(o, Decl(contextuallyTypedIife.ts, 15, 4))

// rest parameters
((...numbers) => numbers.every(n => n > 0))(5,6,7);
>numbers : Symbol(numbers, Decl(contextuallyTypedIife.ts, 17, 2))
>numbers.every : Symbol(Array.every, Decl(lib.d.ts, --, --))
>numbers : Symbol(numbers, Decl(contextuallyTypedIife.ts, 17, 2))
>every : Symbol(Array.every, Decl(lib.d.ts, --, --))
>n : Symbol(n, Decl(contextuallyTypedIife.ts, 17, 31))
>n : Symbol(n, Decl(contextuallyTypedIife.ts, 17, 31))

((...mixed) => mixed.every(n => !!n))(5,'oops','oh no');
>mixed : Symbol(mixed, Decl(contextuallyTypedIife.ts, 18, 2))
>mixed.every : Symbol(Array.every, Decl(lib.d.ts, --, --))
>mixed : Symbol(mixed, Decl(contextuallyTypedIife.ts, 18, 2))
>every : Symbol(Array.every, Decl(lib.d.ts, --, --))
>n : Symbol(n, Decl(contextuallyTypedIife.ts, 18, 27))
>n : Symbol(n, Decl(contextuallyTypedIife.ts, 18, 27))

((...noNumbers) => noNumbers.some(n => n > 0))();
>noNumbers : Symbol(noNumbers, Decl(contextuallyTypedIife.ts, 19, 2))
>noNumbers.some : Symbol(Array.some, Decl(lib.d.ts, --, --))
>noNumbers : Symbol(noNumbers, Decl(contextuallyTypedIife.ts, 19, 2))
>some : Symbol(Array.some, Decl(lib.d.ts, --, --))
>n : Symbol(n, Decl(contextuallyTypedIife.ts, 19, 34))
>n : Symbol(n, Decl(contextuallyTypedIife.ts, 19, 34))

((first, ...rest) => first ? [] : rest.map(n => n > 0))(8,9,10);
>first : Symbol(first, Decl(contextuallyTypedIife.ts, 20, 2))
>rest : Symbol(rest, Decl(contextuallyTypedIife.ts, 20, 8))
>first : Symbol(first, Decl(contextuallyTypedIife.ts, 20, 2))
>rest.map : Symbol(Array.map, Decl(lib.d.ts, --, --))
>rest : Symbol(rest, Decl(contextuallyTypedIife.ts, 20, 8))
>map : Symbol(Array.map, Decl(lib.d.ts, --, --))
>n : Symbol(n, Decl(contextuallyTypedIife.ts, 20, 43))
>n : Symbol(n, Decl(contextuallyTypedIife.ts, 20, 43))

// destructuring parameters (with defaults too!)
(({ q }) => q)({ q : 13 });
>q : Symbol(q, Decl(contextuallyTypedIife.ts, 22, 3))
>q : Symbol(q, Decl(contextuallyTypedIife.ts, 22, 3))
>q : Symbol(q, Decl(contextuallyTypedIife.ts, 22, 16))

(({ p = 14 }) => p)({ p : 15 });
>p : Symbol(p, Decl(contextuallyTypedIife.ts, 23, 3))
>p : Symbol(p, Decl(contextuallyTypedIife.ts, 23, 3))
>p : Symbol(p, Decl(contextuallyTypedIife.ts, 23, 21))

(({ r = 17 } = { r: 18 }) => r)({r : 19});
>r : Symbol(r, Decl(contextuallyTypedIife.ts, 24, 3))
>r : Symbol(r, Decl(contextuallyTypedIife.ts, 24, 16))
>r : Symbol(r, Decl(contextuallyTypedIife.ts, 24, 3))
>r : Symbol(r, Decl(contextuallyTypedIife.ts, 24, 33))

(({ u = 22 } = { u: 23 }) => u)();
>u : Symbol(u, Decl(contextuallyTypedIife.ts, 25, 3))
>u : Symbol(u, Decl(contextuallyTypedIife.ts, 25, 16))
>u : Symbol(u, Decl(contextuallyTypedIife.ts, 25, 3))

// contextually typed parameters.
let twelve = (f => f(12))(i => i);
>twelve : Symbol(twelve, Decl(contextuallyTypedIife.ts, 27, 3))
>f : Symbol(f, Decl(contextuallyTypedIife.ts, 27, 14))
>f : Symbol(f, Decl(contextuallyTypedIife.ts, 27, 14))
>i : Symbol(i, Decl(contextuallyTypedIife.ts, 27, 26))
>i : Symbol(i, Decl(contextuallyTypedIife.ts, 27, 26))

let eleven = (o => o.a(11))({ a: function(n) { return n; } });
>eleven : Symbol(eleven, Decl(contextuallyTypedIife.ts, 28, 3))
>o : Symbol(o, Decl(contextuallyTypedIife.ts, 28, 14))
>o.a : Symbol(a, Decl(contextuallyTypedIife.ts, 28, 29))
>o : Symbol(o, Decl(contextuallyTypedIife.ts, 28, 14))
>a : Symbol(a, Decl(contextuallyTypedIife.ts, 28, 29))
>a : Symbol(a, Decl(contextuallyTypedIife.ts, 28, 29))
>n : Symbol(n, Decl(contextuallyTypedIife.ts, 28, 42))
>n : Symbol(n, Decl(contextuallyTypedIife.ts, 28, 42))

Loading