Skip to content

Order of methods affects validity of instance variables #1016

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

Closed
gvanrossum opened this issue Nov 27, 2015 · 5 comments
Closed

Order of methods affects validity of instance variables #1016

gvanrossum opened this issue Nov 27, 2015 · 5 comments
Labels

Comments

@gvanrossum
Copy link
Member

Consider:

class C(object):
    def foo(self) -> None:
        self.bar()
        print(self.x)
    def bar(self) -> None:
        self.x = 42

This fails:

/Users/guido/mypy_tests/mypy_gen.py: note: In member "foo" of class "C":
/Users/guido/mypy_tests/mypy_gen.py:4: error: Cannot determine type of 'x'

This is apparently because bar() hasn't been analyzed yet when foo() is being analyzed. If we swap the definitions the program is clean.

@JukkaL
Copy link
Collaborator

JukkaL commented Nov 27, 2015

Basically this is a similar issue to #481. The reason is that type inference goes from top to bottom in a file, and when you refer to something that hasn't been inferred yet mypy complains.

I haven't prioritized this because it's usuall;y easy to work around by giving an explicit annotation:

class C(object):
    def foo(self) -> None:
        self.bar()
        print(self.x)
    def bar(self) -> None:
        self.x = 42  # type: int

Another workaround (but this can change semantics):

class C(object):
    x = None  # type: int   # or "x = 0"
    def foo(self) -> None:
        self.bar()
        print(self.x)
    def bar(self) -> None:
        self.x = 42

The general fix would be run type checking in multiple passes. We wouldn't report errors when mypy can't determine the type immediately. Instead, the enclosing function would be added to a worklist, and after doing a full type checker run over a module (or a set of cyclically dependent modules) we'd type check items in the worklist again, and we'd repeat this until we worklist doesn't get any smaller in an iteration or we hit some max number of iterations.

@JukkaL JukkaL added the feature label Nov 27, 2015
@JukkaL
Copy link
Collaborator

JukkaL commented Nov 27, 2015

A partial, quick fix would be to run simple type inference as part of semantic analysis and infer types for variables where the initializer is a simple expression (and where initialization doesn't happen in an if statement, for example). So we could infer these types always, independent of order:

a = 1
b = 1.0
c = 'x'
d = b'x'
e = {'x': 'y'}
f = [0]
g = (1, 'x')

These would cover a non-trivial subset of initializers. Not sure whether it's worth it to special case these, however.

@gvanrossum
Copy link
Member Author

Oh wow, I would never have guessed that adding # type: ... would work. The actual case where this stumped me didn't have a simple type on the RHS, but inferring from basic constants still sounds like a good idea to reduce the impact of this. (OTOH until this is solved better you've got job security explaining things like this. :-)

@JukkaL
Copy link
Collaborator

JukkaL commented Nov 29, 2015

Yeah, this is a pretty bad issue. I thought about this some more and solving this for a single file (i.e. not for cyclically dependent modules) shouldn't be too hard, maybe one or two days of work -- but it could be more, as changing this would change a bunch of subtle implicit assumptions in the implementation.

Inferring types from literals should be a few hours to implement. As a quick fix, I'll try adding a more informative error message (something like Consider adding a "# type:" annotation for "x" in "ClassName").

@JukkaL
Copy link
Collaborator

JukkaL commented Feb 1, 2016

Mypy now does 2-pass type inference within a single file.

@JukkaL JukkaL closed this as completed Feb 1, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants