Skip to content

Commit 1b2a0e6

Browse files
authored
[ty] add special-case diagnostic for numbers module (#22931)
1 parent b54c9d7 commit 1b2a0e6

4 files changed

Lines changed: 71 additions & 1 deletion

File tree

crates/ty_module_resolver/src/module.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,7 @@ pub enum KnownModule {
334334
UnittestMock,
335335
Uuid,
336336
Warnings,
337+
Numbers,
337338
}
338339

339340
impl KnownModule {
@@ -362,6 +363,7 @@ impl KnownModule {
362363
Self::UnittestMock => "unittest.mock",
363364
Self::Uuid => "uuid",
364365
Self::Templatelib => "string.templatelib",
366+
Self::Numbers => "numbers",
365367
}
366368
}
367369

crates/ty_python_semantic/resources/mdtest/assignment/annotations.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,16 @@ reveal_type(y) # revealed: Literal[1]
1616
x: int = "foo" # error: [invalid-assignment] "Object of type `Literal["foo"]` is not assignable to `int`"
1717
```
1818

19+
## Numbers special case
20+
21+
<!-- snapshot-diagnostics -->
22+
23+
```py
24+
from numbers import Number
25+
26+
a: Number = 1 # error: [invalid-assignment] "Object of type `Literal[1]` is not assignable to `Number`"
27+
```
28+
1929
## Violates previous annotation
2030

2131
```py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
---
2+
source: crates/ty_test/src/lib.rs
3+
expression: snapshot
4+
---
5+
6+
---
7+
mdtest name: annotations.md - Assignment with annotations - Numbers special case
8+
mdtest path: crates/ty_python_semantic/resources/mdtest/assignment/annotations.md
9+
---
10+
11+
# Python source files
12+
13+
## mdtest_snippet.py
14+
15+
```
16+
1 | from numbers import Number
17+
2 |
18+
3 | a: Number = 1 # error: [invalid-assignment] "Object of type `Literal[1]` is not assignable to `Number`"
19+
```
20+
21+
# Diagnostics
22+
23+
```
24+
error[invalid-assignment]: Object of type `Literal[1]` is not assignable to `Number`
25+
--> src/mdtest_snippet.py:3:4
26+
|
27+
1 | from numbers import Number
28+
2 |
29+
3 | a: Number = 1 # error: [invalid-assignment] "Object of type `Literal[1]` is not assignable to `Number`"
30+
| ------ ^ Incompatible value of type `Literal[1]`
31+
| |
32+
| Declared type
33+
|
34+
info: Types from the `numbers` module aren't supported for static type checking
35+
help: Consider using a protocol instead, such as `typing.SupportsFloat`
36+
info: rule `invalid-assignment` is enabled by default
37+
38+
```

crates/ty_python_semantic/src/types/diagnostic.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ use ruff_python_ast::{self as ast, AnyNodeRef, PythonVersion, StringFlags};
4545
use ruff_text_size::{Ranged, TextRange};
4646
use rustc_hash::FxHashSet;
4747
use std::fmt::{self, Formatter};
48-
use ty_module_resolver::{Module, ModuleName};
48+
use ty_module_resolver::{KnownModule, Module, ModuleName, file_to_module};
4949

5050
const RUNTIME_CHECKABLE_DOCS_URL: &str =
5151
"https://docs.python.org/3/library/typing.html#typing.runtime_checkable";
@@ -3018,6 +3018,26 @@ pub(super) fn report_invalid_assignment<'db>(
30183018
let message = diag.primary_message().to_string();
30193019
diag.set_concise_message(message);
30203020
}
3021+
3022+
// special case message
3023+
if let Type::NominalInstance(target_instance) = target_ty {
3024+
let db = context.db();
3025+
let file = target_instance.class(db).class_literal(db).file(db);
3026+
if let Some(module) = file_to_module(db, file)
3027+
&& module.is_known(db, KnownModule::Numbers)
3028+
{
3029+
let is_numeric = [KnownClass::Int, KnownClass::Float, KnownClass::Complex]
3030+
.iter()
3031+
.any(|numeric| value_ty.is_subtype_of(db, numeric.to_instance(db)));
3032+
3033+
if is_numeric {
3034+
diag.info(
3035+
"Types from the `numbers` module aren't supported for static type checking",
3036+
);
3037+
diag.help("Consider using a protocol instead, such as `typing.SupportsFloat`");
3038+
}
3039+
}
3040+
}
30213041
}
30223042

30233043
pub(super) fn report_invalid_attribute_assignment(

0 commit comments

Comments
 (0)