mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Type check for bind, polish emit for pipeline
This commit is contained in:
+78
-17
@@ -4304,6 +4304,17 @@ namespace ts {
|
||||
sig.typePredicate, sig.minArgumentCount, sig.hasRestParameter, sig.hasLiteralTypes);
|
||||
}
|
||||
|
||||
function getSignatureWithoutThis(sig: Signature) {
|
||||
if (sig.thisParameter) {
|
||||
if (!sig.thisFreeSignatureCache) {
|
||||
sig.thisFreeSignatureCache = cloneSignature(sig);
|
||||
sig.thisFreeSignatureCache.thisParameter = undefined;
|
||||
}
|
||||
return sig.thisFreeSignatureCache;
|
||||
}
|
||||
return sig;
|
||||
}
|
||||
|
||||
function getDefaultConstructSignatures(classType: InterfaceType): Signature[] {
|
||||
const baseConstructorType = getBaseConstructorTypeOfClass(classType);
|
||||
const baseSignatures = getSignaturesOfType(baseConstructorType, SignatureKind.Construct);
|
||||
@@ -5195,6 +5206,25 @@ namespace ts {
|
||||
return signature.erasedSignatureCache;
|
||||
}
|
||||
|
||||
function createTypeFromSignatures(signatures: Signature[]): ObjectType {
|
||||
const type = <ResolvedType>createObjectType(ObjectFlags.Anonymous);
|
||||
type.members = emptySymbols;
|
||||
type.properties = emptyArray;
|
||||
let callSignatures: Signature[];
|
||||
let constructSignatures: Signature[];
|
||||
for (const signature of signatures) {
|
||||
if (signature.isConstruct) {
|
||||
constructSignatures = append(constructSignatures, signature);
|
||||
}
|
||||
else {
|
||||
callSignatures = append(callSignatures, signature);
|
||||
}
|
||||
}
|
||||
type.callSignatures = callSignatures || emptyArray;
|
||||
type.constructSignatures = constructSignatures || emptyArray;
|
||||
return type;
|
||||
}
|
||||
|
||||
function getOrCreateTypeFromSignature(signature: Signature): ObjectType {
|
||||
// There are two ways to declare a construct signature, one is by declaring a class constructor
|
||||
// using the constructor keyword, and the other is declaring a bare construct signature in an
|
||||
@@ -12186,6 +12216,12 @@ namespace ts {
|
||||
return getIndexedAccessType(objectType, indexType, node);
|
||||
}
|
||||
|
||||
function checkBindExpression(node: BindExpression): Type {
|
||||
checkNonNullExpression(node.expression);
|
||||
const signatures = getResolvedPartialSignatures(node);
|
||||
return createTypeFromSignatures(map(signatures, getSignatureWithoutThis));
|
||||
}
|
||||
|
||||
function checkThatExpressionIsProperSymbolReference(expression: Expression, expressionType: Type, reportError: boolean): boolean {
|
||||
if (expressionType === unknownType) {
|
||||
// There is already an error, so no need to report one.
|
||||
@@ -12232,7 +12268,7 @@ namespace ts {
|
||||
if (node.kind === SyntaxKind.TaggedTemplateExpression) {
|
||||
checkExpression((<TaggedTemplateExpression>node).template);
|
||||
}
|
||||
else if (node.kind !== SyntaxKind.Decorator) {
|
||||
else if (node.kind === SyntaxKind.CallExpression || node.kind === SyntaxKind.NewExpression) {
|
||||
forEach((<CallExpression>node).arguments, argument => {
|
||||
checkExpression(argument);
|
||||
});
|
||||
@@ -12313,7 +12349,6 @@ namespace ts {
|
||||
let argCount: number; // Apparent number of arguments we will have in this call
|
||||
let typeArguments: NodeArray<TypeNode>; // Type arguments (undefined if none)
|
||||
let callIsIncomplete: boolean; // In incomplete call we want to be lenient when we have too few arguments
|
||||
let isDecorator: boolean;
|
||||
let spreadArgIndex = -1;
|
||||
|
||||
if (node.kind === SyntaxKind.TaggedTemplateExpression) {
|
||||
@@ -12341,8 +12376,7 @@ namespace ts {
|
||||
callIsIncomplete = !!templateLiteral.isUnterminated;
|
||||
}
|
||||
}
|
||||
else if (node.kind === SyntaxKind.Decorator) {
|
||||
isDecorator = true;
|
||||
else if (node.kind === SyntaxKind.Decorator || node.kind === SyntaxKind.BindExpression) {
|
||||
typeArguments = undefined;
|
||||
argCount = getEffectiveArgumentCount(node, /*args*/ undefined, signature);
|
||||
}
|
||||
@@ -12574,6 +12608,9 @@ namespace ts {
|
||||
return (callee as ElementAccessExpression).expression;
|
||||
}
|
||||
}
|
||||
else if (node.kind === SyntaxKind.BindExpression) {
|
||||
return node.expression;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -12596,7 +12633,7 @@ namespace ts {
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (node.kind === SyntaxKind.Decorator) {
|
||||
else if (node.kind === SyntaxKind.Decorator || 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.
|
||||
@@ -12675,6 +12712,9 @@ namespace ts {
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
else if (node.kind === SyntaxKind.BindExpression) {
|
||||
return signature.minArgumentCount;
|
||||
}
|
||||
else {
|
||||
return args.length;
|
||||
}
|
||||
@@ -12859,6 +12899,9 @@ namespace ts {
|
||||
if (node.kind === SyntaxKind.Decorator) {
|
||||
return getEffectiveDecoratorArgumentType(<Decorator>node, argIndex);
|
||||
}
|
||||
else if (node.kind === SyntaxKind.BindExpression) {
|
||||
return unknownType;
|
||||
}
|
||||
else if (argIndex === 0 && node.kind === SyntaxKind.TaggedTemplateExpression) {
|
||||
return getGlobalTemplateStringsArrayType();
|
||||
}
|
||||
@@ -12874,6 +12917,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.BindExpression ||
|
||||
(argIndex === 0 && node.kind === SyntaxKind.TaggedTemplateExpression)) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -12902,10 +12946,11 @@ namespace ts {
|
||||
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) {
|
||||
if (!isTaggedTemplate && !isDecorator && !isPipeline && !isBind) {
|
||||
typeArguments = (<CallExpression>node).typeArguments;
|
||||
|
||||
// We already perform checking on the type arguments on the class declaration itself.
|
||||
@@ -12939,7 +12984,7 @@ 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) {
|
||||
if (!isDecorator && !isBind) {
|
||||
// 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++) {
|
||||
@@ -13420,7 +13465,6 @@ namespace ts {
|
||||
}
|
||||
|
||||
function resolvePipelineExpression(node: PipelineExpression, candidatesOutArray: Signature[]): Signature {
|
||||
(<any>Error).stackTraceLimit = Infinity;
|
||||
const funcType = checkExpression(node.right);
|
||||
const apparentType = getApparentType(funcType);
|
||||
if (apparentType === unknownType) {
|
||||
@@ -13440,6 +13484,26 @@ namespace ts {
|
||||
return resolveCall(node, callSignatures, /*partialSignaturesOutArray*/ undefined, candidatesOutArray);
|
||||
}
|
||||
|
||||
function resolveBindExpression(node: BindExpression, partialSignaturesOutArray: Signature[], candidatesOutArray?: Signature[]): Signature {
|
||||
const funcType = checkExpression(node.targetExpression);
|
||||
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 resolveSignature(node: CallLikeExpression, partialSignaturesOutArray: Signature[], candidatesOutArray?: Signature[]): Signature {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.CallExpression:
|
||||
@@ -13452,6 +13516,8 @@ namespace ts {
|
||||
return resolveDecorator(<Decorator>node, candidatesOutArray);
|
||||
case SyntaxKind.BinaryExpression:
|
||||
return resolvePipelineExpression(<PipelineExpression>node, candidatesOutArray);
|
||||
case SyntaxKind.BindExpression:
|
||||
return resolveBindExpression(<BindExpression>node, partialSignaturesOutArray, candidatesOutArray);
|
||||
}
|
||||
Debug.fail("Branch in 'resolveSignature' should be unreachable.");
|
||||
}
|
||||
@@ -14238,19 +14304,12 @@ namespace ts {
|
||||
function createOperatorExpressionType(operator: SyntaxKind) {
|
||||
switch (operator) {
|
||||
case SyntaxKind.PlusToken:
|
||||
const signatures = [
|
||||
return createTypeFromSignatures([
|
||||
createBinaryOperatorSignature(undefined, stringType, stringType, stringType),
|
||||
createBinaryOperatorSignature(undefined, stringType, numberType, stringType),
|
||||
createBinaryOperatorSignature(undefined, numberType, stringType, stringType),
|
||||
createBinaryOperatorSignature(undefined, numberType, numberType, numberType),
|
||||
]
|
||||
const plusType = createObjectType(ObjectFlags.Anonymous);
|
||||
(<ResolvedType>plusType).members = emptySymbols;
|
||||
(<ResolvedType>plusType).properties = emptyArray;
|
||||
(<ResolvedType>plusType).callSignatures = signatures;
|
||||
(<ResolvedType>plusType).constructSignatures = emptyArray;
|
||||
return plusType;
|
||||
|
||||
]);
|
||||
case SyntaxKind.AsteriskToken:
|
||||
case SyntaxKind.AsteriskAsteriskToken:
|
||||
case SyntaxKind.SlashToken:
|
||||
@@ -15249,6 +15308,8 @@ namespace ts {
|
||||
return checkPropertyAccessExpression(<PropertyAccessExpression>node);
|
||||
case SyntaxKind.ElementAccessExpression:
|
||||
return checkIndexedAccess(<ElementAccessExpression>node);
|
||||
case SyntaxKind.BindExpression:
|
||||
return checkBindExpression(<BindExpression>node);
|
||||
case SyntaxKind.CallExpression:
|
||||
case SyntaxKind.NewExpression:
|
||||
return checkCallExpression(<CallExpression>node);
|
||||
|
||||
@@ -161,6 +161,9 @@ namespace ts {
|
||||
case SyntaxKind.ElementAccessExpression:
|
||||
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);
|
||||
case SyntaxKind.CallExpression:
|
||||
case SyntaxKind.NewExpression:
|
||||
return visitNode(cbNode, (<CallExpression>node).expression) ||
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
namespace ts {
|
||||
export function transformESNext(context: TransformationContext) {
|
||||
const {
|
||||
startLexicalEnvironment,
|
||||
resumeLexicalEnvironment,
|
||||
endLexicalEnvironment
|
||||
endLexicalEnvironment,
|
||||
hoistVariableDeclaration,
|
||||
} = context;
|
||||
return transformSourceFile;
|
||||
|
||||
@@ -441,60 +441,64 @@ namespace ts {
|
||||
}
|
||||
|
||||
function visitCallExpression(node: CallExpression): Expression {
|
||||
const expression = visitNode(node.expression, visitor, isExpression);
|
||||
let position = 0;
|
||||
let positionalParameters: ParameterDeclaration[];
|
||||
let positionalRestParameter: ParameterDeclaration;
|
||||
let argumentList: Expression[];
|
||||
for (let i = 0; i < node.arguments.length; i++) {
|
||||
const argument = node.arguments[i];
|
||||
let updated: Expression;
|
||||
if (isPositionalElement(argument)) {
|
||||
if (!positionalParameters) {
|
||||
positionalParameters = [];
|
||||
}
|
||||
if (argument.literal) {
|
||||
position = +argument.literal.text;
|
||||
}
|
||||
const parameter = positionalParameters[position] || (positionalParameters[position] = createParameter());
|
||||
updated = <Identifier>parameter.name;
|
||||
position++;
|
||||
}
|
||||
else if (isPositionalSpreadElement(argument)) {
|
||||
const parameter = positionalRestParameter || (positionalRestParameter = createParameter(/*decorators*/ undefined, /*modifiers*/ undefined, createToken(SyntaxKind.DotDotDotToken)));
|
||||
updated = createSpreadElement(<Identifier>parameter.name);
|
||||
}
|
||||
else {
|
||||
updated = visitNode(argument, visitor, isExpression);
|
||||
}
|
||||
if (argumentList || updated !== argument) {
|
||||
if (!argumentList) {
|
||||
argumentList = node.arguments.slice(0, i);
|
||||
}
|
||||
argumentList.push(updated);
|
||||
}
|
||||
let expression = visitNode(node.expression, visitor, isExpression) as Expression;
|
||||
if (!forEach(node.arguments, isPositionalOrPositionalSpreadElement)) {
|
||||
return updateCall(
|
||||
node,
|
||||
expression,
|
||||
/*typeArguments*/ undefined,
|
||||
visitNodes(node.arguments, visitor, isExpression));
|
||||
}
|
||||
if (positionalParameters || positionalRestParameter) {
|
||||
startLexicalEnvironment();
|
||||
else {
|
||||
const expressionTemp = createTempVariable(hoistVariableDeclaration);
|
||||
const argumentList: Expression[] = [];
|
||||
const pendingExpressions: Expression[] = [createAssignment(expressionTemp, expression)];
|
||||
const positionalParameters: ParameterDeclaration[] = [];
|
||||
let positionalRestParameter: ParameterDeclaration;
|
||||
let position = 0;
|
||||
for (let i = 0; i < node.arguments.length; i++) {
|
||||
let argument = node.arguments[i];
|
||||
if (isPositionalElement(argument)) {
|
||||
if (argument.literal) {
|
||||
position = +argument.literal.text;
|
||||
}
|
||||
const parameter = positionalParameters[position] || (positionalParameters[position] = createParameter());
|
||||
argument = <Identifier>parameter.name;
|
||||
position++;
|
||||
}
|
||||
else if (isPositionalSpreadElement(argument)) {
|
||||
const parameter = positionalRestParameter || (positionalRestParameter = createParameter(/*decorators*/ undefined, /*modifiers*/ undefined, createToken(SyntaxKind.DotDotDotToken)));
|
||||
argument = createSpreadElement(<Identifier>parameter.name);
|
||||
}
|
||||
else {
|
||||
argument = visitNode(argument, visitor, isExpression);
|
||||
const temp = createTempVariable(hoistVariableDeclaration);
|
||||
pendingExpressions.push(createAssignment(temp, isSpreadElement(argument) ? argument.expression : argument));
|
||||
argument = isSpreadElement(argument) ? createSpreadElement(temp) : temp;
|
||||
}
|
||||
argumentList.push(argument);
|
||||
}
|
||||
if (positionalRestParameter) {
|
||||
positionalParameters = append(positionalParameters, positionalRestParameter);
|
||||
positionalParameters.push(positionalRestParameter);
|
||||
}
|
||||
for (let i = 0; i < positionalParameters.length; i++) {
|
||||
if (!positionalParameters[i]) {
|
||||
positionalParameters[i] = createParameter();
|
||||
}
|
||||
}
|
||||
return createArrowFunction(
|
||||
/*modifiers*/ undefined,
|
||||
/*typeParameters*/ undefined,
|
||||
positionalParameters,
|
||||
/*type*/ undefined,
|
||||
/*equalsGreaterThanToken*/ createToken(SyntaxKind.EqualsGreaterThanToken),
|
||||
updateCall(node, expression, /*typeArguments*/ undefined, argumentList || node.arguments),
|
||||
/*location*/ node
|
||||
pendingExpressions.push(
|
||||
createArrowFunction(
|
||||
/*modifiers*/ undefined,
|
||||
/*typeParameters*/ undefined,
|
||||
positionalParameters,
|
||||
/*type*/ undefined,
|
||||
/*equalsGreaterThanToken*/ createToken(SyntaxKind.EqualsGreaterThanToken),
|
||||
updateCall(node, expressionTemp, /*typeArguments*/ undefined, argumentList),
|
||||
/*location*/ node
|
||||
)
|
||||
);
|
||||
return inlineExpressions(pendingExpressions);
|
||||
}
|
||||
return updateCall(node, expression, /*typeArguments*/ undefined, argumentList || node.arguments);
|
||||
}
|
||||
|
||||
function visitOperatorExpression(node: OperatorExpression) {
|
||||
@@ -542,7 +546,7 @@ namespace ts {
|
||||
|
||||
function visitBindExpression(node: BindExpression) {
|
||||
const thisArg = createTempVariable(context.hoistVariableDeclaration);
|
||||
return inlineExpressions([
|
||||
return createComma(
|
||||
createAssignment(
|
||||
thisArg,
|
||||
visitNode(node.expression, visitor, isExpression),
|
||||
@@ -554,7 +558,7 @@ namespace ts {
|
||||
[],
|
||||
node
|
||||
)
|
||||
]);
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1456,7 +1456,7 @@ namespace ts {
|
||||
template: TemplateLiteral;
|
||||
}
|
||||
|
||||
export type CallLikeExpression = CallExpression | NewExpression | TaggedTemplateExpression | Decorator | PipelineExpression;
|
||||
export type CallLikeExpression = CallExpression | NewExpression | TaggedTemplateExpression | Decorator | PipelineExpression | BindExpression;
|
||||
|
||||
export interface PositionalElement extends Expression {
|
||||
kind: SyntaxKind.PositionalElement;
|
||||
@@ -3053,6 +3053,8 @@ namespace ts {
|
||||
/* @internal */
|
||||
erasedSignatureCache?: Signature; // Erased version of signature (deferred)
|
||||
/* @internal */
|
||||
thisFreeSignatureCache?: Signature; // Signature without 'this' parameter.
|
||||
/* @internal */
|
||||
isolatedSignatureType?: ObjectType; // A manufactured type that just contains the signature for purposes of signature comparison
|
||||
/* @internal */
|
||||
typePredicate?: TypePredicate;
|
||||
|
||||
Reference in New Issue
Block a user