-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Selftype - fallback to type(x) for classmethods #3633
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
Selftype - fallback to type(x) for classmethods #3633
Conversation
c5b7109
to
398f520
Compare
@@ -472,7 +472,7 @@ class B(A): pass | |||
tvars = [TypeVarDef(n, i + 1, [], builtin_type('builtins.object'), tv.variance) | |||
for (i, n), tv in zip(enumerate(info.type_vars), info.defn.type_vars)] | |||
if is_classmethod: | |||
t = bind_self(t, original_type) | |||
t = bind_self(t, original_type, is_classmethod=True) |
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.
This path is not tested
398f520
to
b369ca8
Compare
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.
Thanks! Just few comments.
self_param_type, original_type)[0] | ||
ids = [x.id for x in func.variables] | ||
typearg = infer_type_arguments(ids, self_param_type, original_type)[0] | ||
if (is_classmethod and isinstance(typearg, UninhabitedType) |
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.
Do you really need this additional test for UninhabitedType
? It looks a bit suspicious.
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.
Even if it is a classmethod, if the inference is successful with the original type, then it's fine; this is the normal case, calling the method on a class. We only "delegate" to the type if we are not successful.
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.
OK, this seems reasonable. If there will be no objections, then I am going to merge this.
and isinstance(original_type, (Instance, TypeVarType, TupleType))): | ||
# In case we call a classmethod through an instance x, fallback to type(x) | ||
# TODO: handle Union | ||
typearg = infer_type_arguments(ids, self_param_type, TypeType(original_type))[0] |
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.
Does actually Type[]
accepts Tuple
as an argument? I thought it works with unions, but not with tuple types. Please correct me if I am wrong. (Or is this only to cover self types in named tuples?)
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.
I basically mirrored the restriction on the type of the parameters :) but yes, I think it is needed for namedtuples.
def make(cls: Type[Q]) -> Q: | ||
reveal_type(cls.new) # E: Revealed type is 'def () -> Q`-1' | ||
reveal_type(cls().new) # E: Revealed type is 'def () -> Q`-1' | ||
reveal_type(cls().new()) # E: Revealed type is 'Q`-1' |
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.
I would add more tests like in the original issue, i.e. with classes and @classmethod
.
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.
I'm not sure I understand. Can you elaborate? I thought the test for D
above (line 226) is exactly the same as in the original issue.
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.
Yes, sorry, GitHub just cut @classmethod
for me.
def make(cls: Type[Q]) -> Q: | ||
reveal_type(cls.new) # E: Revealed type is 'def () -> Q`-1' | ||
reveal_type(cls().new) # E: Revealed type is 'def () -> Q`-1' | ||
reveal_type(cls().new()) # E: Revealed type is 'Q`-1' |
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.
Yes, sorry, GitHub just cut @classmethod
for me.
self_param_type, original_type)[0] | ||
ids = [x.id for x in func.variables] | ||
typearg = infer_type_arguments(ids, self_param_type, original_type)[0] | ||
if (is_classmethod and isinstance(typearg, UninhabitedType) |
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.
OK, this seems reasonable. If there will be no objections, then I am going to merge this.
Fix #3630