Skip to content
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

Cannot infer type argument when mixing int and float #2035

Closed
JukkaL opened this issue Aug 18, 2016 · 6 comments
Closed

Cannot infer type argument when mixing int and float #2035

JukkaL opened this issue Aug 18, 2016 · 6 comments

Comments

@JukkaL
Copy link
Collaborator

JukkaL commented Aug 18, 2016

Mypy complains about this code, even though it looks fine to me:

from typing import Sequence, TypeVar

_T = TypeVar('_T')

def bisect_left(a: Sequence[_T], x: _T) -> int: ...

bisect_left([1, 2, 3], 5.391)  #  Cannot infer type argument 1 of "bisect_left"

This doesn't seem to be related to promotions, as it also happens with user-defined types:

class A: pass
class B(A): pass

bisect_left([B()], A())   # same error
@matthiaskramm
Copy link
Contributor

Just out of curiosity: What is mypy supposed to do, when having

def f(x: _T, y: _T)

and a call

f(A(), B())

Should it try to "promote" either A to B or B to A? Or should it try to find a common base class between the two?

Or would the magic that makes bisect_left work not actually apply for the non-sequence case?

@JukkaL
Copy link
Collaborator Author

JukkaL commented Aug 19, 2016

It looks for a value for _T that is compatible for all arguments. There are some additional rules, such as that we generally don't infer Any types, even though they would be valid everywhere, and we favor narrower types as results. It tries to look for common base classes and it also considers promotions such as int -> float. In your example, if B is a subclass of A, so we'd infer _T = A. object would also be a valid result, but since A is narrower we prefer that.

The non-sequence case should work already -- it's the sequence case that is broken.

@gvanrossum gvanrossum added this to the Future milestone Aug 25, 2016
@gvanrossum gvanrossum removed this from the Future milestone Mar 29, 2017
@graingert
Copy link
Contributor

any way of specifying type arguments to a function?

class A: pass
class B(A): pass

bisect_left[A]([B()], A())   # same error

@JukkaL
Copy link
Collaborator Author

JukkaL commented Mar 31, 2017

Not directly, but you can use cast within the arguments to make all argument types match exactly, so it's obvious what the value of a type argument will be. Example:

from typing import cast

class A: pass
class B(A): pass

bisect_left([cast(A, B())], A())  # ok

@graingert
Copy link
Contributor

@JukkaL here's an issue about what I mean #3096

@JukkaL
Copy link
Collaborator Author

JukkaL commented Mar 19, 2018

Increasing priority since there was a user question that boils down to this issue and the fix seems simple.

@JukkaL JukkaL self-assigned this Mar 19, 2018
ilevkivskyi pushed a commit to ilevkivskyi/mypy that referenced this issue Oct 21, 2018
Fixes python#2035.

Conflicts:
	test-data/unit/check-inference-context.test
ilevkivskyi added a commit that referenced this issue Oct 22, 2018
Fixes #2035

Note that in two tests we now infer `object` instead of giving an error. This may be not what a user expects, but I think this is still OK, and after #3816 mypy will always ask for an annotation in such cases.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants