[mypyc] always add implicit None return type to __init__ method - #9866
Conversation
JukkaL
left a comment
There was a problem hiding this comment.
Thanks for the fix! Looks good, just found one edge case that may require a minor tweak.
| arg_types = [object_rprimitive for arg in fdef.arguments] | ||
| ret = object_rprimitive | ||
| # We at least know the return type for __init__ will be None. | ||
| if fdef.name == '__init__': |
There was a problem hiding this comment.
Could fdef be a module-level function with the (confusing) name __init__? Add test for this. We should allow top-level functions to return any values, even if they are named __init__ for some reason.
(You should be able to compare the FuncDef info attribute against FUNC_NO_INFO to check whether it's a method.)
There was a problem hiding this comment.
Oh nice catch this will not work for module-level functions named __init__! I will add a check and test for this. Thank you for the FUNC_NO_INFO tip.
…nnotation to module-level __init__ functions
|
|
||
| @property | ||
| def is_module_level_func(self) -> bool: | ||
| return self.info == FUNC_NO_INFO |
There was a problem hiding this comment.
@JukkaL my instinct was to "hide" the use of FUNC_NO_INFO. I'm not sure if that was a good instinct.
There was a problem hiding this comment.
Actually I think that this is unnecessary (see below).
JukkaL
left a comment
There was a problem hiding this comment.
Thanks for the updates! This looks correct now. Left some some comments about style. (Sorry, my original suggestion to use FUNC_NO_INFO was a bad idea.)
| [case testInitMethodWithMissingNoneReturnAnnotation] | ||
| class C: | ||
| def __init__(self): | ||
| pass |
There was a problem hiding this comment.
Also try constructing an instance of C (just make sure it produces a result).
|
|
||
| @property | ||
| def is_module_level_func(self) -> bool: | ||
| return self.info == FUNC_NO_INFO |
There was a problem hiding this comment.
Actually I think that this is unnecessary (see below).
| raise SuggestionFailure("Function does not typecheck.") | ||
|
|
||
| is_method = bool(node.info) and not node.is_static | ||
| is_method = not node.is_module_level_func and not node.is_static |
There was a problem hiding this comment.
Let's leave this as it was, since using an info attribute as a boolean is a common idiom.
| arg_types = [object_rprimitive for arg in fdef.arguments] | ||
| ret = object_rprimitive | ||
| # We at least know the return type for __init__ methods will be None. | ||
| is_init_method = fdef.name == '__init__' and not fdef.is_module_level_func |
There was a problem hiding this comment.
I think that you can just use ... and bool(fdef.info). Your suggestion to use a property is reasonable, but we have many checks where we do the equivalent of if fdef.info so it would add some inconsistency.
There was a problem hiding this comment.
Okay thank you that makes sense. Applying this update and the suggestions above now.
…ove test case for missing __init__ return annotation
JukkaL
left a comment
There was a problem hiding this comment.
Looks good now! Thanks for updates. This fixes a major issue.
Description
Fixes mypyc/mypyc#792.
Always give
__init__an implicitNonereturn type so that programs likecompile.
Test Plan
Included a test program that doesn't compile with the existing application code.