-
Notifications
You must be signed in to change notification settings - Fork 1.4k
[ty] Use RHS inferred type for bare Final
symbols
#19142
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -524,6 +524,21 @@ impl<'db> PlaceAndQualifiers<'db> { | |
self.qualifiers.contains(TypeQualifiers::CLASS_VAR) | ||
} | ||
|
||
/// Returns `Some(…)` if the place is qualified with `typing.Final` without a specified type. | ||
pub(crate) fn is_bare_final(&self) -> Option<TypeQualifiers> { | ||
match self { | ||
PlaceAndQualifiers { place, qualifiers } | ||
if (qualifiers.contains(TypeQualifiers::FINAL) | ||
&& place | ||
.ignore_possibly_unbound() | ||
.is_some_and(|ty| ty.is_unknown())) => | ||
{ | ||
Some(*qualifiers) | ||
} | ||
_ => None, | ||
} | ||
} | ||
Comment on lines
+527
to
+540
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this mean that we would consider from ty_extensions import Unknown
from typing import Final
x: Final[Unknown] I think that's okay if so; people just shouldn't do that ;) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, well spotted 😄. I agree that it's not as clean as it could be. The alternative is much more complicated as it requires us to return |
||
|
||
#[must_use] | ||
pub(crate) fn map_type( | ||
self, | ||
|
@@ -645,6 +660,18 @@ fn place_by_id<'db>( | |
ConsideredDefinitions::AllReachable => use_def.all_reachable_bindings(place_id), | ||
}; | ||
|
||
// If a symbol is undeclared, but qualified with `typing.Final`, we use the right-hand side | ||
// inferred type, without unioning with `Unknown`, because it can not be modified. | ||
if let Some(qualifiers) = declared | ||
.as_ref() | ||
.ok() | ||
.and_then(PlaceAndQualifiers::is_bare_final) | ||
{ | ||
let bindings = all_considered_bindings(); | ||
return place_from_bindings_impl(db, bindings, requires_explicit_reexport) | ||
.with_qualifiers(qualifiers); | ||
} | ||
|
||
match declared { | ||
// Place is declared, trust the declared type | ||
Ok( | ||
|
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.
Pretty sure I intended to write
FINAL_A: Final[int] = 1
here originally :-)