-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Stricter relational comparisons checking valueOf
#52807
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -23029,6 +23029,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { | |||||||
type; | ||||||||
} | ||||||||
|
||||||||
function getValueOfResult(type: Type): Type { | ||||||||
const valueOf = getPropertyOfType(type, "valueOf" as __String); | ||||||||
if (valueOf) { | ||||||||
const signatures = getSignaturesOfType(getTypeOfSymbol(valueOf), ts.SignatureKind.Call); | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
if (signatures && signatures.length > 0) { | ||||||||
const returnType = getReturnTypeOfSignature(signatures[0]); | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This favors the first signature in an overload list, while usually in places where we're overload-blind today we usually favor the last overload in the list. Maybe |
||||||||
return returnType; | ||||||||
} | ||||||||
} | ||||||||
return type; | ||||||||
} | ||||||||
|
||||||||
function getWidenedLiteralType(type: Type): Type { | ||||||||
return type.flags & TypeFlags.EnumLike && isFreshLiteralType(type) ? getBaseTypeOfEnumLikeType(type as LiteralType) : | ||||||||
type.flags & TypeFlags.StringLiteral && isFreshLiteralType(type) ? stringType : | ||||||||
|
@@ -36498,10 +36510,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { | |||||||
if (isTypeAny(left) || isTypeAny(right)) { | ||||||||
return true; | ||||||||
} | ||||||||
// Only collect 'valueOf' results here so that the error message doesn't display | ||||||||
// "cannot compare Object to Object" when comparing e.g. [] > [] | ||||||||
if (!(left.flags & TypeFlags.Primitive)) left = getValueOfResult(left); | ||||||||
if (!(right.flags & TypeFlags.Primitive)) right = getValueOfResult(right); | ||||||||
|
||||||||
const leftAssignableToNumber = isTypeAssignableTo(left, numberOrBigIntType); | ||||||||
const rightAssignableToNumber = isTypeAssignableTo(right, numberOrBigIntType); | ||||||||
return leftAssignableToNumber && rightAssignableToNumber || | ||||||||
!leftAssignableToNumber && !rightAssignableToNumber && areTypesComparable(left, right); | ||||||||
if (leftAssignableToNumber) { | ||||||||
const rightAssignableToNumber = isTypeAssignableTo(right, numberOrBigIntType); | ||||||||
if (rightAssignableToNumber) return true; | ||||||||
} | ||||||||
return isTypeAssignableTo(left, stringType) && isTypeAssignableTo(right, stringType); | ||||||||
}); | ||||||||
} | ||||||||
return booleanType; | ||||||||
|
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithIdenticalTypeParameter.ts(2,14): error TS2365: Operator '<' cannot be applied to types 'T' and 'T'. | ||
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithIdenticalTypeParameter.ts(3,14): error TS2365: Operator '>' cannot be applied to types 'T' and 'T'. | ||
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithIdenticalTypeParameter.ts(4,14): error TS2365: Operator '<=' cannot be applied to types 'T' and 'T'. | ||
tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithIdenticalTypeParameter.ts(5,14): error TS2365: Operator '>=' cannot be applied to types 'T' and 'T'. | ||
|
||
|
||
==== tests/cases/conformance/expressions/binaryOperators/comparisonOperator/comparisonOperatorWithIdenticalTypeParameter.ts (4 errors) ==== | ||
function foo<T>(t: T) { | ||
var r1 = t < t; | ||
~~~~~ | ||
!!! error TS2365: Operator '<' cannot be applied to types 'T' and 'T'. | ||
var r2 = t > t; | ||
~~~~~ | ||
!!! error TS2365: Operator '>' cannot be applied to types 'T' and 'T'. | ||
var r3 = t <= t; | ||
~~~~~~ | ||
!!! error TS2365: Operator '<=' cannot be applied to types 'T' and 'T'. | ||
var r4 = t >= t; | ||
~~~~~~ | ||
!!! error TS2365: Operator '>=' cannot be applied to types 'T' and 'T'. | ||
var r5 = t == t; | ||
var r6 = t != t; | ||
var r7 = t === t; | ||
var r8 = t !== t; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI annoying auto-import thing here, but should should just be
SignatureKind.Call
; sometimes thets
prefix appears first in the completion list and gets used (and that's one reason why I'm trying to get us to remove them everywhere).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Main no longer has this
ts
import so when you merge from main next, you'll have to fix this (and then never have to worry about again).