Improve type check, add baselines

This commit is contained in:
Ron Buckton 2016-11-26 04:55:05 -05:00
parent 24f3794952
commit dba5c2bf87
18 changed files with 1529 additions and 339 deletions

View File

@ -865,7 +865,8 @@ namespace ts {
else {
return node.kind === SyntaxKind.BinaryExpression && (
(<BinaryExpression>node).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken ||
(<BinaryExpression>node).operatorToken.kind === SyntaxKind.BarBarToken);
(<BinaryExpression>node).operatorToken.kind === SyntaxKind.BarBarToken ||
(<BinaryExpression>node).operatorToken.kind === SyntaxKind.QuestionQuestionToken);
}
}
}
@ -1230,7 +1231,9 @@ namespace ts {
function bindBinaryExpressionFlow(node: BinaryExpression) {
const operator = node.operatorToken.kind;
if (operator === SyntaxKind.AmpersandAmpersandToken || operator === SyntaxKind.BarBarToken) {
if (operator === SyntaxKind.AmpersandAmpersandToken ||
operator === SyntaxKind.BarBarToken ||
operator === SyntaxKind.QuestionQuestionToken) {
if (isTopLevelLogicalExpression(node)) {
const postExpressionLabel = createBranchLabel();
bindLogicalExpression(node, postExpressionLabel, postExpressionLabel);
@ -2546,6 +2549,10 @@ namespace ts {
transformFlags |= TransformFlags.AssertTypeScript;
}
if (node.flags & NodeFlags.PropagateNull) {
transformFlags |= TransformFlags.AssertESNext;
}
if (subtreeFlags & TransformFlags.ContainsSpread
|| isSuperOrSuperProperty(expression, expressionKind)) {
// If the this node contains a SpreadExpression, or is a super call, then it is an ES6
@ -2577,6 +2584,9 @@ namespace ts {
if (node.typeArguments) {
transformFlags |= TransformFlags.AssertTypeScript;
}
if (node.flags & NodeFlags.PropagateNull) {
transformFlags |= TransformFlags.AssertESNext;
}
if (subtreeFlags & TransformFlags.ContainsSpread) {
// If the this node contains a SpreadElementExpression then it is an ES6
// node.
@ -2987,6 +2997,9 @@ namespace ts {
let transformFlags = subtreeFlags;
const expression = node.expression;
const expressionKind = expression.kind;
if (node.flags & NodeFlags.PropagateNull) {
transformFlags |= TransformFlags.AssertESNext;
}
// If a PropertyAccessExpression starts with a super keyword, then it is
// ES6 syntax, and requires a lexical `this` binding.
@ -3111,6 +3124,7 @@ namespace ts {
switch (kind) {
case SyntaxKind.BarGreaterThanToken:
case SyntaxKind.QuestionQuestionToken:
transformFlags |= TransformFlags.AssertESNext;
break;
@ -3315,6 +3329,12 @@ namespace ts {
break;
case SyntaxKind.ElementAccessExpression:
if (node.flags & NodeFlags.PropagateNull) {
transformFlags |= TransformFlags.AssertESNext;
}
break;
case SyntaxKind.DoStatement:
case SyntaxKind.WhileStatement:
case SyntaxKind.ForStatement:

View File

@ -163,7 +163,6 @@ namespace ts {
const unknownSignature = createSignature(undefined, undefined, undefined, emptyArray, unknownType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
const resolvingSignature = createSignature(undefined, undefined, undefined, emptyArray, anyType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
const silentNeverSignature = createSignature(undefined, undefined, undefined, emptyArray, silentNeverType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
const resolvingPartialSignatures: Signature[] = [];
const enumNumberIndexInfo = createIndexInfo(stringType, /*isReadonly*/ true);
const operatorExpressionTypes = createMap<Type>();
@ -2618,7 +2617,7 @@ namespace ts {
function buildParameterDisplay(p: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) {
const parameterNode = <ParameterDeclaration>p.valueDeclaration;
if ((isTransient(p) && p.transientSymbolIsRest) || isRestParameter(parameterNode)) {
if (isTransient(p) && typeof p.transientSymbolIsRest === "boolean" ? p.transientSymbolIsRest : isRestParameter(parameterNode)) {
writePunctuation(writer, SyntaxKind.DotDotDotToken);
}
if (parameterNode && isBindingPattern(parameterNode.name)) {
@ -8170,6 +8169,20 @@ namespace ts {
return strictNullChecks ? getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull) : type;
}
function propagateNullType(type: Type, propagatingType: Type) {
return propagatingType === neverType ? type : getUnionType([type, propagatingType]);
}
function propagateNullReturnType(signature: Signature, propagatingType: Type) {
if (propagatingType === neverType || isTypeAny(signature.resolvedReturnType)) {
return signature;
}
signature = cloneSignature(signature);
signature.resolvedReturnType = getUnionType([signature.resolvedReturnType, propagatingType]);
return signature;
}
/**
* Return true if type was inferred from an object literal or written as an object type literal
* with no call or construct signatures.
@ -11122,6 +11135,14 @@ namespace ts {
// with this type. It is neither affected by it, nor does it propagate it to its operand.
// So the fact that contextualMapper is passed is not important, because the operand of a spread
// element is not contextually typed.
if (node.expression.kind === SyntaxKind.OmittedExpression && (
node.parent.kind === SyntaxKind.CallExpression ||
node.parent.kind === SyntaxKind.NewExpression)) {
// positional spread in an argument list indicates partial application.
// we indicate `unknownType` here as the type is not known and should not
// introduce type errors.
return unknownType;
}
const arrayOrIterableType = checkExpressionCached(node.expression, contextualMapper);
return checkIteratedTypeOrElementType(arrayOrIterableType, node.expression, /*allowStringInput*/ false);
}
@ -12070,7 +12091,11 @@ namespace ts {
}
function checkPropertyAccessExpressionOrQualifiedName(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, right: Identifier) {
const type = checkNonNullExpression(left);
const propagateNull = node.flags & NodeFlags.PropagateNull;
const objectType = propagateNull ? checkExpression(left) : checkNonNullExpression(left);
const type = propagateNull ? getNonNullableType(objectType) : objectType;
const propagatingType = propagateNull ? getTypeWithFacts(objectType, TypeFacts.EQUndefinedOrNull) : neverType;
if (isTypeAny(type) || type === silentNeverType) {
return type;
}
@ -12112,10 +12137,10 @@ namespace ts {
if (node.kind !== SyntaxKind.PropertyAccessExpression || assignmentKind === AssignmentKind.Definite ||
!(prop.flags & (SymbolFlags.Variable | SymbolFlags.Property | SymbolFlags.Accessor)) &&
!(prop.flags & SymbolFlags.Method && propType.flags & TypeFlags.Union)) {
return propType;
return propagateNullType(propType, propagatingType);
}
const flowType = getFlowTypeOfReference(node, propType, /*assumeInitialized*/ true, /*flowContainer*/ undefined);
return assignmentKind ? getBaseTypeOfLiteralType(flowType) : flowType;
return propagateNullType(assignmentKind ? getBaseTypeOfLiteralType(flowType) : flowType, propagatingType);
}
function isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean {
@ -12184,7 +12209,10 @@ namespace ts {
}
function checkIndexedAccess(node: ElementAccessExpression): Type {
const objectType = checkNonNullExpression(node.expression);
const propagateNull = node.flags & NodeFlags.PropagateNull;
const objectType = propagateNull ? checkExpression(node.expression) : checkNonNullExpression(node.expression);
const type = propagateNull ? getNonNullableType(objectType) : objectType;
const propagatingType = propagateNull ? getTypeWithFacts(objectType, TypeFacts.EQUndefinedOrNull) : neverType;
const indexExpression = node.argumentExpression;
if (!indexExpression) {
@ -12204,27 +12232,24 @@ namespace ts {
const indexType = isForInVariableForNumericPropertyNames(indexExpression) ? numberType : checkExpression(indexExpression);
if (objectType === unknownType || objectType === silentNeverType) {
return objectType;
if (type === unknownType || type === silentNeverType) {
return type;
}
if (isConstEnumObjectType(objectType) && indexExpression.kind !== SyntaxKind.StringLiteral) {
if (isConstEnumObjectType(type) && indexExpression.kind !== SyntaxKind.StringLiteral) {
error(indexExpression, Diagnostics.A_const_enum_member_can_only_be_accessed_using_a_string_literal);
return unknownType;
}
return getIndexedAccessType(objectType, indexType, node);
return propagateNullType(getIndexedAccessType(type, indexType, node), propagatingType);
}
function checkBindExpression(node: BindExpression | BindToExpression): Type {
if (node.kind === SyntaxKind.BindToExpression) {
checkNonNullExpression(node.targetExpression);
const signature = getResolvedSignature(node);
if (signature === unknownSignature) {
return unknownType;
}
const signatures = getResolvedPartialSignatures(node);
if (signatures.length === 0 || singleOrUndefined(signatures) === unknownSignature) {
return unknownType
}
return createTypeFromSignatures(map(signatures, getSignatureWithoutThis));
return getReturnTypeOfSignature(signature);
}
function checkThatExpressionIsProperSymbolReference(expression: Expression, expressionType: Type, reportError: boolean): boolean {
@ -12269,7 +12294,7 @@ namespace ts {
return true;
}
function resolveUntypedCall(node: CallLikeExpression, partialSignaturesOutArray: Signature[]): Signature {
function resolveUntypedCall(node: CallLikeExpression): Signature {
if (node.kind === SyntaxKind.TaggedTemplateExpression) {
checkExpression((<TaggedTemplateExpression>node).template);
}
@ -12278,17 +12303,11 @@ namespace ts {
checkExpression(argument);
});
}
if (partialSignaturesOutArray) {
partialSignaturesOutArray.push(anySignature);
}
return anySignature;
}
function resolveErrorCall(node: CallLikeExpression, partialSignaturesOutArray: Signature[]): Signature {
resolveUntypedCall(node, /*partialSignaturesOutArray*/ undefined);
if (partialSignaturesOutArray) {
partialSignaturesOutArray.push(unknownSignature);
}
function resolveErrorCall(node: CallLikeExpression): Signature {
resolveUntypedCall(node);
return unknownSignature;
}
@ -12655,20 +12674,57 @@ namespace ts {
return undefined;
}
else if (node.kind === SyntaxKind.BinaryExpression) {
let expression = (<PipelineExpression>node).left;
const expression = (<PipelineExpression>node).left;
const pipelineArguments: Expression[] = [];
if (expression.kind === SyntaxKind.ParenthesizedExpression) {
// comma expressions are right-deep
args = [];
expression = (<ParenthesizedExpression>expression).expression;
while (expression.kind === SyntaxKind.BinaryExpression &&
(<BinaryExpression>expression).operatorToken.kind === SyntaxKind.CommaToken) {
args.push((<BinaryExpression>expression).left);
expression = (<BinaryExpression>expression).right;
}
args.push(expression);
collectPipelineArguments((<ParenthesizedExpression>expression).expression, pipelineArguments);
}
else {
args = [expression];
pipelineArguments.push(expression);
}
if (isPartialApplication(node.right)) {
const argumentList = node.right.arguments;
const positionalOffsetMap = new Array<number>(argumentList.length);
let numFreePositions = 0;
let maxFixedPosition = -1;
for (let i = 0; i < argumentList.length; i++) {
const argument = argumentList[i];
if (isPositionalElement(argument)) {
if (argument.literal) {
const fixedPosition = +argument.literal.text | 0;
if (maxFixedPosition < fixedPosition) {
maxFixedPosition = fixedPosition;
}
positionalOffsetMap[i] = fixedPosition;
}
else {
positionalOffsetMap[i] = numFreePositions;
numFreePositions++;
}
}
}
args = [];
const maxNonRestPosition = maxFixedPosition >= numFreePositions ? maxFixedPosition + 1 : numFreePositions;
for (let i = 0; i < argumentList.length; i++) {
const argument = argumentList[i];
if (isPositionalElement(argument)) {
args.push(pipelineArguments[positionalOffsetMap[i]] || argument);
}
else if (isPositionalSpreadElement(argument)) {
for (let j = maxNonRestPosition; j < pipelineArguments.length; j++) {
args.push(pipelineArguments[j]);
}
}
else {
args.push(argument);
}
}
}
else {
args = pipelineArguments;
}
}
else {
@ -12678,6 +12734,15 @@ namespace ts {
return args;
}
function collectPipelineArguments(node: Expression, argumentList: Expression[]) {
if (isCommaExpression(node)) {
collectPipelineArguments(node.left, argumentList);
collectPipelineArguments(node.right, argumentList);
}
else {
argumentList.push(node);
}
}
/**
* Returns the effective argument count for a node that works like a function invocation.
@ -12939,7 +13004,6 @@ namespace ts {
(argIndex === 0 && node.kind === SyntaxKind.TaggedTemplateExpression)) {
return undefined;
}
return args[argIndex];
}
@ -12960,14 +13024,28 @@ namespace ts {
}
}
function resolveCall(node: CallLikeExpression, signatures: Signature[], partialSignaturesOutArray: Signature[], candidatesOutArray: Signature[], headMessage?: DiagnosticMessage): Signature {
let typeArguments: TypeNode[];
function getEffectiveTypeArguments(node: CallLikeExpression): NodeArray<TypeNode> {
if (node.kind === SyntaxKind.CallExpression || node.kind === SyntaxKind.NewExpression) {
typeArguments = node.typeArguments;
const 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);
}
return typeArguments;
}
if (node.kind === SyntaxKind.BinaryExpression && isPartialApplication(node.right)) {
return getEffectiveTypeArguments(node.right);
}
}
function resolveCall(node: CallLikeExpression, signatures: Signature[], candidatesOutArray: Signature[], propagatingType?: Type, headMessage?: DiagnosticMessage): Signature {
const typeArguments: TypeNode[] = getEffectiveTypeArguments(node);
let partialSignatures: Signature[];
if (node.kind === SyntaxKind.BindExpression ||
node.kind === SyntaxKind.BindToExpression ||
isPartialApplication(node)) {
partialSignatures = [];
}
const candidates = candidatesOutArray || [];
@ -12975,7 +13053,7 @@ namespace ts {
reorderCandidates(signatures, candidates);
if (!candidates.length) {
reportError(Diagnostics.Supplied_parameters_do_not_match_any_signature_of_call_target);
return resolveErrorCall(node, partialSignaturesOutArray);
return resolveErrorCall(node);
}
const args = getEffectiveCallArguments(node);
@ -13001,7 +13079,7 @@ namespace ts {
// We do not need to call `getEffectiveArgumentCount` here as it only
// applies when calculating the number of arguments for a decorator.
for (let i = node.kind === SyntaxKind.TaggedTemplateExpression ? 1 : 0; i < args.length; i++) {
if (isContextSensitive(args[i])) {
if (isContextSensitive(getEffectiveArgument(node, args, i))) {
if (!excludeArgument) {
excludeArgument = new Array(args.length);
}
@ -13051,7 +13129,7 @@ namespace ts {
// Whether the call is an error is determined by assignability of the arguments. The subtype pass
// is just important for choosing the best signature. So in the case where there is only one
// signature, the subtype pass is useless. So skipping it is an optimization.
if (candidates.length > 1 && !partialSignaturesOutArray) {
if (candidates.length > 1 && !partialSignatures) {
result = chooseOverload(candidates, subtypeRelation);
}
if (!result) {
@ -13061,8 +13139,24 @@ namespace ts {
resultOfFailedInference = undefined;
result = chooseOverload(candidates, assignableRelation);
}
if (result || some(partialSignaturesOutArray)) {
return result;
if (some(partialSignatures)) {
const returnType = node.kind === SyntaxKind.BindExpression || node.kind === SyntaxKind.BindToExpression
? createTypeFromSignatures(map(partialSignatures, getSignatureWithoutThis))
: getPartialApplicationOfSignatures(args, partialSignatures);
result = createSignature(
/*isConstruct*/ false,
/*typeParameters*/ undefined,
/*typeParameter*/ undefined,
/*parameters*/ emptyArray,
returnType,
/*typePredicate*/ undefined,
/*minArgumentCount*/ 0,
/*hasRestParameter*/ false,
/*hasLiteralTypes*/ false
);
}
if (result) {
return propagateNullReturnType(result, propagatingType || neverType);
}
// No signatures were applicable. Now report errors based on the last applicable signature with
@ -13117,7 +13211,7 @@ namespace ts {
}
}
return resolveErrorCall(node, partialSignaturesOutArray);
return resolveErrorCall(node);
function reportError(message: DiagnosticMessage, arg0?: string, arg1?: string, arg2?: string): void {
let errorInfo: DiagnosticMessageChain;
@ -13164,11 +13258,11 @@ namespace ts {
}
const index = excludeArgument ? indexOf(excludeArgument, true) : -1;
if (index < 0) {
if (partialSignaturesOutArray) {
if (partialSignatures) {
const partialCandidate = originalCandidate.typeParameters
? getPartialSignatureInstantiation(originalCandidate, typeArgumentTypes)
: originalCandidate;
partialSignaturesOutArray.push(partialCandidate);
partialSignatures.push(partialCandidate);
continue nextCandidate;
}
return candidate;
@ -13202,7 +13296,7 @@ namespace ts {
}
}
function resolveCallExpression(node: CallExpression, partialSignaturesOutArray: Signature[], candidatesOutArray: Signature[]): Signature {
function resolveCallExpression(node: CallExpression, candidatesOutArray: Signature[]): Signature {
if (node.expression.kind === SyntaxKind.SuperKeyword) {
const superType = checkSuperExpression(node.expression);
if (superType !== unknownType) {
@ -13211,21 +13305,23 @@ namespace ts {
const baseTypeNode = getClassExtendsHeritageClauseElement(getContainingClass(node));
if (baseTypeNode) {
const baseConstructors = getInstantiatedConstructorsForTypeArguments(superType, baseTypeNode.typeArguments);
return resolveCall(node, baseConstructors, partialSignaturesOutArray, candidatesOutArray);
return resolveCall(node, baseConstructors, candidatesOutArray);
}
}
return resolveUntypedCall(node, partialSignaturesOutArray);
return resolveUntypedCall(node);
}
const funcType = checkNonNullExpression(node.expression);
if (funcType === silentNeverType) {
const propagateNull = node.flags & NodeFlags.PropagateNull;
const funcType = propagateNull ? checkExpression(node.expression) : checkNonNullExpression(node.expression);
const type = propagateNull ? getNonNullableType(funcType) : funcType;
if (type === silentNeverType) {
return silentNeverSignature;
}
const apparentType = getApparentType(funcType);
const apparentType = getApparentType(type);
if (apparentType === unknownType) {
// Another error has already been reported
return resolveErrorCall(node, partialSignaturesOutArray);
return resolveErrorCall(node);
}
// Technically, this signatures list may be incomplete. We are taking the apparent type,
@ -13238,27 +13334,29 @@ namespace ts {
// TS 1.0 Spec: 4.12
// In an untyped function call no TypeArgs are permitted, Args can be any argument list, no contextual
// types are provided for the argument expressions, and the result is always of type Any.
if (isUntypedFunctionCall(funcType, apparentType, callSignatures.length, constructSignatures.length)) {
if (isUntypedFunctionCall(type, apparentType, callSignatures.length, constructSignatures.length)) {
// The unknownType indicates that an error already occurred (and was reported). No
// need to report another error in this case.
if (funcType !== unknownType && node.typeArguments) {
if (type !== unknownType && node.typeArguments) {
error(node, Diagnostics.Untyped_function_calls_may_not_accept_type_arguments);
}
return resolveUntypedCall(node, partialSignaturesOutArray);
return resolveUntypedCall(node);
}
// If FuncExpr's apparent type(section 3.8.1) is a function type, the call is a typed function call.
// TypeScript employs overload resolution in typed function calls in order to support functions
// with multiple call signatures.
if (!callSignatures.length) {
if (constructSignatures.length) {
error(node, Diagnostics.Value_of_type_0_is_not_callable_Did_you_mean_to_include_new, typeToString(funcType));
error(node, Diagnostics.Value_of_type_0_is_not_callable_Did_you_mean_to_include_new, typeToString(type));
}
else {
error(node, Diagnostics.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures, typeToString(apparentType));
}
return resolveErrorCall(node, partialSignaturesOutArray);
return resolveErrorCall(node);
}
return resolveCall(node, callSignatures, partialSignaturesOutArray, candidatesOutArray);
const propagatingType = propagateNull ? getTypeWithFacts(funcType, TypeFacts.EQUndefinedOrNull) : neverType;
return resolveCall(node, callSignatures, candidatesOutArray, propagatingType);
}
/**
@ -13292,8 +13390,10 @@ namespace ts {
}
}
let expressionType = checkNonNullExpression(node.expression);
if (expressionType === silentNeverType) {
const propagateNull = node.flags & NodeFlags.PropagateNull;
const funcType = propagateNull ? checkExpression(node.expression) : checkNonNullExpression(node.expression);
const type = propagateNull ? getNonNullableType(funcType) : funcType;
if (type === silentNeverType) {
return silentNeverSignature;
}
@ -13302,51 +13402,53 @@ namespace ts {
// function call, but using the construct signatures as the initial set of candidate
// signatures for overload resolution. The result type of the function call becomes
// the result type of the operation.
expressionType = getApparentType(expressionType);
if (expressionType === unknownType) {
const apparentType = getApparentType(type);
if (apparentType === unknownType) {
// Another error has already been reported
return resolveErrorCall(node, /*partialSignaturesOutArray*/ undefined);
return resolveErrorCall(node);
}
// If the expression is a class of abstract type, then it cannot be instantiated.
// Note, only class declarations can be declared abstract.
// In the case of a merged class-module or class-interface declaration,
// only the class declaration node will have the Abstract flag set.
const valueDecl = expressionType.symbol && getClassLikeDeclarationOfSymbol(expressionType.symbol);
const valueDecl = apparentType.symbol && getClassLikeDeclarationOfSymbol(apparentType.symbol);
if (valueDecl && getModifierFlags(valueDecl) & ModifierFlags.Abstract) {
error(node, Diagnostics.Cannot_create_an_instance_of_the_abstract_class_0, declarationNameToString(valueDecl.name));
return resolveErrorCall(node, /*partialSignaturesOutArray*/ undefined);
return resolveErrorCall(node);
}
// TS 1.0 spec: 4.11
// If expressionType is of type Any, Args can be any argument
// list and the result of the operation is of type Any.
if (isTypeAny(expressionType)) {
if (isTypeAny(apparentType)) {
if (node.typeArguments) {
error(node, Diagnostics.Untyped_function_calls_may_not_accept_type_arguments);
}
return resolveUntypedCall(node, /*partialSignaturesOutArray*/ undefined);
return resolveUntypedCall(node);
}
// Technically, this signatures list may be incomplete. We are taking the apparent type,
// but we are not including construct signatures that may have been added to the Object or
// Function interface, since they have none by default. This is a bit of a leap of faith
// that the user will not add any.
const constructSignatures = getSignaturesOfType(expressionType, SignatureKind.Construct);
const constructSignatures = getSignaturesOfType(apparentType, SignatureKind.Construct);
if (constructSignatures.length) {
if (!isConstructorAccessible(node, constructSignatures[0])) {
return resolveErrorCall(node, /*partialSignaturesOutArray*/ undefined);
return resolveErrorCall(node);
}
return resolveCall(node, constructSignatures, /*partialSignaturesOutArray*/ undefined, candidatesOutArray);
const propagatingType = propagateNull ? getTypeWithFacts(funcType, TypeFacts.EQUndefinedOrNull) : neverType;
return resolveCall(node, constructSignatures, candidatesOutArray, propagatingType);
}
// If expressionType's apparent type is an object type with no construct signatures but
// one or more call signatures, the expression is processed as a function call. A compile-time
// error occurs if the result of the function call is not Void. The type of the result of the
// operation is Any. It is an error to have a Void this type.
const callSignatures = getSignaturesOfType(expressionType, SignatureKind.Call);
const callSignatures = getSignaturesOfType(apparentType, SignatureKind.Call);
if (callSignatures.length) {
const signature = resolveCall(node, callSignatures, /*partialSignaturesOutArray*/ undefined, candidatesOutArray);
const signature = resolveCall(node, callSignatures, candidatesOutArray);
if (getReturnTypeOfSignature(signature) !== voidType) {
error(node, Diagnostics.Only_a_void_function_can_be_called_with_the_new_keyword);
}
@ -13357,7 +13459,7 @@ namespace ts {
}
error(node, Diagnostics.Cannot_use_new_with_an_expression_whose_type_lacks_a_call_or_construct_signature);
return resolveErrorCall(node, /*partialSignaturesOutArray*/ undefined);
return resolveErrorCall(node);
}
function isConstructorAccessible(node: NewExpression, signature: Signature) {
@ -13408,22 +13510,22 @@ namespace ts {
if (apparentType === unknownType) {
// Another error has already been reported
return resolveErrorCall(node, /*partialSignaturesOutArray*/ undefined);
return resolveErrorCall(node);
}
const callSignatures = getSignaturesOfType(apparentType, SignatureKind.Call);
const constructSignatures = getSignaturesOfType(apparentType, SignatureKind.Construct);
if (isUntypedFunctionCall(tagType, apparentType, callSignatures.length, constructSignatures.length)) {
return resolveUntypedCall(node, /*partialSignaturesOutArray*/ undefined);
return resolveUntypedCall(node);
}
if (!callSignatures.length) {
error(node, Diagnostics.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures, typeToString(apparentType));
return resolveErrorCall(node, /*partialSignaturesOutArray*/ undefined);
return resolveErrorCall(node);
}
return resolveCall(node, callSignatures, /*partialSignaturesOutArray*/ undefined, candidatesOutArray);
return resolveCall(node, callSignatures, candidatesOutArray);
}
/**
@ -13455,13 +13557,13 @@ namespace ts {
const funcType = checkExpression(node.expression);
const apparentType = getApparentType(funcType);
if (apparentType === unknownType) {
return resolveErrorCall(node, /*partialSignaturesOutArray*/ undefined);
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, /*partialSignaturesOutArray*/ undefined);
return resolveUntypedCall(node);
}
const headMessage = getDiagnosticHeadMessageForDecoratorResolution(node);
@ -13470,62 +13572,69 @@ namespace ts {
errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures, typeToString(apparentType));
errorInfo = chainDiagnosticMessages(errorInfo, headMessage);
diagnostics.add(createDiagnosticForNodeFromMessageChain(node, errorInfo));
return resolveErrorCall(node, /*partialSignaturesOutArray*/ undefined);
return resolveErrorCall(node);
}
return resolveCall(node, callSignatures, /*partialSignaturesOutArray*/ undefined, candidatesOutArray, headMessage);
return resolveCall(node, callSignatures, candidatesOutArray, /*propagatingType*/ undefined, headMessage);
}
function resolvePipelineExpression(node: PipelineExpression, candidatesOutArray: Signature[]): Signature {
const funcType = checkExpression(node.right);
const apparentType = getApparentType(funcType);
const type = isPartialApplication(node.right)
? checkNonNullExpression(node.right.expression)
: checkNonNullExpression(node.right);
const apparentType = getApparentType(type);
if (apparentType === unknownType) {
return resolveErrorCall(node, /*partialSignaturesOutArray*/ undefined);
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, /*partialSignaturesOutArray*/ undefined);
if (isUntypedFunctionCall(type, apparentType, callSignatures.length, constructSignatures.length)) {
return resolveUntypedCall(node);
}
if (!callSignatures.length) {
return resolveErrorCall(node, /*partialSignaturesOutArray*/ undefined);
return resolveErrorCall(node);
}
return resolveCall(node, callSignatures, /*partialSignaturesOutArray*/ undefined, candidatesOutArray);
return resolveCall(node, callSignatures, candidatesOutArray);
}
function resolveBindExpression(node: BindExpression | BindToExpression, partialSignaturesOutArray: Signature[], candidatesOutArray?: Signature[]): Signature {
const funcType = checkExpression(node.expression);
const apparentType = getApparentType(funcType);
function resolveBindExpression(node: BindExpression | BindToExpression, candidatesOutArray?: Signature[]): Signature {
const type = checkNonNullExpression(node.expression);
if (type === silentNeverType) {
return silentNeverSignature;
}
const apparentType = getApparentType(type);
if (apparentType === unknownType) {
return resolveErrorCall(node, partialSignaturesOutArray);
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, partialSignaturesOutArray);
if (isUntypedFunctionCall(type, apparentType, callSignatures.length, constructSignatures.length)) {
return resolveUntypedCall(node);
}
if (!callSignatures.length) {
if (constructSignatures.length) {
error(node.expression, Diagnostics.Value_of_type_0_is_not_callable_Did_you_mean_to_include_new, typeToString(funcType));
error(node.expression, Diagnostics.Value_of_type_0_is_not_callable_Did_you_mean_to_include_new, typeToString(type));
}
else {
error(node.expression, Diagnostics.Cannot_bind_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures, typeToString(apparentType));
}
return resolveErrorCall(node, partialSignaturesOutArray);
return resolveErrorCall(node);
}
return resolveCall(node, callSignatures, partialSignaturesOutArray, candidatesOutArray);
return resolveCall(node, callSignatures, candidatesOutArray);
}
function resolveSignature(node: CallLikeExpression, partialSignaturesOutArray: Signature[], candidatesOutArray?: Signature[]): Signature {
function resolveSignature(node: CallLikeExpression, candidatesOutArray?: Signature[]): Signature {
switch (node.kind) {
case SyntaxKind.CallExpression:
return resolveCallExpression(node, partialSignaturesOutArray, candidatesOutArray);
return resolveCallExpression(node, candidatesOutArray);
case SyntaxKind.NewExpression:
return resolveNewExpression(node, candidatesOutArray);
case SyntaxKind.TaggedTemplateExpression:
@ -13536,7 +13645,7 @@ namespace ts {
return resolvePipelineExpression(node, candidatesOutArray);
case SyntaxKind.BindExpression:
case SyntaxKind.BindToExpression:
return resolveBindExpression(node, partialSignaturesOutArray, candidatesOutArray);
return resolveBindExpression(node, candidatesOutArray);
}
Debug.fail("Branch in 'resolveSignature' should be unreachable.");
}
@ -13554,7 +13663,7 @@ namespace ts {
return cached;
}
links.resolvedSignature = resolvingSignature;
const result = resolveSignature(node, /*partialSignaturesOutArray*/ undefined, candidatesOutArray);
const result = resolveSignature(node, candidatesOutArray);
// If signature resolution originated in control flow type analysis (for example to compute the
// assigned type in a flow assignment) we don't cache the result as it may be based on temporary
// types from the control flow analysis.
@ -13562,26 +13671,6 @@ namespace ts {
return result;
}
function getResolvedPartialSignatures(node: CallLikeExpression): Signature[] {
const links = getNodeLinks(node);
// If getResolvedSignature has already been called, we will have cached the resolvedSignature.
// However, it is possible that either candidatesOutArray was not passed in the first time,
// or that a different candidatesOutArray was passed in. Therefore, we need to redo the work
// to correctly fill the candidatesOutArray.
const cached = links.resolvedPartialSignatures;
if (cached && cached !== resolvingPartialSignatures) {
return cached;
}
links.resolvedPartialSignatures = resolvingPartialSignatures;
const partialSignatures: Signature[] = [];
resolveSignature(node, partialSignatures);
// If signature resolution originated in control flow type analysis (for example to compute the
// assigned type in a flow assignment) we don't cache the result as it may be based on temporary
// types from the control flow analysis.
links.resolvedPartialSignatures = flowLoopStart === flowLoopCount ? partialSignatures : cached;
return partialSignatures;
}
function getResolvedOrAnySignature(node: CallLikeExpression) {
// If we're already in the process of resolving the given signature, don't resolve again as
// that could cause infinite recursion. Instead, return anySignature.
@ -13605,9 +13694,7 @@ namespace ts {
// Grammar checking; stop grammar-checking if checkGrammarTypeArguments return true
checkGrammarTypeArguments(node, node.typeArguments) || checkGrammarArguments(node, node.arguments);
const partialApplication = node.kind === SyntaxKind.CallExpression && forEach(node.arguments, isPositionalOrPositionalSpreadElement);
const signatures = partialApplication && getResolvedPartialSignatures(node);
const signature = !partialApplication && getResolvedSignature(node);
const signature = getResolvedSignature(node);
if (node.expression.kind === SyntaxKind.SuperKeyword) {
return voidType;
@ -13645,9 +13732,7 @@ namespace ts {
return resolveExternalModuleTypeByLiteral(<StringLiteral>node.arguments[0]);
}
return partialApplication ?
getPartialApplicationOfSignatures(node.arguments, signatures) :
getReturnTypeOfSignature(signature);
return getReturnTypeOfSignature(signature);
}
function getPartialApplicationOfSignatures(argumentList: Expression[], signatures: Signature[]) {
@ -13655,13 +13740,7 @@ namespace ts {
for (const signature of signatures) {
partialSignatures.push(getPartialApplicationOfSignature(argumentList, signature));
}
const partialType = createObjectType(ObjectFlags.Anonymous);
(<ResolvedType>partialType).members = emptySymbols;
(<ResolvedType>partialType).properties = emptyArray;
(<ResolvedType>partialType).callSignatures = partialSignatures;
(<ResolvedType>partialType).constructSignatures = emptyArray;
return partialType;
return createTypeFromSignatures(partialSignatures);
}
function getPartialApplicationOfSignature(argumentList: Expression[], signature: Signature) {
@ -13670,12 +13749,11 @@ namespace ts {
uniqueParameterNames[parameter.name] = true;
}
let positionalParameters: TransientSymbol[];
const positionalParameters: TransientSymbol[] = [];
let positionalRestParameter: TransientSymbol;
let position = 0;
for (let i = 0; i < argumentList.length; i++) {
const argument = argumentList[i];
// const inRestParameter = signature.hasRestParameter && i >= signature.parameters.length;
const parameter = i < signature.parameters.length ? signature.parameters[i] : lastOrUndefined(signature.parameters);
if (isPositionalElement(argument)) {
let ordinalPosition: number;
@ -13686,9 +13764,7 @@ namespace ts {
ordinalPosition = position;
position++;
}
if (!positionalParameters) {
positionalParameters = [];
}
const type = getTypeAtPosition(signature, i);
const previousParameter = positionalParameters[ordinalPosition];
if (previousParameter) {
@ -13697,17 +13773,14 @@ namespace ts {
}
previousParameter.type = getIntersectionType([previousParameter.type, type]);
}
else if (parameter) {
const sym = createTransientSymbol(parameter, type);
if (sym)
positionalParameters[ordinalPosition] = createTransientSymbol(parameter, type);
}
else {
// TODO(rbuckton): implicit any error?
const name = getUniqueName(uniqueParameterNames, `arg${ordinalPosition}`);
const newParameter = <TransientSymbol>createSymbol(SymbolFlags.Transient | SymbolFlags.Variable, name);
newParameter.type = type;
positionalParameters[ordinalPosition] = newParameter;
const name = i < signature.parameters.length - (signature.hasRestParameter ? 1 : 0) ?
parameter.name :
getUniqueName(uniqueParameterNames, parameter ? parameter.name : `arg${ordinalPosition}`);
positionalParameters[ordinalPosition] = <TransientSymbol>createSymbol(SymbolFlags.Transient | SymbolFlags.Variable, name);
positionalParameters[ordinalPosition].target = parameter;
positionalParameters[ordinalPosition].type = type;
positionalParameters[ordinalPosition].transientSymbolIsRest = false;
}
}
else if (isPositionalSpreadElement(argument)) {
@ -13718,28 +13791,26 @@ namespace ts {
}
positionalRestParameter.type = getIntersectionType([positionalRestParameter.type, type]);
}
else if (parameter) {
positionalRestParameter = createTransientSymbol(parameter, type);
positionalRestParameter.transientSymbolIsRest = true;
}
else {
// TODO(rbuckton): implicit any error?
const name = getUniqueName(uniqueParameterNames, `args`);
const name = parameter ? parameter.name : getUniqueName(uniqueParameterNames, `args`);
positionalRestParameter = <TransientSymbol>createSymbol(SymbolFlags.Transient | SymbolFlags.Variable, name);
positionalRestParameter.target = parameter;
positionalRestParameter.type = type;
positionalRestParameter.transientSymbolIsRest = true;
}
}
}
positionalParameters = append(positionalParameters, positionalRestParameter) || [];
if (positionalRestParameter) {
positionalParameters.push(positionalRestParameter);
}
for (let i = 0; i < positionalParameters.length; i++) {
if (!positionalParameters[i]) {
const name = getUniqueName(uniqueParameterNames, `arg${i}`);
// TODO(rbuckton): implicit any error
positionalParameters[i] = <TransientSymbol>createSymbol(SymbolFlags.Transient | SymbolFlags.Variable, name);
positionalParameters[i].type = anyType;
// TODO(rbuckton): implicit any error
}
}
@ -13759,7 +13830,7 @@ namespace ts {
let uniqueName = name;
let index = 0;
while (uniqueNames[uniqueName]) {
uniqueName = `${name}_${index}`;
uniqueName = `${name}${index}`;
index++;
}
uniqueNames[uniqueName] = true;
@ -15000,6 +15071,10 @@ namespace ts {
return getTypeFacts(leftType) & TypeFacts.Truthy ?
includeFalsyTypes(rightType, getFalsyFlags(strictNullChecks ? leftType : getBaseTypeOfLiteralType(rightType))) :
leftType;
case SyntaxKind.QuestionQuestionToken:
return getTypeFacts(leftType) & TypeFacts.EQUndefinedOrNull ?
getBestChoiceType(getNonNullableType(leftType), rightType) :
leftType;
case SyntaxKind.BarBarToken:
return getTypeFacts(leftType) & TypeFacts.Falsy ?
getBestChoiceType(removeDefinitelyFalsyTypes(leftType), rightType) :

View File

@ -1037,12 +1037,13 @@ namespace ts {
}
function emitPropertyAccessExpression(node: PropertyAccessExpression) {
const propagatesNull = node.flags & NodeFlags.PropagateNull;
let indentBeforeDot = false;
let indentAfterDot = false;
if (!(getEmitFlags(node) & EmitFlags.NoIndentation)) {
const dotRangeStart = node.expression.end;
const dotRangeEnd = skipTrivia(currentText, node.expression.end) + 1;
const dotToken = <Node>{ kind: SyntaxKind.DotToken, pos: dotRangeStart, end: dotRangeEnd };
const dotRangeEnd = skipTrivia(currentText, node.expression.end) + (propagatesNull ? 2 : 1);
const dotToken = <Node>{ kind: propagatesNull ? SyntaxKind.QuestionDotToken : SyntaxKind.DotToken, pos: dotRangeStart, end: dotRangeEnd };
indentBeforeDot = needsIndentation(node, node.expression, dotToken);
indentAfterDot = needsIndentation(node, dotToken, node.name);
}
@ -1050,8 +1051,8 @@ namespace ts {
emitExpression(node.expression);
increaseIndentIf(indentBeforeDot);
const shouldEmitDotDot = !indentBeforeDot && needsDotDotForPropertyAccess(node.expression);
write(shouldEmitDotDot ? ".." : ".");
const shouldEmitDotDot = !propagatesNull && !indentBeforeDot && needsDotDotForPropertyAccess(node.expression);
write(shouldEmitDotDot ? ".." : propagatesNull ? "?." : ".");
increaseIndentIf(indentAfterDot);
emit(node.name);
@ -1078,25 +1079,28 @@ namespace ts {
function emitElementAccessExpression(node: ElementAccessExpression) {
emitExpression(node.expression);
write("[");
write(node.flags & NodeFlags.PropagateNull ? "?.[" : "[");
emitExpression(node.argumentExpression);
write("]");
}
function emitBindToExpression(node: BindToExpression) {
emitExpression(node.targetExpression);
write("::");
write(node.flags & NodeFlags.PropagateNull ? "?::" : "::");
emitExpression(node.expression);
}
function emitBindExpression(node: BindExpression) {
write("::");
write(node.flags & NodeFlags.PropagateNull ? "?::" : "::");
emitExpression(node.expression);
}
function emitCallExpression(node: CallExpression) {
emitExpression(node.expression);
emitTypeArguments(node, node.typeArguments);
if (node.flags & NodeFlags.PropagateNull) {
write("?.");
}
emitExpressionList(node, node.arguments, ListFormat.CallExpressionArguments);
}
@ -1104,6 +1108,9 @@ namespace ts {
write("new ");
emitExpression(node.expression);
emitTypeArguments(node, node.typeArguments);
if (node.flags & NodeFlags.PropagateNull) {
write("?.");
}
emitExpressionList(node, node.arguments, ListFormat.NewExpressionArguments);
}
@ -1119,7 +1126,6 @@ namespace ts {
emit(node.type);
write(">");
}
emitExpression(node.expression);
}

View File

@ -437,8 +437,8 @@ namespace ts {
return node;
}
export function createElementAccess(expression: Expression, index: number | Expression, location?: TextRange) {
const node = <ElementAccessExpression>createNode(SyntaxKind.ElementAccessExpression, location);
export function createElementAccess(expression: Expression, index: number | Expression, location?: TextRange, flags?: NodeFlags) {
const node = <ElementAccessExpression>createNode(SyntaxKind.ElementAccessExpression, location, flags);
node.expression = parenthesizeForAccess(expression);
node.argumentExpression = typeof index === "number" ? createLiteral(index) : index;
return node;
@ -446,7 +446,7 @@ namespace ts {
export function updateElementAccess(node: ElementAccessExpression, expression: Expression, argumentExpression: Expression) {
if (node.expression !== expression || node.argumentExpression !== argumentExpression) {
return updateNode(createElementAccess(expression, argumentExpression, node), node);
return updateNode(createElementAccess(expression, argumentExpression, /*location*/ node, node.flags), node);
}
return node;
}
@ -653,16 +653,16 @@ namespace ts {
if (whenFalse) {
// second overload
node.questionToken = <QuestionToken>questionTokenOrWhenTrue;
node.whenTrue = whenTrueOrWhenFalse;
node.whenTrue = parenthesizeForConditionalResult(whenTrueOrWhenFalse);
node.colonToken = <ColonToken>colonTokenOrLocation;
node.whenFalse = whenFalse;
node.whenFalse = parenthesizeForConditionalResult(whenFalse);
}
else {
// first overload
node.questionToken = createToken(SyntaxKind.QuestionToken);
node.whenTrue = <Expression>questionTokenOrWhenTrue;
node.whenTrue = parenthesizeForConditionalResult(<Expression>questionTokenOrWhenTrue);
node.colonToken = createToken(SyntaxKind.ColonToken);
node.whenFalse = whenTrueOrWhenFalse;
node.whenFalse = parenthesizeForConditionalResult(whenTrueOrWhenFalse);
}
return node;
}
@ -1561,10 +1561,18 @@ namespace ts {
return createBinary(left, SyntaxKind.EqualsEqualsEqualsToken, right);
}
export function createEquality(left: Expression, right: Expression) {
return createBinary(left, SyntaxKind.EqualsEqualsToken, right);
}
export function createStrictInequality(left: Expression, right: Expression) {
return createBinary(left, SyntaxKind.ExclamationEqualsEqualsToken, right);
}
export function createInequality(left: Expression, right: Expression) {
return createBinary(left, SyntaxKind.ExclamationEqualsToken, right);
}
export function createAdd(left: Expression, right: Expression) {
return createBinary(left, SyntaxKind.PlusToken, right);
}
@ -2392,6 +2400,16 @@ namespace ts {
return condition;
}
export function parenthesizeForConditionalResult(expression: Expression) {
const conditionalPrecedence = getOperatorPrecedence(SyntaxKind.ConditionalExpression, SyntaxKind.ColonToken);
const emittedExpression = skipPartiallyEmittedExpressions(expression);
const expressionPrecedence = getExpressionPrecedence(emittedExpression);
if (compareValues(expressionPrecedence, conditionalPrecedence) === Comparison.LessThan) {
return createParen(expression);
}
return expression;
}
/**
* Wraps an expression in parentheses if it is needed in order to use the expression
* as the expression of a NewExpression node.

View File

@ -209,6 +209,8 @@ namespace ts {
visitNode(cbNode, (<ConditionalExpression>node).whenTrue) ||
visitNode(cbNode, (<ConditionalExpression>node).colonToken) ||
visitNode(cbNode, (<ConditionalExpression>node).whenFalse);
case SyntaxKind.PositionalElement:
return visitNode(cbNode, (<PositionalElement>node).literal);
case SyntaxKind.SpreadElement:
return visitNode(cbNode, (<SpreadElement>node).expression);
case SyntaxKind.Block:
@ -3373,6 +3375,7 @@ namespace ts {
switch (token()) {
case SyntaxKind.BarGreaterThanToken:
return 1;
case SyntaxKind.QuestionQuestionToken:
case SyntaxKind.BarBarToken:
return 2;
case SyntaxKind.AmpersandAmpersandToken:
@ -3745,7 +3748,11 @@ namespace ts {
function parseSuperExpression(): MemberExpression {
const expression = parseTokenNode<PrimaryExpression>();
if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.DotToken || token() === SyntaxKind.OpenBracketToken) {
if (token() === SyntaxKind.OpenParenToken ||
token() === SyntaxKind.DotToken ||
token() === SyntaxKind.OpenBracketToken ||
token() === SyntaxKind.QuestionDotToken ||
token() === SyntaxKind.QuestionDotOpenBracketToken) {
return expression;
}
@ -3996,9 +4003,12 @@ namespace ts {
function parseMemberExpressionRest(expression: LeftHandSideExpression): MemberExpression {
while (true) {
const dotToken = parseOptionalToken(SyntaxKind.DotToken);
if (dotToken) {
if (token() === SyntaxKind.DotToken || token() === SyntaxKind.QuestionDotToken) {
const propertyAccess = <PropertyAccessExpression>createNode(SyntaxKind.PropertyAccessExpression, expression.pos);
if (token() === SyntaxKind.QuestionDotToken) {
propertyAccess.flags |= NodeFlags.PropagateNull;
}
nextToken();
propertyAccess.expression = expression;
propertyAccess.name = parseRightSideOfDot(/*allowIdentifierNames*/ true);
expression = finishNode(propertyAccess);
@ -4014,8 +4024,12 @@ namespace ts {
}
// when in the [Decorator] context, we do not parse ElementAccess as it could be part of a ComputedPropertyName
if (!inDecoratorContext() && parseOptional(SyntaxKind.OpenBracketToken)) {
if (!inDecoratorContext() && (token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.QuestionDotOpenBracketToken)) {
const indexedAccess = <ElementAccessExpression>createNode(SyntaxKind.ElementAccessExpression, expression.pos);
if (token() === SyntaxKind.QuestionDotOpenBracketToken) {
indexedAccess.flags |= NodeFlags.PropagateNull;
}
nextToken();
indexedAccess.expression = expression;
// It's not uncommon for a user to write: "new Type[]".
@ -4043,8 +4057,9 @@ namespace ts {
continue;
}
if (parseOptional(SyntaxKind.ColonColonToken)) {
if (token() === SyntaxKind.ColonColonToken) {
const bindExpression = <BindToExpression>createNode(SyntaxKind.BindToExpression, expression.pos);
nextToken();
bindExpression.targetExpression = expression;
bindExpression.expression = parseMemberExpressionOrHigher();
expression = finishNode(bindExpression);
@ -4058,37 +4073,35 @@ namespace ts {
function parseCallExpressionRest(expression: LeftHandSideExpression): LeftHandSideExpression {
while (true) {
expression = parseMemberExpressionRest(expression);
let typeArguments: NodeArray<TypeNode>;
if (token() === SyntaxKind.LessThanToken) {
// See if this is the start of a generic invocation. If so, consume it and
// keep checking for postfix expressions. Otherwise, it's just a '<' that's
// part of an arithmetic expression. Break out so we consume it higher in the
// stack.
const typeArguments = tryParse(parseTypeArgumentsInExpression);
typeArguments = tryParse(parseTypeArgumentsInExpression);
if (!typeArguments) {
return expression;
}
const callExpr = <CallExpression>createNode(SyntaxKind.CallExpression, expression.pos);
callExpr.expression = expression;
callExpr.typeArguments = typeArguments;
callExpr.arguments = parseArgumentList();
expression = finishNode(callExpr);
continue;
}
else if (token() === SyntaxKind.OpenParenToken) {
const callExpr = <CallExpression>createNode(SyntaxKind.CallExpression, expression.pos);
callExpr.expression = expression;
callExpr.arguments = parseArgumentList();
expression = finishNode(callExpr);
continue;
else if (token() !== SyntaxKind.OpenParenToken && token() !== SyntaxKind.QuestionDotOpenParenToken) {
return expression;
}
return expression;
const callExpr = <CallExpression>createNode(SyntaxKind.CallExpression, expression.pos);
if (token() === SyntaxKind.QuestionDotOpenParenToken) {
callExpr.flags |= NodeFlags.PropagateNull;
}
callExpr.expression = expression;
callExpr.typeArguments = typeArguments;
callExpr.arguments = parseArgumentList();
expression = finishNode(callExpr);
}
}
function parseArgumentList() {
parseExpected(SyntaxKind.OpenParenToken);
if (!parseOptional(SyntaxKind.QuestionDotOpenParenToken)) {
parseExpected(SyntaxKind.OpenParenToken);
}
const result = parseDelimitedList(ParsingContext.ArgumentExpressions, parseArgumentExpression);
parseExpected(SyntaxKind.CloseParenToken);
return result;
@ -4115,6 +4128,7 @@ namespace ts {
function canFollowTypeArgumentsInExpression(): boolean {
switch (token()) {
case SyntaxKind.OpenParenToken: // foo<x>(
case SyntaxKind.QuestionDotOpenParenToken: // foo<x>?.(
// this case are the only case where this token can legally follow a type argument
// list. So we definitely want to treat this as a type arg list.
@ -4437,7 +4451,10 @@ namespace ts {
parseExpected(SyntaxKind.NewKeyword);
node.expression = parseMemberExpressionOrHigher();
node.typeArguments = tryParse(parseTypeArgumentsInExpression);
if (node.typeArguments || token() === SyntaxKind.OpenParenToken) {
if (node.typeArguments || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.QuestionDotOpenParenToken) {
if (token() === SyntaxKind.QuestionDotOpenParenToken) {
node.flags |= NodeFlags.PropagateNull;
}
node.arguments = parseArgumentList();
}

View File

@ -170,6 +170,10 @@ namespace ts {
"&&": SyntaxKind.AmpersandAmpersandToken,
"||": SyntaxKind.BarBarToken,
"?": SyntaxKind.QuestionToken,
"??": SyntaxKind.QuestionQuestionToken,
"?.": SyntaxKind.QuestionDotToken,
"?.[": SyntaxKind.QuestionDotOpenBracketToken,
"?.(": SyntaxKind.QuestionDotOpenParenToken,
":": SyntaxKind.ColonToken,
"::": SyntaxKind.ColonColonToken,
"=": SyntaxKind.EqualsToken,
@ -1550,6 +1554,20 @@ namespace ts {
pos++;
return token = SyntaxKind.GreaterThanToken;
case CharacterCodes.question:
if (text.charCodeAt(pos + 1) === CharacterCodes.question) {
return pos += 2, token = SyntaxKind.QuestionQuestionToken;
}
if (text.charCodeAt(pos + 1) === CharacterCodes.dot) {
if (text.charCodeAt(pos + 2) === CharacterCodes.openParen) {
return pos += 3, token = SyntaxKind.QuestionDotOpenParenToken;
}
if (text.charCodeAt(pos + 2) === CharacterCodes.openBracket) {
return pos += 3, token = SyntaxKind.QuestionDotOpenBracketToken;
}
if (!isDigit(text.charCodeAt(pos + 2))) {
return pos += 2, token = SyntaxKind.QuestionDotToken;
}
}
pos++;
return token = SyntaxKind.QuestionToken;
case CharacterCodes.openBracket:

View File

@ -69,12 +69,18 @@ namespace ts {
return visitParenthesizedExpression(node as ParenthesizedExpression, noDestructuringValue);
case SyntaxKind.CallExpression:
return visitCallExpression(node as CallExpression);
case SyntaxKind.NewExpression:
return visitNewExpression(node as NewExpression);
case SyntaxKind.OperatorExpression:
return visitOperatorExpression(node as OperatorExpression);
case SyntaxKind.BindExpression:
return visitBindExpression(node as BindExpression);
case SyntaxKind.BindToExpression:
return visitBindToExpression(node as BindToExpression);
case SyntaxKind.PropertyAccessExpression:
return visitPropertyAccess(node as PropertyAccessExpression);
case SyntaxKind.ElementAccessExpression:
return visitElementAccess(node as ElementAccessExpression);
default:
return visitEachChild(node, visitor, context);
}
@ -159,28 +165,25 @@ namespace ts {
visitNode(node.right, noDestructuringValue ? visitorNoDestructuringValue : visitor, isExpression)
);
case SyntaxKind.BarGreaterThanToken:
return transformPipelineExpression(node);
return transformPipelineExpression(<PipelineExpression>node);
case SyntaxKind.QuestionQuestionToken:
return transformCoalesceExpression(<CoalesceExpression>node);
}
return visitEachChild(node, visitor, context);
}
function transformPipelineExpression(node: BinaryExpression) {
function transformPipelineExpression(node: PipelineExpression) {
const argumentList: Expression[] = [];
let expression = node.left;
if (expression.kind === SyntaxKind.ParenthesizedExpression) {
// comma expressions are right-deep
expression = (<ParenthesizedExpression>expression).expression;
while (expression.kind === SyntaxKind.BinaryExpression &&
(<BinaryExpression>expression).operatorToken.kind === SyntaxKind.CommaToken) {
argumentList.push(visitNode((<BinaryExpression>expression).left, visitor, isExpression));
expression = (<BinaryExpression>expression).right;
}
if (node.left.kind === SyntaxKind.ParenthesizedExpression) {
collectPipelineArguments((<ParenthesizedExpression>node.left).expression, argumentList);
}
else {
argumentList.push(visitNode(node.left, visitor, isExpression));
}
argumentList.push(visitNode(expression, visitor, isExpression));
const func = visitNode(node.right, visitor, isExpression);
if (func.kind === SyntaxKind.ArrowFunction ||
func.kind === SyntaxKind.FunctionExpression) {
return createCall(func, /*typeArguments*/ undefined, argumentList);
return createCall(func, /*typeArguments*/ undefined, argumentList, node);
}
else {
const parameterList: ParameterDeclaration[] = [];
@ -204,7 +207,38 @@ namespace ts {
)
),
/*typeArguments*/ undefined,
argumentList
argumentList,
node
);
}
}
function collectPipelineArguments(node: Expression, argumentList: Expression[]) {
if (isCommaExpression(node)) {
collectPipelineArguments(node.left, argumentList);
collectPipelineArguments(node.right, argumentList);
}
else {
argumentList.push(visitNode(node, visitor, isExpression));
}
}
function transformCoalesceExpression(node: CoalesceExpression): Expression {
const left = visitNode(node.left, visitor, isExpression);
const right = visitNode(node.right, visitor, isExpression);
if (isIdentifier(left)) {
return createConditional(
createInequality(left, createNull()),
left,
right
);
}
else {
const temp = createTempVariable(hoistVariableDeclaration);
return createConditional(
createInequality(createAssignment(temp, left), createNull()),
temp,
right
);
}
}
@ -442,65 +476,181 @@ namespace ts {
return body;
}
function propagateNull<T extends Node>(finishExpression: (node: T, nullableExpression: Expression) => Expression, node: T, nullableExpression: Expression): Expression;
function propagateNull<T extends Node, U>(finishExpression: (node: T, nullableExpression: Expression, data: U) => Expression, node: T, nullableExpression: Expression, data: U): Expression;
function propagateNull<T extends Node, U>(finishExpression: (node: T, nullableExpression: Expression, data: U) => Expression, node: T, nullableExpression: Expression, data?: U): Expression {
if (node.flags & NodeFlags.PropagateNull) {
if (isIdentifier(nullableExpression)) {
return createConditional(
createEquality(nullableExpression, createNull()),
nullableExpression,
finishExpression(node, nullableExpression, data),
node
);
}
else {
const temp = createTempVariable(hoistVariableDeclaration);
return createConditional(
createEquality(
createAssignment(temp, nullableExpression),
createNull()
),
temp,
finishExpression(node, temp, data),
node
);
}
}
return finishExpression(node, nullableExpression, data);
}
function visitCallExpression(node: CallExpression): Expression {
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));
return propagateNull(finishCallExpression, node, visitNode(node.expression, visitor, isExpression));
}
function finishCallExpression(node: CallExpression, expression: Expression) {
if (forEach(node.arguments, isPositionalOrPositionalSpreadElement)) {
return transformPartialCallExpression(node, expression);
}
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.push(positionalRestParameter);
}
for (let i = 0; i < positionalParameters.length; i++) {
if (!positionalParameters[i]) {
positionalParameters[i] = createParameter();
}
}
pendingExpressions.push(
createArrowFunction(
/*modifiers*/ undefined,
/*typeParameters*/ undefined,
positionalParameters,
/*type*/ undefined,
/*equalsGreaterThanToken*/ createToken(SyntaxKind.EqualsGreaterThanToken),
updateCall(node, expressionTemp, /*typeArguments*/ undefined, argumentList),
/*location*/ node
)
if (node.flags & NodeFlags.PropagateNull) {
return setOriginalNode(
createCall(
expression,
/*typeArguments*/ undefined,
visitNodes(node.arguments, visitor, isExpression),
node
),
node
);
return inlineExpressions(pendingExpressions);
}
return updateCall(
node,
expression,
/*typeArguments*/ undefined,
visitNodes(node.arguments, visitor, isExpression),
)
}
function transformPartialCallExpression(node: CallExpression, expression: Expression) {
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.push(positionalRestParameter);
}
for (let i = 0; i < positionalParameters.length; i++) {
if (!positionalParameters[i]) {
positionalParameters[i] = createParameter();
}
}
pendingExpressions.push(
createArrowFunction(
/*modifiers*/ undefined,
/*typeParameters*/ undefined,
positionalParameters,
/*type*/ undefined,
/*equalsGreaterThanToken*/ createToken(SyntaxKind.EqualsGreaterThanToken),
setOriginalNode(
createCall(expressionTemp, /*typeArguments*/ undefined, argumentList, node),
node
),
/*location*/ node
)
);
return inlineExpressions(pendingExpressions);
}
function visitNewExpression(node: NewExpression): Expression {
return propagateNull(finishNewExpression, node, visitNode(node.expression, visitor, isExpression));
}
function finishNewExpression(node: NewExpression, expression: Expression) {
if (node.flags & NodeFlags.PropagateNull) {
return setOriginalNode(
createNew(
expression,
/*typeArguments*/ undefined,
visitNodes(node.arguments, visitor, isExpression),
/*location*/ node
),
node
);
}
return updateNew(
node,
expression,
/*typeArguments*/ undefined,
visitNodes(node.arguments, visitor, isExpression),
);
}
function visitPropertyAccess(node: PropertyAccessExpression): Expression {
return propagateNull(finishPropertyAccess, node, visitNode(node.expression, visitor, isExpression));
}
function finishPropertyAccess(node: PropertyAccessExpression, expression: Expression) {
if (node.flags & NodeFlags.PropagateNull) {
return setOriginalNode(
createPropertyAccess(
expression,
node.name,
node
),
node
);
}
return updatePropertyAccess(
node,
expression,
node.name
);
}
function visitElementAccess(node: ElementAccessExpression): Expression {
return propagateNull(finishElementAccess, node, visitNode(node.expression, visitor, isExpression));
}
function finishElementAccess(node: ElementAccessExpression, expression: Expression) {
if (node.flags & NodeFlags.PropagateNull) {
return setOriginalNode(
createElementAccess(
expression,
visitNode(node.argumentExpression, visitor, isExpression),
node
),
node
);
}
return updateElementAccess(
node,
expression,
visitNode(node.argumentExpression, visitor, isExpression),
);
}
function visitOperatorExpression(node: OperatorExpression) {
@ -551,37 +701,27 @@ namespace ts {
if (operand.kind === SyntaxKind.PropertyAccessExpression
|| operand.kind === SyntaxKind.ElementAccessExpression) {
const { target, thisArg } = createCallBinding(operand, hoistVariableDeclaration);
return createFunctionBind(
target,
thisArg,
[],
node
)
return createFunctionBind(target, thisArg, [], node);
}
else {
return createFunctionBind(
operand,
createNull(),
[],
node
);
return createFunctionBind(operand, createNull(), [], node);
}
}
function visitBindToExpression(node: BindToExpression) {
const targetExpression = visitNode(node.targetExpression, visitor, isExpression);
const expression = visitNode(node.expression, visitor, isLeftHandSideExpression);
if (isIdentifier(targetExpression)) {
return createFunctionBind(expression, targetExpression, [], node);
}
const thisArg = createTempVariable(context.hoistVariableDeclaration);
return createComma(
createAssignment(
thisArg,
visitNode(node.targetExpression, visitor, isExpression),
targetExpression,
node.targetExpression
),
createFunctionBind(
visitNode(node.expression, visitor, isLeftHandSideExpression),
thisArg,
[],
node
)
createFunctionBind(expression, thisArg, [], node)
);
}
}

View File

@ -53,7 +53,7 @@ namespace ts {
TemplateMiddle,
TemplateTail,
// Punctuation
OpenBraceToken,
OpenBraceToken, // FirstPunctuation
CloseBraceToken,
OpenParenToken,
CloseParenToken,
@ -62,10 +62,21 @@ namespace ts {
DotToken,
DotDotDotToken,
SemicolonToken,
BarGreaterThanToken,
CommaToken,
EqualsGreaterThanToken,
LessThanToken,
QuestionDotToken,
QuestionDotOpenBracketToken,
QuestionDotOpenParenToken,
QuestionToken,
ColonToken,
AtToken,
PlusPlusToken, // FirstPrefixUnaryOperator, FirstPostfixUnaryOperator
MinusMinusToken, // LastPostfixUnaryOperator
ExclamationToken,
TildeToken, // LastPrefixUnaryOperator
TildePlusToken,
TildeMinusToken,
LessThanToken, // FirstBinaryOperator
LessThanSlashToken,
GreaterThanToken,
LessThanEqualsToken,
@ -80,27 +91,20 @@ namespace ts {
AsteriskAsteriskToken,
SlashToken,
PercentToken,
PlusPlusToken,
MinusMinusToken,
LessThanLessThanToken,
GreaterThanGreaterThanToken,
GreaterThanGreaterThanGreaterThanToken,
AmpersandToken,
BarToken,
CaretToken,
ExclamationToken,
TildeToken,
TildePlusToken,
TildeMinusToken,
AmpersandAmpersandToken,
BarBarToken,
QuestionToken,
ColonToken,
QuestionQuestionToken,
ColonColonToken,
AtToken,
BarGreaterThanToken,
// Assignments
EqualsToken,
PlusEqualsToken,
EqualsToken, // FirstAssignment
PlusEqualsToken, // FirstCompoundAssignment
MinusEqualsToken,
AsteriskEqualsToken,
AsteriskAsteriskEqualsToken,
@ -111,7 +115,7 @@ namespace ts {
GreaterThanGreaterThanGreaterThanEqualsToken,
AmpersandEqualsToken,
BarEqualsToken,
CaretEqualsToken,
CaretEqualsToken, // LastAssignment, LastCompoundAssignment, LastBinaryOperator, LastPunctuation
// Identifiers
Identifier,
// Reserved words
@ -382,10 +386,6 @@ namespace ts {
// Enum value count
Count,
// Markers
FirstAssignment = EqualsToken,
LastAssignment = CaretEqualsToken,
FirstCompoundAssignment = PlusEqualsToken,
LastCompoundAssignment = CaretEqualsToken,
FirstReservedWord = BreakKeyword,
LastReservedWord = WithKeyword,
FirstKeyword = BreakKeyword,
@ -394,6 +394,16 @@ namespace ts {
LastFutureReservedWord = YieldKeyword,
FirstTypeNode = TypePredicate,
LastTypeNode = LiteralType,
FirstAssignment = EqualsToken,
LastAssignment = CaretEqualsToken,
FirstCompoundAssignment = PlusEqualsToken,
LastCompoundAssignment = CaretEqualsToken,
FirstPrefixUnaryOperator = PlusPlusToken,
LastPrefixUnaryOperator = TildeToken,
FirstPostfixUnaryOperator = PlusPlusToken,
LastPostfixUnaryOperator = MinusMinusToken,
FirstBinaryOperator = LessThanToken,
LastBinaryOperator = CaretEqualsToken,
FirstPunctuation = OpenBraceToken,
LastPunctuation = CaretEqualsToken,
FirstToken = Unknown,
@ -404,8 +414,6 @@ namespace ts {
LastLiteralToken = NoSubstitutionTemplateLiteral,
FirstTemplateToken = NoSubstitutionTemplateLiteral,
LastTemplateToken = TemplateTail,
FirstBinaryOperator = LessThanToken,
LastBinaryOperator = CaretEqualsToken,
FirstNode = QualifiedName,
FirstJSDocNode = JSDocTypeExpression,
LastJSDocNode = JSDocLiteralType,
@ -420,25 +428,26 @@ namespace ts {
NestedNamespace = 1 << 2, // Namespace declaration
Synthesized = 1 << 3, // Node was synthesized during transformation
Namespace = 1 << 4, // Namespace declaration
ExportContext = 1 << 5, // Export context (initialized by binding)
ContainsThis = 1 << 6, // Interface contains references to "this"
HasImplicitReturn = 1 << 7, // If function implicitly returns on one of codepaths (initialized by binding)
HasExplicitReturn = 1 << 8, // If function has explicit reachable return on one of codepaths (initialized by binding)
GlobalAugmentation = 1 << 9, // Set if module declaration is an augmentation for the global scope
HasClassExtends = 1 << 10, // If the file has a non-ambient class with an extends clause in ES5 or lower (initialized by binding)
HasDecorators = 1 << 11, // If the file has decorators (initialized by binding)
HasParamDecorators = 1 << 12, // If the file has parameter decorators (initialized by binding)
HasAsyncFunctions = 1 << 13, // If the file has async functions (initialized by binding)
HasSpreadAttribute = 1 << 14, // If the file as JSX spread attributes (initialized by binding)
HasRestAttribute = 1 << 15, // If the file has object destructure elements
DisallowInContext = 1 << 16, // If node was parsed in a context where 'in-expressions' are not allowed
YieldContext = 1 << 17, // If node was parsed in the 'yield' context created when parsing a generator
DecoratorContext = 1 << 18, // If node was parsed as part of a decorator
AwaitContext = 1 << 19, // If node was parsed in the 'await' context created when parsing an async function
ThisNodeHasError = 1 << 20, // If the parser encountered an error when parsing the code that created this node
JavaScriptFile = 1 << 21, // If node was parsed in a JavaScript
ThisNodeOrAnySubNodesHasError = 1 << 22, // If this node or any of its children had an error
HasAggregatedChildData = 1 << 23, // If we've computed data from children and cached it in this node
PropagateNull = 1 << 5, // Expression
ExportContext = 1 << 6, // Export context (initialized by binding)
ContainsThis = 1 << 7, // Interface contains references to "this"
HasImplicitReturn = 1 << 8, // If function implicitly returns on one of codepaths (initialized by binding)
HasExplicitReturn = 1 << 9, // If function has explicit reachable return on one of codepaths (initialized by binding)
GlobalAugmentation = 1 << 10, // Set if module declaration is an augmentation for the global scope
HasClassExtends = 1 << 11, // If the file has a non-ambient class with an extends clause in ES5 or lower (initialized by binding)
HasDecorators = 1 << 12, // If the file has decorators (initialized by binding)
HasParamDecorators = 1 << 13, // If the file has parameter decorators (initialized by binding)
HasAsyncFunctions = 1 << 14, // If the file has async functions (initialized by binding)
HasSpreadAttribute = 1 << 15, // If the file as JSX spread attributes (initialized by binding)
HasRestAttribute = 1 << 16, // If the file has object destructure elements
DisallowInContext = 1 << 17, // If node was parsed in a context where 'in-expressions' are not allowed
YieldContext = 1 << 18, // If node was parsed in the 'yield' context created when parsing a generator
DecoratorContext = 1 << 19, // If node was parsed as part of a decorator
AwaitContext = 1 << 20, // If node was parsed in the 'await' context created when parsing an async function
ThisNodeHasError = 1 << 21, // If the parser encountered an error when parsing the code that created this node
JavaScriptFile = 1 << 22, // If node was parsed in a JavaScript
ThisNodeOrAnySubNodesHasError = 1 << 23, // If this node or any of its children had an error
HasAggregatedChildData = 1 << 24, // If we've computed data from children and cached it in this node
BlockScoped = Let | Const,
@ -1140,6 +1149,7 @@ namespace ts {
export type LogicalOperator
= SyntaxKind.AmpersandAmpersandToken
| SyntaxKind.BarBarToken
| SyntaxKind.QuestionQuestionToken
;
// see: https://tc39.github.io/ecma262/#prod-LogicalANDExpression
@ -1181,6 +1191,7 @@ namespace ts {
export type BinaryOperator
= AssignmentOperatorOrHigher
| SyntaxKind.BarGreaterThanToken
| SyntaxKind.QuestionQuestionToken
| SyntaxKind.CommaToken
;
@ -1194,12 +1205,22 @@ namespace ts {
right: Expression;
}
export type CommaToken = Token<SyntaxKind.CommaToken>;
export type BarGreaterThanToken = Token<SyntaxKind.BarGreaterThanToken>;
export type QuestionQuestionToken = Token<SyntaxKind.QuestionQuestionToken>;
export interface CommaExpression extends BinaryExpression {
operatorToken: CommaToken;
}
export interface PipelineExpression extends BinaryExpression {
operatorToken: BarGreaterThanToken;
}
export interface CoalesceExpression extends BinaryExpression {
operatorToken: QuestionQuestionToken;
}
export type AssignmentOperatorToken = Token<AssignmentOperator>;
export interface AssignmentExpression<TOperator extends AssignmentOperatorToken> extends BinaryExpression {
@ -2777,7 +2798,6 @@ namespace ts {
flags?: NodeCheckFlags; // Set of flags specific to Node
resolvedType?: Type; // Cached type of type node
resolvedSignature?: Signature; // Cached signature of signature node or call expression
resolvedPartialSignatures?: Signature[];
resolvedSymbol?: Symbol; // Cached name resolution result
resolvedIndexInfo?: IndexInfo; // Cached indexing info resolution result
maybeTypePredicate?: boolean; // Cached check whether call expression might reference a type predicate

View File

@ -2135,36 +2135,40 @@ namespace ts {
case SyntaxKind.ParenthesizedExpression:
case SyntaxKind.OmittedExpression:
case SyntaxKind.RawExpression:
return 19;
case SyntaxKind.BindExpression:
return 20;
case SyntaxKind.TaggedTemplateExpression:
case SyntaxKind.PropertyAccessExpression:
case SyntaxKind.ElementAccessExpression:
return 18;
case SyntaxKind.BindToExpression:
return 19;
case SyntaxKind.NewExpression:
return hasArguments ? 18 : 17;
return hasArguments ? 19 : 18;
case SyntaxKind.CallExpression:
return 17;
return 18;
case SyntaxKind.PostfixUnaryExpression:
return 16;
return 17;
case SyntaxKind.PrefixUnaryExpression:
case SyntaxKind.TypeOfExpression:
case SyntaxKind.VoidExpression:
case SyntaxKind.DeleteExpression:
case SyntaxKind.AwaitExpression:
return 15;
return 16;
case SyntaxKind.BinaryExpression:
switch (operatorKind) {
case SyntaxKind.ExclamationToken:
case SyntaxKind.TildeToken:
return 15;
return 16;
case SyntaxKind.AsteriskAsteriskToken:
return 15;
case SyntaxKind.AsteriskToken:
case SyntaxKind.SlashToken:
case SyntaxKind.PercentToken:
@ -2206,6 +2210,7 @@ namespace ts {
return 6;
case SyntaxKind.BarBarToken:
case SyntaxKind.QuestionQuestionToken:
return 5;
case SyntaxKind.EqualsToken:
@ -2231,11 +2236,12 @@ namespace ts {
}
case SyntaxKind.ConditionalExpression:
return 4;
return operatorKind === SyntaxKind.QuestionToken ? 4 : 3;
case SyntaxKind.YieldExpression:
return 2;
case SyntaxKind.PositionalElement:
case SyntaxKind.SpreadElement:
return 1;
@ -3903,6 +3909,7 @@ namespace ts {
case SyntaxKind.AmpersandAmpersandToken:
case SyntaxKind.BarBarToken:
case SyntaxKind.BarGreaterThanToken:
case SyntaxKind.QuestionQuestionToken:
return true;
}
return false;
@ -3912,6 +3919,11 @@ namespace ts {
return node.kind === SyntaxKind.BinaryExpression;
}
export function isCommaExpression(node: Node): node is CommaExpression {
return isBinaryExpression(node)
&& node.operatorToken.kind === SyntaxKind.CommaToken
}
export function isConditionalExpression(node: Node): node is ConditionalExpression {
return node.kind === SyntaxKind.ConditionalExpression;
}
@ -3943,6 +3955,11 @@ namespace ts {
return isPositionalElement(node) || isPositionalSpreadElement(node);
}
export function isPartialApplication(node: Node): node is CallExpression {
return node.kind === SyntaxKind.CallExpression
&& forEach((<CallExpression>node).arguments, isPositionalOrPositionalSpreadElement);
}
export function isExpressionWithTypeArguments(node: Node): node is ExpressionWithTypeArguments {
return node.kind === SyntaxKind.ExpressionWithTypeArguments;
}

View File

@ -0,0 +1,72 @@
=== tests/cases/conformance/parser/esnext/parser.bindTo.esnext.1.ts ===
// single argument
declare function f1(this: number): string;
>f1 : Symbol(f1, Decl(parser.bindTo.esnext.1.ts, 0, 0))
>this : Symbol(this, Decl(parser.bindTo.esnext.1.ts, 1, 20))
1 :: f1;
1 :: f1();
// multiple steps
declare function f2(this: string): boolean;
>f2 : Symbol(f2, Decl(parser.bindTo.esnext.1.ts, 3, 10))
>this : Symbol(this, Decl(parser.bindTo.esnext.1.ts, 5, 20))
1 :: f1() :: f2();
// use cases
declare function map<T, U>(this: Iterable<T>, cb: (value: T) => U): Iterable<U>;
>map : Symbol(map, Decl(parser.bindTo.esnext.1.ts, 6, 18))
>T : Symbol(T, Decl(parser.bindTo.esnext.1.ts, 8, 21))
>U : Symbol(U, Decl(parser.bindTo.esnext.1.ts, 8, 23))
>this : Symbol(this, Decl(parser.bindTo.esnext.1.ts, 8, 27))
>Iterable : Symbol(Iterable, Decl(lib.es2015.iterable.d.ts, --, --))
>T : Symbol(T, Decl(parser.bindTo.esnext.1.ts, 8, 21))
>cb : Symbol(cb, Decl(parser.bindTo.esnext.1.ts, 8, 45))
>value : Symbol(value, Decl(parser.bindTo.esnext.1.ts, 8, 51))
>T : Symbol(T, Decl(parser.bindTo.esnext.1.ts, 8, 21))
>U : Symbol(U, Decl(parser.bindTo.esnext.1.ts, 8, 23))
>Iterable : Symbol(Iterable, Decl(lib.es2015.iterable.d.ts, --, --))
>U : Symbol(U, Decl(parser.bindTo.esnext.1.ts, 8, 23))
declare function filter<T>(this: Iterable<T>, cb: (value: T) => boolean): Iterable<T>;
>filter : Symbol(filter, Decl(parser.bindTo.esnext.1.ts, 8, 80))
>T : Symbol(T, Decl(parser.bindTo.esnext.1.ts, 9, 24))
>this : Symbol(this, Decl(parser.bindTo.esnext.1.ts, 9, 27))
>Iterable : Symbol(Iterable, Decl(lib.es2015.iterable.d.ts, --, --))
>T : Symbol(T, Decl(parser.bindTo.esnext.1.ts, 9, 24))
>cb : Symbol(cb, Decl(parser.bindTo.esnext.1.ts, 9, 45))
>value : Symbol(value, Decl(parser.bindTo.esnext.1.ts, 9, 51))
>T : Symbol(T, Decl(parser.bindTo.esnext.1.ts, 9, 24))
>Iterable : Symbol(Iterable, Decl(lib.es2015.iterable.d.ts, --, --))
>T : Symbol(T, Decl(parser.bindTo.esnext.1.ts, 9, 24))
declare function reduce<T>(this: Iterable<T>, cb: (memo: T, value: T) => T, initial: T): T;
>reduce : Symbol(reduce, Decl(parser.bindTo.esnext.1.ts, 9, 86))
>T : Symbol(T, Decl(parser.bindTo.esnext.1.ts, 10, 24))
>this : Symbol(this, Decl(parser.bindTo.esnext.1.ts, 10, 27))
>Iterable : Symbol(Iterable, Decl(lib.es2015.iterable.d.ts, --, --))
>T : Symbol(T, Decl(parser.bindTo.esnext.1.ts, 10, 24))
>cb : Symbol(cb, Decl(parser.bindTo.esnext.1.ts, 10, 45))
>memo : Symbol(memo, Decl(parser.bindTo.esnext.1.ts, 10, 51))
>T : Symbol(T, Decl(parser.bindTo.esnext.1.ts, 10, 24))
>value : Symbol(value, Decl(parser.bindTo.esnext.1.ts, 10, 59))
>T : Symbol(T, Decl(parser.bindTo.esnext.1.ts, 10, 24))
>T : Symbol(T, Decl(parser.bindTo.esnext.1.ts, 10, 24))
>initial : Symbol(initial, Decl(parser.bindTo.esnext.1.ts, 10, 75))
>T : Symbol(T, Decl(parser.bindTo.esnext.1.ts, 10, 24))
>T : Symbol(T, Decl(parser.bindTo.esnext.1.ts, 10, 24))
[1, 2, 3]
:: map(x => x * 2)
>x : Symbol(x, Decl(parser.bindTo.esnext.1.ts, 12, 11))
>x : Symbol(x, Decl(parser.bindTo.esnext.1.ts, 12, 11))
:: filter(x => x > 2)
>x : Symbol(x, Decl(parser.bindTo.esnext.1.ts, 13, 14))
>x : Symbol(x, Decl(parser.bindTo.esnext.1.ts, 13, 14))
:: reduce((x, y) => x + y, 0);
>x : Symbol(x, Decl(parser.bindTo.esnext.1.ts, 14, 15))
>y : Symbol(y, Decl(parser.bindTo.esnext.1.ts, 14, 17))
>x : Symbol(x, Decl(parser.bindTo.esnext.1.ts, 14, 15))
>y : Symbol(y, Decl(parser.bindTo.esnext.1.ts, 14, 17))

View File

@ -0,0 +1,102 @@
=== tests/cases/conformance/parser/esnext/parser.bindTo.esnext.1.ts ===
// single argument
declare function f1(this: number): string;
>f1 : (this: number) => string
>this : number
1 :: f1;
>f1 : any
1 :: f1();
>1 :: f1() : string
>f1 : any
// multiple steps
declare function f2(this: string): boolean;
>f2 : (this: string) => boolean
>this : string
1 :: f1() :: f2();
>1 :: f1() :: f2() : boolean
>1 :: f1() : string
>f1 : any
>f2 : any
// use cases
declare function map<T, U>(this: Iterable<T>, cb: (value: T) => U): Iterable<U>;
>map : <T, U>(this: Iterable<T>, cb: (value: T) => U) => Iterable<U>
>T : T
>U : U
>this : Iterable<T>
>Iterable : Iterable<T>
>T : T
>cb : (value: T) => U
>value : T
>T : T
>U : U
>Iterable : Iterable<T>
>U : U
declare function filter<T>(this: Iterable<T>, cb: (value: T) => boolean): Iterable<T>;
>filter : <T>(this: Iterable<T>, cb: (value: T) => boolean) => Iterable<T>
>T : T
>this : Iterable<T>
>Iterable : Iterable<T>
>T : T
>cb : (value: T) => boolean
>value : T
>T : T
>Iterable : Iterable<T>
>T : T
declare function reduce<T>(this: Iterable<T>, cb: (memo: T, value: T) => T, initial: T): T;
>reduce : <T>(this: Iterable<T>, cb: (memo: T, value: T) => T, initial: T) => T
>T : T
>this : Iterable<T>
>Iterable : Iterable<T>
>T : T
>cb : (memo: T, value: T) => T
>memo : T
>T : T
>value : T
>T : T
>T : T
>initial : T
>T : T
>T : T
[1, 2, 3]
>[1, 2, 3] :: map(x => x * 2) :: filter(x => x > 2) :: reduce((x, y) => x + y, 0) : number
>[1, 2, 3] :: map(x => x * 2) :: filter(x => x > 2) : Iterable<number>
>[1, 2, 3] :: map(x => x * 2) : Iterable<number>
>[1, 2, 3] : number[]
>1 : 1
>2 : 2
>3 : 3
:: map(x => x * 2)
>map : any
>x => x * 2 : (x: number) => number
>x : number
>x * 2 : number
>x : number
>2 : 2
:: filter(x => x > 2)
>filter : any
>x => x > 2 : (x: number) => boolean
>x : number
>x > 2 : boolean
>x : number
>2 : 2
:: reduce((x, y) => x + y, 0);
>reduce : any
>(x, y) => x + y : (x: number, y: number) => number
>x : number
>y : number
>x + y : number
>x : number
>y : number
>0 : 0

View File

@ -0,0 +1,114 @@
=== tests/cases/conformance/parser/esnext/parser.partialApplication.esnext.1.ts ===
declare function f(a: number, b: number, ...c: number[]): void;
>f : Symbol(f, Decl(parser.partialApplication.esnext.1.ts, 0, 0))
>a : Symbol(a, Decl(parser.partialApplication.esnext.1.ts, 0, 19))
>b : Symbol(b, Decl(parser.partialApplication.esnext.1.ts, 0, 29))
>c : Symbol(c, Decl(parser.partialApplication.esnext.1.ts, 0, 40))
declare const o: { m(a: number, b: number, ...c: number[]): void; };
>o : Symbol(o, Decl(parser.partialApplication.esnext.1.ts, 1, 13))
>m : Symbol(m, Decl(parser.partialApplication.esnext.1.ts, 1, 18))
>a : Symbol(a, Decl(parser.partialApplication.esnext.1.ts, 1, 21))
>b : Symbol(b, Decl(parser.partialApplication.esnext.1.ts, 1, 31))
>c : Symbol(c, Decl(parser.partialApplication.esnext.1.ts, 1, 42))
// positional elements
f(?, 0);
>f : Symbol(f, Decl(parser.partialApplication.esnext.1.ts, 0, 0))
f(0, ?);
>f : Symbol(f, Decl(parser.partialApplication.esnext.1.ts, 0, 0))
f(?, ?);
>f : Symbol(f, Decl(parser.partialApplication.esnext.1.ts, 0, 0))
o.m(?, 0);
>o.m : Symbol(m, Decl(parser.partialApplication.esnext.1.ts, 1, 18))
>o : Symbol(o, Decl(parser.partialApplication.esnext.1.ts, 1, 13))
>m : Symbol(m, Decl(parser.partialApplication.esnext.1.ts, 1, 18))
o.m(0, ?);
>o.m : Symbol(m, Decl(parser.partialApplication.esnext.1.ts, 1, 18))
>o : Symbol(o, Decl(parser.partialApplication.esnext.1.ts, 1, 13))
>m : Symbol(m, Decl(parser.partialApplication.esnext.1.ts, 1, 18))
o.m(?, ?);
>o.m : Symbol(m, Decl(parser.partialApplication.esnext.1.ts, 1, 18))
>o : Symbol(o, Decl(parser.partialApplication.esnext.1.ts, 1, 13))
>m : Symbol(m, Decl(parser.partialApplication.esnext.1.ts, 1, 18))
// ordinal positional elements
f(?0, 0);
>f : Symbol(f, Decl(parser.partialApplication.esnext.1.ts, 0, 0))
f(0, ?0);
>f : Symbol(f, Decl(parser.partialApplication.esnext.1.ts, 0, 0))
f(?0, ?1);
>f : Symbol(f, Decl(parser.partialApplication.esnext.1.ts, 0, 0))
f(?1, ?0);
>f : Symbol(f, Decl(parser.partialApplication.esnext.1.ts, 0, 0))
o.m(?0, 0);
>o.m : Symbol(m, Decl(parser.partialApplication.esnext.1.ts, 1, 18))
>o : Symbol(o, Decl(parser.partialApplication.esnext.1.ts, 1, 13))
>m : Symbol(m, Decl(parser.partialApplication.esnext.1.ts, 1, 18))
o.m(0, ?0);
>o.m : Symbol(m, Decl(parser.partialApplication.esnext.1.ts, 1, 18))
>o : Symbol(o, Decl(parser.partialApplication.esnext.1.ts, 1, 13))
>m : Symbol(m, Decl(parser.partialApplication.esnext.1.ts, 1, 18))
o.m(?0, ?1);
>o.m : Symbol(m, Decl(parser.partialApplication.esnext.1.ts, 1, 18))
>o : Symbol(o, Decl(parser.partialApplication.esnext.1.ts, 1, 13))
>m : Symbol(m, Decl(parser.partialApplication.esnext.1.ts, 1, 18))
o.m(?1, ?0);
>o.m : Symbol(m, Decl(parser.partialApplication.esnext.1.ts, 1, 18))
>o : Symbol(o, Decl(parser.partialApplication.esnext.1.ts, 1, 13))
>m : Symbol(m, Decl(parser.partialApplication.esnext.1.ts, 1, 18))
// positional spread element
f(0, 1, ...);
>f : Symbol(f, Decl(parser.partialApplication.esnext.1.ts, 0, 0))
f(0, 1, ..., 2);
>f : Symbol(f, Decl(parser.partialApplication.esnext.1.ts, 0, 0))
o.m(0, 1, ...);
>o.m : Symbol(m, Decl(parser.partialApplication.esnext.1.ts, 1, 18))
>o : Symbol(o, Decl(parser.partialApplication.esnext.1.ts, 1, 13))
>m : Symbol(m, Decl(parser.partialApplication.esnext.1.ts, 1, 18))
o.m(0, 1, ..., 2);
>o.m : Symbol(m, Decl(parser.partialApplication.esnext.1.ts, 1, 18))
>o : Symbol(o, Decl(parser.partialApplication.esnext.1.ts, 1, 13))
>m : Symbol(m, Decl(parser.partialApplication.esnext.1.ts, 1, 18))
// mixed
f(?, 0, ...);
>f : Symbol(f, Decl(parser.partialApplication.esnext.1.ts, 0, 0))
f(0, ?, ...);
>f : Symbol(f, Decl(parser.partialApplication.esnext.1.ts, 0, 0))
f(0, 1, ..., ?0);
>f : Symbol(f, Decl(parser.partialApplication.esnext.1.ts, 0, 0))
o.m(?, 0, ...);
>o.m : Symbol(m, Decl(parser.partialApplication.esnext.1.ts, 1, 18))
>o : Symbol(o, Decl(parser.partialApplication.esnext.1.ts, 1, 13))
>m : Symbol(m, Decl(parser.partialApplication.esnext.1.ts, 1, 18))
o.m(0, ?, ...);
>o.m : Symbol(m, Decl(parser.partialApplication.esnext.1.ts, 1, 18))
>o : Symbol(o, Decl(parser.partialApplication.esnext.1.ts, 1, 13))
>m : Symbol(m, Decl(parser.partialApplication.esnext.1.ts, 1, 18))
o.m(0, 1, ..., ?0);
>o.m : Symbol(m, Decl(parser.partialApplication.esnext.1.ts, 1, 18))
>o : Symbol(o, Decl(parser.partialApplication.esnext.1.ts, 1, 13))
>m : Symbol(m, Decl(parser.partialApplication.esnext.1.ts, 1, 18))

View File

@ -0,0 +1,184 @@
=== tests/cases/conformance/parser/esnext/parser.partialApplication.esnext.1.ts ===
declare function f(a: number, b: number, ...c: number[]): void;
>f : (a: number, b: number, ...c: number[]) => void
>a : number
>b : number
>c : number[]
declare const o: { m(a: number, b: number, ...c: number[]): void; };
>o : { m(a: number, b: number, ...c: number[]): void; }
>m : (a: number, b: number, ...c: number[]) => void
>a : number
>b : number
>c : number[]
// positional elements
f(?, 0);
>f(?, 0) : (a: number) => void
>f : (a: number, b: number, ...c: number[]) => void
>0 : 0
f(0, ?);
>f(0, ?) : (b: number) => void
>f : (a: number, b: number, ...c: number[]) => void
>0 : 0
f(?, ?);
>f(?, ?) : (a: number, b: number) => void
>f : (a: number, b: number, ...c: number[]) => void
o.m(?, 0);
>o.m(?, 0) : (a: number) => void
>o.m : (a: number, b: number, ...c: number[]) => void
>o : { m(a: number, b: number, ...c: number[]): void; }
>m : (a: number, b: number, ...c: number[]) => void
>0 : 0
o.m(0, ?);
>o.m(0, ?) : (b: number) => void
>o.m : (a: number, b: number, ...c: number[]) => void
>o : { m(a: number, b: number, ...c: number[]): void; }
>m : (a: number, b: number, ...c: number[]) => void
>0 : 0
o.m(?, ?);
>o.m(?, ?) : (a: number, b: number) => void
>o.m : (a: number, b: number, ...c: number[]) => void
>o : { m(a: number, b: number, ...c: number[]): void; }
>m : (a: number, b: number, ...c: number[]) => void
// ordinal positional elements
f(?0, 0);
>f(?0, 0) : (a: number) => void
>f : (a: number, b: number, ...c: number[]) => void
>0 : 0
f(0, ?0);
>f(0, ?0) : (b: number) => void
>f : (a: number, b: number, ...c: number[]) => void
>0 : 0
f(?0, ?1);
>f(?0, ?1) : (a: number, b: number) => void
>f : (a: number, b: number, ...c: number[]) => void
f(?1, ?0);
>f(?1, ?0) : (b: number, a: number) => void
>f : (a: number, b: number, ...c: number[]) => void
o.m(?0, 0);
>o.m(?0, 0) : (a: number) => void
>o.m : (a: number, b: number, ...c: number[]) => void
>o : { m(a: number, b: number, ...c: number[]): void; }
>m : (a: number, b: number, ...c: number[]) => void
>0 : 0
o.m(0, ?0);
>o.m(0, ?0) : (b: number) => void
>o.m : (a: number, b: number, ...c: number[]) => void
>o : { m(a: number, b: number, ...c: number[]): void; }
>m : (a: number, b: number, ...c: number[]) => void
>0 : 0
o.m(?0, ?1);
>o.m(?0, ?1) : (a: number, b: number) => void
>o.m : (a: number, b: number, ...c: number[]) => void
>o : { m(a: number, b: number, ...c: number[]): void; }
>m : (a: number, b: number, ...c: number[]) => void
o.m(?1, ?0);
>o.m(?1, ?0) : (b: number, a: number) => void
>o.m : (a: number, b: number, ...c: number[]) => void
>o : { m(a: number, b: number, ...c: number[]): void; }
>m : (a: number, b: number, ...c: number[]) => void
// positional spread element
f(0, 1, ...);
>f(0, 1, ...) : (...c: number) => void
>f : (a: number, b: number, ...c: number[]) => void
>0 : 0
>1 : 1
>... : any
> : undefined
f(0, 1, ..., 2);
>f(0, 1, ..., 2) : (...c: number) => void
>f : (a: number, b: number, ...c: number[]) => void
>0 : 0
>1 : 1
>... : any
> : undefined
>2 : 2
o.m(0, 1, ...);
>o.m(0, 1, ...) : (...c: number) => void
>o.m : (a: number, b: number, ...c: number[]) => void
>o : { m(a: number, b: number, ...c: number[]): void; }
>m : (a: number, b: number, ...c: number[]) => void
>0 : 0
>1 : 1
>... : any
> : undefined
o.m(0, 1, ..., 2);
>o.m(0, 1, ..., 2) : (...c: number) => void
>o.m : (a: number, b: number, ...c: number[]) => void
>o : { m(a: number, b: number, ...c: number[]): void; }
>m : (a: number, b: number, ...c: number[]) => void
>0 : 0
>1 : 1
>... : any
> : undefined
>2 : 2
// mixed
f(?, 0, ...);
>f(?, 0, ...) : (a: number, ...c: number) => void
>f : (a: number, b: number, ...c: number[]) => void
>0 : 0
>... : any
> : undefined
f(0, ?, ...);
>f(0, ?, ...) : (b: number, ...c: number) => void
>f : (a: number, b: number, ...c: number[]) => void
>0 : 0
>... : any
> : undefined
f(0, 1, ..., ?0);
>f(0, 1, ..., ?0) : (c0: number, ...c: number) => void
>f : (a: number, b: number, ...c: number[]) => void
>0 : 0
>1 : 1
>... : any
> : undefined
o.m(?, 0, ...);
>o.m(?, 0, ...) : (a: number, ...c: number) => void
>o.m : (a: number, b: number, ...c: number[]) => void
>o : { m(a: number, b: number, ...c: number[]): void; }
>m : (a: number, b: number, ...c: number[]) => void
>0 : 0
>... : any
> : undefined
o.m(0, ?, ...);
>o.m(0, ?, ...) : (b: number, ...c: number) => void
>o.m : (a: number, b: number, ...c: number[]) => void
>o : { m(a: number, b: number, ...c: number[]): void; }
>m : (a: number, b: number, ...c: number[]) => void
>0 : 0
>... : any
> : undefined
o.m(0, 1, ..., ?0);
>o.m(0, 1, ..., ?0) : (c0: number, ...c: number) => void
>o.m : (a: number, b: number, ...c: number[]) => void
>o : { m(a: number, b: number, ...c: number[]): void; }
>m : (a: number, b: number, ...c: number[]) => void
>0 : 0
>1 : 1
>... : any
> : undefined

View File

@ -0,0 +1,121 @@
=== tests/cases/conformance/parser/esnext/parser.pipeline.esnext.1.ts ===
// single argument
declare function f1(x: number): string;
>f1 : Symbol(f1, Decl(parser.pipeline.esnext.1.ts, 0, 0))
>x : Symbol(x, Decl(parser.pipeline.esnext.1.ts, 1, 20))
1 |> f1;
>f1 : Symbol(f1, Decl(parser.pipeline.esnext.1.ts, 0, 0))
1 |> f1(?);
>f1 : Symbol(f1, Decl(parser.pipeline.esnext.1.ts, 0, 0))
(1) |> f1;
>f1 : Symbol(f1, Decl(parser.pipeline.esnext.1.ts, 0, 0))
(1) |> f1(?);
>f1 : Symbol(f1, Decl(parser.pipeline.esnext.1.ts, 0, 0))
// multiple argument
declare function f2(x: number, y: number): string;
>f2 : Symbol(f2, Decl(parser.pipeline.esnext.1.ts, 5, 13))
>x : Symbol(x, Decl(parser.pipeline.esnext.1.ts, 7, 20))
>y : Symbol(y, Decl(parser.pipeline.esnext.1.ts, 7, 30))
(1, 2) |> f2;
>f2 : Symbol(f2, Decl(parser.pipeline.esnext.1.ts, 5, 13))
(1, 2) |> f2(?, ?);
>f2 : Symbol(f2, Decl(parser.pipeline.esnext.1.ts, 5, 13))
// multiple steps
declare function f3(x: string): boolean;
>f3 : Symbol(f3, Decl(parser.pipeline.esnext.1.ts, 9, 19))
>x : Symbol(x, Decl(parser.pipeline.esnext.1.ts, 11, 20))
declare function f4(x: string, y: number): boolean;
>f4 : Symbol(f4, Decl(parser.pipeline.esnext.1.ts, 11, 40))
>x : Symbol(x, Decl(parser.pipeline.esnext.1.ts, 12, 20))
>y : Symbol(y, Decl(parser.pipeline.esnext.1.ts, 12, 30))
1 |> f1 |> f3;
>f1 : Symbol(f1, Decl(parser.pipeline.esnext.1.ts, 0, 0))
>f3 : Symbol(f3, Decl(parser.pipeline.esnext.1.ts, 9, 19))
1 |> f1(?) |> f3;
>f1 : Symbol(f1, Decl(parser.pipeline.esnext.1.ts, 0, 0))
>f3 : Symbol(f3, Decl(parser.pipeline.esnext.1.ts, 9, 19))
1 |> f1 |> f3(?);
>f1 : Symbol(f1, Decl(parser.pipeline.esnext.1.ts, 0, 0))
>f3 : Symbol(f3, Decl(parser.pipeline.esnext.1.ts, 9, 19))
1 |> f1(?) |> f3(?);
>f1 : Symbol(f1, Decl(parser.pipeline.esnext.1.ts, 0, 0))
>f3 : Symbol(f3, Decl(parser.pipeline.esnext.1.ts, 9, 19))
(1 |> f1(?), 2) |> f4;
>f1 : Symbol(f1, Decl(parser.pipeline.esnext.1.ts, 0, 0))
>f4 : Symbol(f4, Decl(parser.pipeline.esnext.1.ts, 11, 40))
// use case
declare function map<T, U>(source: Iterable<T>, cb: (value: T) => U): Iterable<U>;
>map : Symbol(map, Decl(parser.pipeline.esnext.1.ts, 17, 22))
>T : Symbol(T, Decl(parser.pipeline.esnext.1.ts, 19, 21))
>U : Symbol(U, Decl(parser.pipeline.esnext.1.ts, 19, 23))
>source : Symbol(source, Decl(parser.pipeline.esnext.1.ts, 19, 27))
>Iterable : Symbol(Iterable, Decl(lib.es2015.iterable.d.ts, --, --))
>T : Symbol(T, Decl(parser.pipeline.esnext.1.ts, 19, 21))
>cb : Symbol(cb, Decl(parser.pipeline.esnext.1.ts, 19, 47))
>value : Symbol(value, Decl(parser.pipeline.esnext.1.ts, 19, 53))
>T : Symbol(T, Decl(parser.pipeline.esnext.1.ts, 19, 21))
>U : Symbol(U, Decl(parser.pipeline.esnext.1.ts, 19, 23))
>Iterable : Symbol(Iterable, Decl(lib.es2015.iterable.d.ts, --, --))
>U : Symbol(U, Decl(parser.pipeline.esnext.1.ts, 19, 23))
declare function filter<T>(source: Iterable<T>, cb: (value: T) => boolean): Iterable<T>;
>filter : Symbol(filter, Decl(parser.pipeline.esnext.1.ts, 19, 82))
>T : Symbol(T, Decl(parser.pipeline.esnext.1.ts, 20, 24))
>source : Symbol(source, Decl(parser.pipeline.esnext.1.ts, 20, 27))
>Iterable : Symbol(Iterable, Decl(lib.es2015.iterable.d.ts, --, --))
>T : Symbol(T, Decl(parser.pipeline.esnext.1.ts, 20, 24))
>cb : Symbol(cb, Decl(parser.pipeline.esnext.1.ts, 20, 47))
>value : Symbol(value, Decl(parser.pipeline.esnext.1.ts, 20, 53))
>T : Symbol(T, Decl(parser.pipeline.esnext.1.ts, 20, 24))
>Iterable : Symbol(Iterable, Decl(lib.es2015.iterable.d.ts, --, --))
>T : Symbol(T, Decl(parser.pipeline.esnext.1.ts, 20, 24))
declare function reduce<T>(source: Iterable<T>, cb: (memo: T, value: T) => T, initial: T): T;
>reduce : Symbol(reduce, Decl(parser.pipeline.esnext.1.ts, 20, 88))
>T : Symbol(T, Decl(parser.pipeline.esnext.1.ts, 21, 24))
>source : Symbol(source, Decl(parser.pipeline.esnext.1.ts, 21, 27))
>Iterable : Symbol(Iterable, Decl(lib.es2015.iterable.d.ts, --, --))
>T : Symbol(T, Decl(parser.pipeline.esnext.1.ts, 21, 24))
>cb : Symbol(cb, Decl(parser.pipeline.esnext.1.ts, 21, 47))
>memo : Symbol(memo, Decl(parser.pipeline.esnext.1.ts, 21, 53))
>T : Symbol(T, Decl(parser.pipeline.esnext.1.ts, 21, 24))
>value : Symbol(value, Decl(parser.pipeline.esnext.1.ts, 21, 61))
>T : Symbol(T, Decl(parser.pipeline.esnext.1.ts, 21, 24))
>T : Symbol(T, Decl(parser.pipeline.esnext.1.ts, 21, 24))
>initial : Symbol(initial, Decl(parser.pipeline.esnext.1.ts, 21, 77))
>T : Symbol(T, Decl(parser.pipeline.esnext.1.ts, 21, 24))
>T : Symbol(T, Decl(parser.pipeline.esnext.1.ts, 21, 24))
[1, 2, 3]
|> map(?, x => x * 2)
>map : Symbol(map, Decl(parser.pipeline.esnext.1.ts, 17, 22))
>x : Symbol(x, Decl(parser.pipeline.esnext.1.ts, 23, 13))
>x : Symbol(x, Decl(parser.pipeline.esnext.1.ts, 23, 13))
|> filter(?, x => x > 2)
>filter : Symbol(filter, Decl(parser.pipeline.esnext.1.ts, 19, 82))
>x : Symbol(x, Decl(parser.pipeline.esnext.1.ts, 24, 16))
>x : Symbol(x, Decl(parser.pipeline.esnext.1.ts, 24, 16))
|> reduce(?, (x, y) => x + y, 0);
>reduce : Symbol(reduce, Decl(parser.pipeline.esnext.1.ts, 20, 88))
>x : Symbol(x, Decl(parser.pipeline.esnext.1.ts, 25, 18))
>y : Symbol(y, Decl(parser.pipeline.esnext.1.ts, 25, 20))
>x : Symbol(x, Decl(parser.pipeline.esnext.1.ts, 25, 18))
>y : Symbol(y, Decl(parser.pipeline.esnext.1.ts, 25, 20))

View File

@ -0,0 +1,187 @@
=== tests/cases/conformance/parser/esnext/parser.pipeline.esnext.1.ts ===
// single argument
declare function f1(x: number): string;
>f1 : (x: number) => string
>x : number
1 |> f1;
>1 |> f1 : string
>1 : 1
>f1 : (x: number) => string
1 |> f1(?);
>1 |> f1(?) : string
>1 : 1
>f1(?) : (x: number) => string
>f1 : (x: number) => string
(1) |> f1;
>(1) |> f1 : string
>(1) : 1
>1 : 1
>f1 : (x: number) => string
(1) |> f1(?);
>(1) |> f1(?) : string
>(1) : 1
>1 : 1
>f1(?) : (x: number) => string
>f1 : (x: number) => string
// multiple argument
declare function f2(x: number, y: number): string;
>f2 : (x: number, y: number) => string
>x : number
>y : number
(1, 2) |> f2;
>(1, 2) |> f2 : string
>(1, 2) : 2
>1, 2 : 2
>1 : 1
>2 : 2
>f2 : (x: number, y: number) => string
(1, 2) |> f2(?, ?);
>(1, 2) |> f2(?, ?) : string
>(1, 2) : 2
>1, 2 : 2
>1 : 1
>2 : 2
>f2(?, ?) : (x: number, y: number) => string
>f2 : (x: number, y: number) => string
// multiple steps
declare function f3(x: string): boolean;
>f3 : (x: string) => boolean
>x : string
declare function f4(x: string, y: number): boolean;
>f4 : (x: string, y: number) => boolean
>x : string
>y : number
1 |> f1 |> f3;
>1 |> f1 |> f3 : boolean
>1 |> f1 : string
>1 : 1
>f1 : (x: number) => string
>f3 : (x: string) => boolean
1 |> f1(?) |> f3;
>1 |> f1(?) |> f3 : boolean
>1 |> f1(?) : string
>1 : 1
>f1(?) : (x: number) => string
>f1 : (x: number) => string
>f3 : (x: string) => boolean
1 |> f1 |> f3(?);
>1 |> f1 |> f3(?) : boolean
>1 |> f1 : string
>1 : 1
>f1 : (x: number) => string
>f3(?) : (x: string) => boolean
>f3 : (x: string) => boolean
1 |> f1(?) |> f3(?);
>1 |> f1(?) |> f3(?) : boolean
>1 |> f1(?) : string
>1 : 1
>f1(?) : (x: number) => string
>f1 : (x: number) => string
>f3(?) : (x: string) => boolean
>f3 : (x: string) => boolean
(1 |> f1(?), 2) |> f4;
>(1 |> f1(?), 2) |> f4 : boolean
>(1 |> f1(?), 2) : 2
>1 |> f1(?), 2 : 2
>1 |> f1(?) : string
>1 : 1
>f1(?) : (x: number) => string
>f1 : (x: number) => string
>2 : 2
>f4 : (x: string, y: number) => boolean
// use case
declare function map<T, U>(source: Iterable<T>, cb: (value: T) => U): Iterable<U>;
>map : <T, U>(source: Iterable<T>, cb: (value: T) => U) => Iterable<U>
>T : T
>U : U
>source : Iterable<T>
>Iterable : Iterable<T>
>T : T
>cb : (value: T) => U
>value : T
>T : T
>U : U
>Iterable : Iterable<T>
>U : U
declare function filter<T>(source: Iterable<T>, cb: (value: T) => boolean): Iterable<T>;
>filter : <T>(source: Iterable<T>, cb: (value: T) => boolean) => Iterable<T>
>T : T
>source : Iterable<T>
>Iterable : Iterable<T>
>T : T
>cb : (value: T) => boolean
>value : T
>T : T
>Iterable : Iterable<T>
>T : T
declare function reduce<T>(source: Iterable<T>, cb: (memo: T, value: T) => T, initial: T): T;
>reduce : <T>(source: Iterable<T>, cb: (memo: T, value: T) => T, initial: T) => T
>T : T
>source : Iterable<T>
>Iterable : Iterable<T>
>T : T
>cb : (memo: T, value: T) => T
>memo : T
>T : T
>value : T
>T : T
>T : T
>initial : T
>T : T
>T : T
[1, 2, 3]
>[1, 2, 3] |> map(?, x => x * 2) |> filter(?, x => x > 2) |> reduce(?, (x, y) => x + y, 0) : number
>[1, 2, 3] |> map(?, x => x * 2) |> filter(?, x => x > 2) : Iterable<number>
>[1, 2, 3] |> map(?, x => x * 2) : Iterable<number>
>[1, 2, 3] : number[]
>1 : 1
>2 : 2
>3 : 3
|> map(?, x => x * 2)
>map(?, x => x * 2) : <T>(source: Iterable<T>) => Iterable<number>
>map : <T, U>(source: Iterable<T>, cb: (value: T) => U) => Iterable<U>
>x => x * 2 : (x: number) => number
>x : number
>x * 2 : number
>x : number
>2 : 2
|> filter(?, x => x > 2)
>filter(?, x => x > 2) : <T>(source: Iterable<T>) => Iterable<T>
>filter : <T>(source: Iterable<T>, cb: (value: T) => boolean) => Iterable<T>
>x => x > 2 : (x: number) => boolean
>x : number
>x > 2 : boolean
>x : number
>2 : 2
|> reduce(?, (x, y) => x + y, 0);
>reduce(?, (x, y) => x + y, 0) : (source: Iterable<number>) => number
>reduce : <T>(source: Iterable<T>, cb: (memo: T, value: T) => T, initial: T) => T
>(x, y) => x + y : (x: number, y: number) => number
>x : number
>y : number
>x + y : number
>x : number
>y : number
>0 : 0

View File

@ -0,0 +1,18 @@
// @target: esnext
// @noEmit: true
// @lib: es2015
// single argument
declare function f1(this: number): string;
1 :: f1;
1 :: f1();
// multiple steps
declare function f2(this: string): boolean;
1 :: f1() :: f2();
// use cases
declare function map<T, U>(this: Iterable<T>, cb: (value: T) => U): Iterable<U>;
declare function filter<T>(this: Iterable<T>, cb: (value: T) => boolean): Iterable<T>;
declare function reduce<T>(this: Iterable<T>, cb: (memo: T, value: T) => T, initial: T): T;
[1, 2, 3]
:: map(x => x * 2)
:: filter(x => x > 2)
:: reduce((x, y) => x + y, 0);

View File

@ -0,0 +1,32 @@
// @target: esnext
// @noEmit: true
declare function f(a: number, b: number, ...c: number[]): void;
declare const o: { m(a: number, b: number, ...c: number[]): void; };
// positional elements
f(?, 0);
f(0, ?);
f(?, ?);
o.m(?, 0);
o.m(0, ?);
o.m(?, ?);
// ordinal positional elements
f(?0, 0);
f(0, ?0);
f(?0, ?1);
f(?1, ?0);
o.m(?0, 0);
o.m(0, ?0);
o.m(?0, ?1);
o.m(?1, ?0);
// positional spread element
f(0, 1, ...);
f(0, 1, ..., 2);
o.m(0, 1, ...);
o.m(0, 1, ..., 2);
// mixed
f(?, 0, ...);
f(0, ?, ...);
f(0, 1, ..., ?0);
o.m(?, 0, ...);
o.m(0, ?, ...);
o.m(0, 1, ..., ?0);

View File

@ -0,0 +1,29 @@
// @target: esnext
// @noEmit: true
// @lib: es2015
// single argument
declare function f1(x: number): string;
1 |> f1;
1 |> f1(?);
(1) |> f1;
(1) |> f1(?);
// multiple argument
declare function f2(x: number, y: number): string;
(1, 2) |> f2;
(1, 2) |> f2(?, ?);
// multiple steps
declare function f3(x: string): boolean;
declare function f4(x: string, y: number): boolean;
1 |> f1 |> f3;
1 |> f1(?) |> f3;
1 |> f1 |> f3(?);
1 |> f1(?) |> f3(?);
(1 |> f1(?), 2) |> f4;
// use case
declare function map<T, U>(source: Iterable<T>, cb: (value: T) => U): Iterable<U>;
declare function filter<T>(source: Iterable<T>, cb: (value: T) => boolean): Iterable<T>;
declare function reduce<T>(source: Iterable<T>, cb: (memo: T, value: T) => T, initial: T): T;
[1, 2, 3]
|> map(?, x => x * 2)
|> filter(?, x => x > 2)
|> reduce(?, (x, y) => x + y, 0);