-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
[red-knot] Do not emit invalid-return-type
for abstract functions
#16900
Conversation
|
I don't know if we want to support |
a84f4d5
to
393329b
Compare
Glad to hear that! Reverted. |
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.
Should we add a test for "Function can implicitly return None
, which is not assignable to return type {}
" is emitted when you have a function with no body outside of class
# error: [invalid-return-type] "Function can implicitly return `None`, which is not assignable to return type `int`"
def f(self) -> int: ...
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 looks great to me -- thank you!
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.
Thank you, this is a nice improvement!
let class_inherits_protocol_directly = (|| -> bool { | ||
let current_scope_id = self.scope().file_scope_id(self.db()); | ||
let current_scope = self.index.scope(current_scope_id); | ||
let Some(parent_scope_id) = current_scope.parent() else { | ||
return false; | ||
}; | ||
let parent_scope = self.index.scope(parent_scope_id); | ||
|
||
let NodeWithScopeKind::Class(node_ref) = parent_scope.node() else { | ||
return false; | ||
}; | ||
|
||
node_ref.bases().iter().any(|base| { | ||
matches!( | ||
self.file_expression_type(base), | ||
Type::KnownInstance(KnownInstanceType::Protocol) | ||
) | ||
}) | ||
})(); |
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.
In terms of API, rather than doing all this right here in type inference, I think we should have methods Class::is_protocol() -> bool
and FunctionType::enclosing_class() -> Option<Class<'db>>
.
In terms of how those methods are implemented, I did wonder about an alternate strategy that would record the enclosing-class information for each function in semantic indexing. This would imply that DefinitionKind::Function
would include an Option<FileScopeId>
which is the body scope of the lexically enclosing class.
But I'm not sure this is really better; it would require extra work in semantic indexing to maintain the "enclosing class" state and clear it appropriately (that is, nested functions inside methods are not themselves methods and should have no enclosing class), and I think the scope-walking code you have here can be made fully correct without too much difficulty.
I think we should test this, but it seems orthogonal to this PR. If we are lacking a test for this and you want to submit a PR to add it, that would be great! |
e3457da
to
1aa98e6
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.
Added tests look good! I would still like to see us break up the mass of the new added code by extracting some reusable and meaningfully-named functions.
@carljm |
My other concern is that we should let |
Still halfway tempted to move "find the enclosing class" logic to |
Thanks for the PR! |
Ok, I found where I had seen this is-method-of-class logic before, and we still have it (and it's currently wrong). See #16928 |
Summary
Resolves #16895.
abstractmethod
is now aKnownFunction
. When a function is decorated byabstractmethod
or when the parent class inherits directly fromProtocol
,invalid-return-type
won't be emitted for that function.Test Plan
Markdown tests.