[ty] support NewTypes of float and complex#21886
Conversation
Diagnostic diff on typing conformance testsNo changes detected when running ty on typing conformance tests ✅ |
crates/ty_python_semantic/resources/mdtest/annotations/new_types.md
Outdated
Show resolved
Hide resolved
|
0b66863 to
22f0db0
Compare
NewTypes of float and complexNewTypes of float and complex
22f0db0 to
88ddd96
Compare
|
AlexWaygood
left a comment
There was a problem hiding this comment.
Nice, I like the semantics and the implementation here!
carljm
left a comment
There was a problem hiding this comment.
I also like these semantics and this implementation; nice work!
| } | ||
| // If we get here, there is no `ClassType` (because this newtype is cyclic), and we don't | ||
| // call `f` at all. | ||
| // If we get here, there is no `ClassType` (because this newtype is either float/complex or |
There was a problem hiding this comment.
It might be worth explicitly commenting here that mapping base class types is used for normalization and applying type mappings, and neither of these apply to int/float/complex (they are already fully normalized and not generic), so it's fine to ignore them here.
| /// Returns true if this union is equivalent to `int | float`, which is what `float` expands | ||
| /// into in type position. | ||
| pub(crate) fn is_int_float(self, db: &'db dyn Db) -> bool { | ||
| let elements = self.elements(db); | ||
| if elements.len() != 2 { | ||
| return false; | ||
| } | ||
| let mut has_int = false; | ||
| let mut has_float = false; | ||
| for element in elements { | ||
| if let Type::NominalInstance(nominal) = element | ||
| && let Some(known) = nominal.known_class(db) | ||
| { | ||
| match known { | ||
| KnownClass::Int => has_int = true, | ||
| KnownClass::Float => has_float = true, | ||
| _ => {} | ||
| } | ||
| } | ||
| } | ||
| has_int && has_float | ||
| } | ||
|
|
||
| /// Returns true if this union is equivalent to `int | float | complex`, which is what | ||
| /// `complex` expands into in type position. | ||
| pub(crate) fn is_int_float_complex(self, db: &'db dyn Db) -> bool { | ||
| let elements = self.elements(db); | ||
| if elements.len() != 3 { | ||
| return false; | ||
| } | ||
| let mut has_int = false; | ||
| let mut has_float = false; | ||
| let mut has_complex = false; | ||
| for element in elements { | ||
| if let Type::NominalInstance(nominal) = element | ||
| && let Some(known) = nominal.known_class(db) | ||
| { | ||
| match known { | ||
| KnownClass::Int => has_int = true, | ||
| KnownClass::Float => has_float = true, | ||
| KnownClass::Complex => has_complex = true, | ||
| _ => {} | ||
| } | ||
| } | ||
| } | ||
| has_int && has_float && has_complex | ||
| } |
There was a problem hiding this comment.
This could be a single method which returns an option of an enum, since these are mutually exclusive possibilities that require effectively the same work to check... that would be slightly less redundant and slightly more efficient? But I think it doesn't really matter, this way is totally fine.
737beba to
2689148
Compare

astral-sh/ty#1818
There is a known-failing test case in this first draft, which is related to a very hacky bit that I'm pretty sure is wrong. Feedback needed :) Comments below.Second pass: allow the two special-cased unions as
NewTypeBasevariants, and remove the presumption that the concrete base type is aClassType.