diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 67a733cbbb811..918bd0a1f40a4 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -39252,7 +39252,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } return numberType; } - return getUnaryResultType(operandType); + return getUnaryArithmeticResultType(operandType); case SyntaxKind.ExclamationToken: checkTruthinessOfType(operandType, node.operand); const facts = getTypeFacts(operandType, TypeFacts.Truthy | TypeFacts.Falsy); @@ -39270,7 +39270,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { Diagnostics.The_operand_of_an_increment_or_decrement_operator_may_not_be_an_optional_property_access, ); } - return getUnaryResultType(operandType); + return getUnaryArithmeticResultType(operandType); } return errorType; } @@ -39293,11 +39293,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { Diagnostics.The_operand_of_an_increment_or_decrement_operator_may_not_be_an_optional_property_access, ); } - return getUnaryResultType(operandType); + return getUnaryArithmeticResultType(operandType); } - function getUnaryResultType(operandType: Type): Type { - if (maybeTypeOfKind(operandType, TypeFlags.BigIntLike)) { + function getUnaryArithmeticResultType(operandType: Type): Type { + if (maybeTypeOfKindConsideringBaseConstraint(operandType, TypeFlags.BigIntLike)) { return isTypeAssignableToKind(operandType, TypeFlags.AnyOrUnknown) || maybeTypeOfKind(operandType, TypeFlags.NumberLike) ? numberOrBigIntType : bigintType; @@ -40009,35 +40009,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // otherwise just check each operand separately and report errors as normal const leftOk = checkArithmeticOperandType(left, leftType, Diagnostics.The_left_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_bigint_or_an_enum_type, /*isAwaitValid*/ true); const rightOk = checkArithmeticOperandType(right, rightType, Diagnostics.The_right_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_bigint_or_an_enum_type, /*isAwaitValid*/ true); - let resultType: Type; - // If both are any or unknown, allow operation; assume it will resolve to number - if ( - (isTypeAssignableToKind(leftType, TypeFlags.AnyOrUnknown) && isTypeAssignableToKind(rightType, TypeFlags.AnyOrUnknown)) || - // Or, if neither could be bigint, implicit coercion results in a number result - !(maybeTypeOfKind(leftType, TypeFlags.BigIntLike) || maybeTypeOfKind(rightType, TypeFlags.BigIntLike)) - ) { - resultType = numberType; - } - // At least one is assignable to bigint, so check that both are - else if (bothAreBigIntLike(leftType, rightType)) { - switch (operator) { - case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: - case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: - reportOperatorError(); - break; - case SyntaxKind.AsteriskAsteriskToken: - case SyntaxKind.AsteriskAsteriskEqualsToken: - if (languageVersion < ScriptTarget.ES2016) { - error(errorNode, Diagnostics.Exponentiation_cannot_be_performed_on_bigint_values_unless_the_target_option_is_set_to_es2016_or_later); - } - } - resultType = bigintType; - } - // Exactly one of leftType/rightType is assignable to bigint - else { - reportOperatorError(bothAreBigIntLike); - resultType = errorType; - } + + const resultType = getBinaryArithmeticResultType(leftType, rightType); if (leftOk && rightOk) { checkAssignmentOperator(resultType); switch (operator) { @@ -40228,6 +40201,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return Debug.fail(); } + function getBinaryArithmeticResultType(leftType: Type, rightType: Type): Type { + if (isTypeAssignableToKind(leftType, TypeFlags.AnyOrUnknown) && isTypeAssignableToKind(rightType, TypeFlags.AnyOrUnknown)) { + // If both are any or unknown, allow operation; assume it will resolve to number + // (This is unsound, but it is not practical for untyped programs to + // have `bigint|number` inferred everywhere; #41741) + return numberType; + } + else if (!maybeTypeOfKindConsideringBaseConstraint(leftType, TypeFlags.BigIntLike) && !maybeTypeOfKindConsideringBaseConstraint(rightType, TypeFlags.BigIntLike)) { + // If neither could be bigint, implicit coercion results in a number result + return numberType; + } + // At least one is assignable to bigint, so check that both are + else if (bothAreBigIntLike(leftType, rightType)) { + switch (operator) { + case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: + case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: + reportOperatorError(); + break; + case SyntaxKind.AsteriskAsteriskToken: + case SyntaxKind.AsteriskAsteriskEqualsToken: + if (languageVersion < ScriptTarget.ES2016) { + error(errorNode, Diagnostics.Exponentiation_cannot_be_performed_on_bigint_values_unless_the_target_option_is_set_to_es2016_or_later); + } + } + return bigintType; + } + + // Exactly one of leftType/rightType is assignable to bigint + reportOperatorError(bothAreBigIntLike); + return errorType; + } + function bothAreBigIntLike(left: Type, right: Type): boolean { return isTypeAssignableToKind(left, TypeFlags.BigIntLike) && isTypeAssignableToKind(right, TypeFlags.BigIntLike); } diff --git a/tests/baselines/reference/bigintSubtypingTypeParameter.js b/tests/baselines/reference/bigintSubtypingTypeParameter.js new file mode 100644 index 0000000000000..ed83420e3b368 --- /dev/null +++ b/tests/baselines/reference/bigintSubtypingTypeParameter.js @@ -0,0 +1,77 @@ +//// [tests/cases/compiler/bigintSubtypingTypeParameter.ts] //// + +//// [bigintSubtypingTypeParameter.ts] +function bigintSubtypeAdder(a: T, b: T): bigint { + const sum = a + b; + return sum; +} + +function bigintSubtypeDifference(a: T, b: T): bigint { + const difference = a - b; + return difference; +} + +function bigintSubtypeArithmeticNegation(a: T): bigint { + const negation = -a; + return negation; +} + +function bigintSubtypeBitInverse(a: T): bigint { + const bitInverse = ~a; + return bitInverse; +} + +function bigintSubtypeBitand(a: T, b: T): bigint { + const bitand = a & b; + return bitand; +} + +function bigintSubtypeBitor(a: T, b: T): bigint { + const bitor = a | b; + return bitor; +} + +function bigintSubtypeLeftshift(a: T, b: T): bigint { + const leftshift = a << b; + return leftshift; +} + +function bigintSubtypeRightshift(a: T, b: T): bigint { + const rightshift = a >> b; + return rightshift; +} + + +//// [bigintSubtypingTypeParameter.js] +function bigintSubtypeAdder(a, b) { + var sum = a + b; + return sum; +} +function bigintSubtypeDifference(a, b) { + var difference = a - b; + return difference; +} +function bigintSubtypeArithmeticNegation(a) { + var negation = -a; + return negation; +} +function bigintSubtypeBitInverse(a) { + var bitInverse = ~a; + return bitInverse; +} +function bigintSubtypeBitand(a, b) { + var bitand = a & b; + return bitand; +} +function bigintSubtypeBitor(a, b) { + var bitor = a | b; + return bitor; +} +function bigintSubtypeLeftshift(a, b) { + var leftshift = a << b; + return leftshift; +} +function bigintSubtypeRightshift(a, b) { + var rightshift = a >> b; + return rightshift; +} diff --git a/tests/baselines/reference/bigintSubtypingTypeParameter.symbols b/tests/baselines/reference/bigintSubtypingTypeParameter.symbols new file mode 100644 index 0000000000000..02e119f41de65 --- /dev/null +++ b/tests/baselines/reference/bigintSubtypingTypeParameter.symbols @@ -0,0 +1,133 @@ +//// [tests/cases/compiler/bigintSubtypingTypeParameter.ts] //// + +=== bigintSubtypingTypeParameter.ts === +function bigintSubtypeAdder(a: T, b: T): bigint { +>bigintSubtypeAdder : Symbol(bigintSubtypeAdder, Decl(bigintSubtypingTypeParameter.ts, 0, 0)) +>T : Symbol(T, Decl(bigintSubtypingTypeParameter.ts, 0, 28)) +>a : Symbol(a, Decl(bigintSubtypingTypeParameter.ts, 0, 46)) +>T : Symbol(T, Decl(bigintSubtypingTypeParameter.ts, 0, 28)) +>b : Symbol(b, Decl(bigintSubtypingTypeParameter.ts, 0, 51)) +>T : Symbol(T, Decl(bigintSubtypingTypeParameter.ts, 0, 28)) + + const sum = a + b; +>sum : Symbol(sum, Decl(bigintSubtypingTypeParameter.ts, 1, 6)) +>a : Symbol(a, Decl(bigintSubtypingTypeParameter.ts, 0, 46)) +>b : Symbol(b, Decl(bigintSubtypingTypeParameter.ts, 0, 51)) + + return sum; +>sum : Symbol(sum, Decl(bigintSubtypingTypeParameter.ts, 1, 6)) +} + +function bigintSubtypeDifference(a: T, b: T): bigint { +>bigintSubtypeDifference : Symbol(bigintSubtypeDifference, Decl(bigintSubtypingTypeParameter.ts, 3, 1)) +>T : Symbol(T, Decl(bigintSubtypingTypeParameter.ts, 5, 33)) +>a : Symbol(a, Decl(bigintSubtypingTypeParameter.ts, 5, 51)) +>T : Symbol(T, Decl(bigintSubtypingTypeParameter.ts, 5, 33)) +>b : Symbol(b, Decl(bigintSubtypingTypeParameter.ts, 5, 56)) +>T : Symbol(T, Decl(bigintSubtypingTypeParameter.ts, 5, 33)) + + const difference = a - b; +>difference : Symbol(difference, Decl(bigintSubtypingTypeParameter.ts, 6, 6)) +>a : Symbol(a, Decl(bigintSubtypingTypeParameter.ts, 5, 51)) +>b : Symbol(b, Decl(bigintSubtypingTypeParameter.ts, 5, 56)) + + return difference; +>difference : Symbol(difference, Decl(bigintSubtypingTypeParameter.ts, 6, 6)) +} + +function bigintSubtypeArithmeticNegation(a: T): bigint { +>bigintSubtypeArithmeticNegation : Symbol(bigintSubtypeArithmeticNegation, Decl(bigintSubtypingTypeParameter.ts, 8, 1)) +>T : Symbol(T, Decl(bigintSubtypingTypeParameter.ts, 10, 41)) +>a : Symbol(a, Decl(bigintSubtypingTypeParameter.ts, 10, 59)) +>T : Symbol(T, Decl(bigintSubtypingTypeParameter.ts, 10, 41)) + + const negation = -a; +>negation : Symbol(negation, Decl(bigintSubtypingTypeParameter.ts, 11, 6)) +>a : Symbol(a, Decl(bigintSubtypingTypeParameter.ts, 10, 59)) + + return negation; +>negation : Symbol(negation, Decl(bigintSubtypingTypeParameter.ts, 11, 6)) +} + +function bigintSubtypeBitInverse(a: T): bigint { +>bigintSubtypeBitInverse : Symbol(bigintSubtypeBitInverse, Decl(bigintSubtypingTypeParameter.ts, 13, 1)) +>T : Symbol(T, Decl(bigintSubtypingTypeParameter.ts, 15, 33)) +>a : Symbol(a, Decl(bigintSubtypingTypeParameter.ts, 15, 51)) +>T : Symbol(T, Decl(bigintSubtypingTypeParameter.ts, 15, 33)) + + const bitInverse = ~a; +>bitInverse : Symbol(bitInverse, Decl(bigintSubtypingTypeParameter.ts, 16, 6)) +>a : Symbol(a, Decl(bigintSubtypingTypeParameter.ts, 15, 51)) + + return bitInverse; +>bitInverse : Symbol(bitInverse, Decl(bigintSubtypingTypeParameter.ts, 16, 6)) +} + +function bigintSubtypeBitand(a: T, b: T): bigint { +>bigintSubtypeBitand : Symbol(bigintSubtypeBitand, Decl(bigintSubtypingTypeParameter.ts, 18, 1)) +>T : Symbol(T, Decl(bigintSubtypingTypeParameter.ts, 20, 29)) +>a : Symbol(a, Decl(bigintSubtypingTypeParameter.ts, 20, 47)) +>T : Symbol(T, Decl(bigintSubtypingTypeParameter.ts, 20, 29)) +>b : Symbol(b, Decl(bigintSubtypingTypeParameter.ts, 20, 52)) +>T : Symbol(T, Decl(bigintSubtypingTypeParameter.ts, 20, 29)) + + const bitand = a & b; +>bitand : Symbol(bitand, Decl(bigintSubtypingTypeParameter.ts, 21, 6)) +>a : Symbol(a, Decl(bigintSubtypingTypeParameter.ts, 20, 47)) +>b : Symbol(b, Decl(bigintSubtypingTypeParameter.ts, 20, 52)) + + return bitand; +>bitand : Symbol(bitand, Decl(bigintSubtypingTypeParameter.ts, 21, 6)) +} + +function bigintSubtypeBitor(a: T, b: T): bigint { +>bigintSubtypeBitor : Symbol(bigintSubtypeBitor, Decl(bigintSubtypingTypeParameter.ts, 23, 1)) +>T : Symbol(T, Decl(bigintSubtypingTypeParameter.ts, 25, 28)) +>a : Symbol(a, Decl(bigintSubtypingTypeParameter.ts, 25, 46)) +>T : Symbol(T, Decl(bigintSubtypingTypeParameter.ts, 25, 28)) +>b : Symbol(b, Decl(bigintSubtypingTypeParameter.ts, 25, 51)) +>T : Symbol(T, Decl(bigintSubtypingTypeParameter.ts, 25, 28)) + + const bitor = a | b; +>bitor : Symbol(bitor, Decl(bigintSubtypingTypeParameter.ts, 26, 6)) +>a : Symbol(a, Decl(bigintSubtypingTypeParameter.ts, 25, 46)) +>b : Symbol(b, Decl(bigintSubtypingTypeParameter.ts, 25, 51)) + + return bitor; +>bitor : Symbol(bitor, Decl(bigintSubtypingTypeParameter.ts, 26, 6)) +} + +function bigintSubtypeLeftshift(a: T, b: T): bigint { +>bigintSubtypeLeftshift : Symbol(bigintSubtypeLeftshift, Decl(bigintSubtypingTypeParameter.ts, 28, 1)) +>T : Symbol(T, Decl(bigintSubtypingTypeParameter.ts, 30, 32)) +>a : Symbol(a, Decl(bigintSubtypingTypeParameter.ts, 30, 50)) +>T : Symbol(T, Decl(bigintSubtypingTypeParameter.ts, 30, 32)) +>b : Symbol(b, Decl(bigintSubtypingTypeParameter.ts, 30, 55)) +>T : Symbol(T, Decl(bigintSubtypingTypeParameter.ts, 30, 32)) + + const leftshift = a << b; +>leftshift : Symbol(leftshift, Decl(bigintSubtypingTypeParameter.ts, 31, 6)) +>a : Symbol(a, Decl(bigintSubtypingTypeParameter.ts, 30, 50)) +>b : Symbol(b, Decl(bigintSubtypingTypeParameter.ts, 30, 55)) + + return leftshift; +>leftshift : Symbol(leftshift, Decl(bigintSubtypingTypeParameter.ts, 31, 6)) +} + +function bigintSubtypeRightshift(a: T, b: T): bigint { +>bigintSubtypeRightshift : Symbol(bigintSubtypeRightshift, Decl(bigintSubtypingTypeParameter.ts, 33, 1)) +>T : Symbol(T, Decl(bigintSubtypingTypeParameter.ts, 35, 33)) +>a : Symbol(a, Decl(bigintSubtypingTypeParameter.ts, 35, 51)) +>T : Symbol(T, Decl(bigintSubtypingTypeParameter.ts, 35, 33)) +>b : Symbol(b, Decl(bigintSubtypingTypeParameter.ts, 35, 56)) +>T : Symbol(T, Decl(bigintSubtypingTypeParameter.ts, 35, 33)) + + const rightshift = a >> b; +>rightshift : Symbol(rightshift, Decl(bigintSubtypingTypeParameter.ts, 36, 6)) +>a : Symbol(a, Decl(bigintSubtypingTypeParameter.ts, 35, 51)) +>b : Symbol(b, Decl(bigintSubtypingTypeParameter.ts, 35, 56)) + + return rightshift; +>rightshift : Symbol(rightshift, Decl(bigintSubtypingTypeParameter.ts, 36, 6)) +} + diff --git a/tests/baselines/reference/bigintSubtypingTypeParameter.types b/tests/baselines/reference/bigintSubtypingTypeParameter.types new file mode 100644 index 0000000000000..8d979e8bd9fdf --- /dev/null +++ b/tests/baselines/reference/bigintSubtypingTypeParameter.types @@ -0,0 +1,179 @@ +//// [tests/cases/compiler/bigintSubtypingTypeParameter.ts] //// + +=== bigintSubtypingTypeParameter.ts === +function bigintSubtypeAdder(a: T, b: T): bigint { +>bigintSubtypeAdder : (a: T, b: T) => bigint +> : ^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^ +>a : T +> : ^ +>b : T +> : ^ + + const sum = a + b; +>sum : bigint +> : ^^^^^^ +>a + b : bigint +> : ^^^^^^ +>a : T +> : ^ +>b : T +> : ^ + + return sum; +>sum : bigint +> : ^^^^^^ +} + +function bigintSubtypeDifference(a: T, b: T): bigint { +>bigintSubtypeDifference : (a: T, b: T) => bigint +> : ^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^ +>a : T +> : ^ +>b : T +> : ^ + + const difference = a - b; +>difference : bigint +> : ^^^^^^ +>a - b : bigint +> : ^^^^^^ +>a : T +> : ^ +>b : T +> : ^ + + return difference; +>difference : bigint +> : ^^^^^^ +} + +function bigintSubtypeArithmeticNegation(a: T): bigint { +>bigintSubtypeArithmeticNegation : (a: T) => bigint +> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ +>a : T +> : ^ + + const negation = -a; +>negation : bigint +> : ^^^^^^ +>-a : bigint +> : ^^^^^^ +>a : T +> : ^ + + return negation; +>negation : bigint +> : ^^^^^^ +} + +function bigintSubtypeBitInverse(a: T): bigint { +>bigintSubtypeBitInverse : (a: T) => bigint +> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ +>a : T +> : ^ + + const bitInverse = ~a; +>bitInverse : bigint +> : ^^^^^^ +>~a : bigint +> : ^^^^^^ +>a : T +> : ^ + + return bitInverse; +>bitInverse : bigint +> : ^^^^^^ +} + +function bigintSubtypeBitand(a: T, b: T): bigint { +>bigintSubtypeBitand : (a: T, b: T) => bigint +> : ^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^ +>a : T +> : ^ +>b : T +> : ^ + + const bitand = a & b; +>bitand : bigint +> : ^^^^^^ +>a & b : bigint +> : ^^^^^^ +>a : T +> : ^ +>b : T +> : ^ + + return bitand; +>bitand : bigint +> : ^^^^^^ +} + +function bigintSubtypeBitor(a: T, b: T): bigint { +>bigintSubtypeBitor : (a: T, b: T) => bigint +> : ^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^ +>a : T +> : ^ +>b : T +> : ^ + + const bitor = a | b; +>bitor : bigint +> : ^^^^^^ +>a | b : bigint +> : ^^^^^^ +>a : T +> : ^ +>b : T +> : ^ + + return bitor; +>bitor : bigint +> : ^^^^^^ +} + +function bigintSubtypeLeftshift(a: T, b: T): bigint { +>bigintSubtypeLeftshift : (a: T, b: T) => bigint +> : ^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^ +>a : T +> : ^ +>b : T +> : ^ + + const leftshift = a << b; +>leftshift : bigint +> : ^^^^^^ +>a << b : bigint +> : ^^^^^^ +>a : T +> : ^ +>b : T +> : ^ + + return leftshift; +>leftshift : bigint +> : ^^^^^^ +} + +function bigintSubtypeRightshift(a: T, b: T): bigint { +>bigintSubtypeRightshift : (a: T, b: T) => bigint +> : ^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^ +>a : T +> : ^ +>b : T +> : ^ + + const rightshift = a >> b; +>rightshift : bigint +> : ^^^^^^ +>a >> b : bigint +> : ^^^^^^ +>a : T +> : ^ +>b : T +> : ^ + + return rightshift; +>rightshift : bigint +> : ^^^^^^ +} + diff --git a/tests/cases/compiler/bigintSubtypingTypeParameter.ts b/tests/cases/compiler/bigintSubtypingTypeParameter.ts new file mode 100644 index 0000000000000..9d8c69040e5fe --- /dev/null +++ b/tests/cases/compiler/bigintSubtypingTypeParameter.ts @@ -0,0 +1,39 @@ +function bigintSubtypeAdder(a: T, b: T): bigint { + const sum = a + b; + return sum; +} + +function bigintSubtypeDifference(a: T, b: T): bigint { + const difference = a - b; + return difference; +} + +function bigintSubtypeArithmeticNegation(a: T): bigint { + const negation = -a; + return negation; +} + +function bigintSubtypeBitInverse(a: T): bigint { + const bitInverse = ~a; + return bitInverse; +} + +function bigintSubtypeBitand(a: T, b: T): bigint { + const bitand = a & b; + return bitand; +} + +function bigintSubtypeBitor(a: T, b: T): bigint { + const bitor = a | b; + return bitor; +} + +function bigintSubtypeLeftshift(a: T, b: T): bigint { + const leftshift = a << b; + return leftshift; +} + +function bigintSubtypeRightshift(a: T, b: T): bigint { + const rightshift = a >> b; + return rightshift; +}