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

Fix meta level on member access #2809

Merged
merged 2 commits into from
Feb 7, 2017

Conversation

ilevkivskyi
Copy link
Member

Fixes #2804

The problem is that analize_member_access calls freshen_function_type_vars if the member is a function (i.e. method). This is necessary to not mix the type variables during type inference of generic methods inside generic functions. However, if the method does not participate in type inference, type variables are left in meta_level = 1 state. This causes the error, since the types could not be serialized in the middle of type inference.

In this PR I propose to restore meta_level = 0 on member access, this is safe, since anyway, check_call always calls freshen_function_type_vars on callee (for generic functions, generic methods, etc).

class Mapping(Generic[T, U]): pass
class Mapping(Generic[T, U]):
@overload
def get(self, k: T) -> Optional[U]: pass
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you move this to Dict in fixture/dict.pyi? We try to keep the typing.pyi stub pretty minimal.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, sure, I moved this to dict.pyi in a new commit.

@@ -990,6 +990,13 @@ def analyze_ordinary_member_access(self, e: MemberExpr,
e.name, original_type, e, is_lvalue, False, False,
self.named_type, self.not_ready_callback, self.msg,
original_type=original_type, chk=self.chk)
if isinstance(member_type, CallableType):
for v in member_type.variables:
v.id.meta_level = 0
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we just switch the meta level, I think that we can get an id conflict between type variables in the 0 level if we happen to be in a generic function which has some additional type variables in scope. Not sure what's the best way to work around this. What about serializing the meta levels of type variables as well?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can get an id conflict between type variables in the 0 level if we happen to be in a generic function which has some additional type variables in scope

I was also thinking about such possibility, but I didn't manage to trigger this error so I thought maybe I was wrong. Now you are also saying this and I am worried again. I need to think more about this tomorrow, maybe there is a way to exclude such possibility.

What about serializing the meta levels of type variables as well?

I think that serialazing type variables with meta_level == 1 is not a good idea. As I understand, this means that they are in process of being inferred, while serialazing is used for completely analysed modules, or am I wrong?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, your original approach actually seems to be fine, since we are should always freshen the type variables before using them in type inference, so I think that there can be no conflict.

@ilevkivskyi
Copy link
Member Author

@gvanrossum What does the new label blocked mean? It looks so scary.

@gvanrossum gvanrossum removed the blocked label Feb 6, 2017
@gvanrossum
Copy link
Member

Sorry, the "blocked" label means that the PR is waiting for someone or something not on the core mypy team -- typically waiting for the author to push more commits (e.g. response to code review or a rebase) or when it's waiting for another issue to be fixed, or perhaps on a difficult decision. This is a signal to the core team to reduce priority reviewing. We're still experimenting with this workflow -- we don't have a way to signal exactly what it's waiting for, nor do we have a bot yet that automatically unblocks when the anticipated event happens. (Nor have we consistently applied it yet to the mypy repo -- I did do a pass over typeshed.) Sorry to scare you! I've removed the label now that you've responded to the code review.

@ilevkivskyi
Copy link
Member Author

@gvanrossum
Thank you for the detailed explanation! It looks like a more "calm" color could better reflect the meaning of this label. I realize that the workload for the core team is high. Indeed, it could be helpful to have labels for PRs. I have seen other GitHub repos are using topic labels for PRs.

@gvanrossum
Copy link
Member

gvanrossum commented Feb 7, 2017 via email

@ilevkivskyi
Copy link
Member Author

Do you have a suggestion for a better color?

White text on blue background might be better (the PR is "cold", waits for a new input).

@JukkaL
Copy link
Collaborator

JukkaL commented Feb 7, 2017

I think that this is actually good now and my concerns weren't valid. Thanks for the PR!

@JukkaL JukkaL merged commit a2d654b into python:master Feb 7, 2017
@ilevkivskyi
Copy link
Member Author

@JukkaL
There still one minor question, maybe it makes sense move this code inside analize_member_access at the end of the function? (just to keep it clearer for people who will later read this)

@JukkaL
Copy link
Collaborator

JukkaL commented Feb 7, 2017

Hmm I just noticed that there are several calls to analyze_member_access in checkexpr.py. It's unclear whether we should always tweak the type variables or not at the end.

@ilevkivskyi
Copy link
Member Author

@JukkaL

Hmm I just noticed that there are several calls to analyze_member_access in checkexpr.py. It's unclear whether we should always tweak the type variables or not at the end.

OK, I will take a look at those and will make an additional PR if necessary.

@ilevkivskyi
Copy link
Member Author

@JukkaL

Hmm I just noticed that there are several calls to analyze_member_access in checkexpr.py. It's unclear whether we should always tweak the type variables or not at the end.

I investigated this, and it looks like wee need to do this everywhere, one can still trigger the crash in serialize with

from typing import TypeVar
T = TypeVar('T')

class C:
    def m(self, x: T) -> T:
        return x

class D(C):
    def __init__(self) -> None:
        self.d = super().m

I will make a PR to fix this soon.

@ilevkivskyi
Copy link
Member Author

OK, here is the PR I promised #2847

gvanrossum pushed a commit that referenced this pull request Feb 28, 2017
This is a follow-up of PR #2809. This PR makes a more robust fix by moving the relevant piece of code from visit_member_expr to analyze_member_access. The latter, as noted by @JukkaL also used few times outside the former (for example in analyze_super).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants