Skip to content

Commit 9a3001b

Browse files
authored
[red-knot] Do not attach diagnostics to wrong file (#14337)
## Summary Avoid attaching diagnostics to the wrong file. See related issue for details. Closes #14334 ## Test Plan New regression test.
1 parent ec2c7ca commit 9a3001b

File tree

3 files changed

+28
-10
lines changed

3 files changed

+28
-10
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Regression test for #14334
2+
3+
Regression test for [this issue](https://github.com/astral-sh/ruff/issues/14334).
4+
5+
```py path=base.py
6+
# error: [invalid-base]
7+
class Base(2): ...
8+
```
9+
10+
```py path=a.py
11+
# No error here
12+
from base import Base
13+
```

crates/red_knot_python_semantic/src/types/infer.rs

+15-9
Original file line numberDiff line numberDiff line change
@@ -469,16 +469,22 @@ impl<'db> TypeInferenceBuilder<'db> {
469469
let class_definitions = self
470470
.types
471471
.declarations
472-
.values()
473-
.filter_map(|ty| ty.into_class_literal())
474-
.map(|class_ty| class_ty.class);
472+
.iter()
473+
.filter_map(|(definition, ty)| {
474+
// Filter out class literals that result from imports
475+
if let DefinitionKind::Class(class) = definition.kind(self.db) {
476+
ty.into_class_literal().map(|ty| (ty.class, class.node()))
477+
} else {
478+
None
479+
}
480+
});
475481

476482
// Iterate through all class definitions in this scope.
477-
for class in class_definitions {
483+
for (class, class_node) in class_definitions {
478484
// (1) Check that the class does not have a cyclic definition
479485
if class.is_cyclically_defined(self.db) {
480486
self.diagnostics.add(
481-
class.node(self.db).into(),
487+
class_node.into(),
482488
"cyclic-class-def",
483489
format_args!(
484490
"Cyclic definition of `{}` or bases of `{}` (class cannot inherit from itself)",
@@ -495,7 +501,7 @@ impl<'db> TypeInferenceBuilder<'db> {
495501
if let Err(mro_error) = class.try_mro(self.db).as_ref() {
496502
match mro_error.reason() {
497503
MroErrorKind::DuplicateBases(duplicates) => {
498-
let base_nodes = class.node(self.db).bases();
504+
let base_nodes = class_node.bases();
499505
for (index, duplicate) in duplicates {
500506
self.diagnostics.add(
501507
(&base_nodes[*index]).into(),
@@ -505,7 +511,7 @@ impl<'db> TypeInferenceBuilder<'db> {
505511
}
506512
}
507513
MroErrorKind::InvalidBases(bases) => {
508-
let base_nodes = class.node(self.db).bases();
514+
let base_nodes = class_node.bases();
509515
for (index, base_ty) in bases {
510516
self.diagnostics.add(
511517
(&base_nodes[*index]).into(),
@@ -518,7 +524,7 @@ impl<'db> TypeInferenceBuilder<'db> {
518524
}
519525
}
520526
MroErrorKind::UnresolvableMro { bases_list } => self.diagnostics.add(
521-
class.node(self.db).into(),
527+
class_node.into(),
522528
"inconsistent-mro",
523529
format_args!(
524530
"Cannot create a consistent method resolution order (MRO) for class `{}` with bases list `[{}]`",
@@ -545,7 +551,7 @@ impl<'db> TypeInferenceBuilder<'db> {
545551
},
546552
candidate1_is_base_class,
547553
} => {
548-
let node = class.node(self.db).into();
554+
let node = class_node.into();
549555
if *candidate1_is_base_class {
550556
self.diagnostics.add(
551557
node,

crates/ruff_benchmark/benches/red_knot.rs

-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ static EXPECTED_DIAGNOSTICS: &[&str] = &[
5050
"error[possibly-unresolved-reference] /src/tomllib/_parser.py:580:63 Name `char` used when possibly not defined",
5151
"error[conflicting-declarations] /src/tomllib/_parser.py:590:9 Conflicting declared types for `char`: Unknown, str | None",
5252
"error[possibly-unresolved-reference] /src/tomllib/_parser.py:629:38 Name `datetime_obj` used when possibly not defined",
53-
"error[invalid-base] /src/tomllib/_parser.py:692:8354 Invalid class base with type `GenericAlias` (all bases must be a class, `Any`, `Unknown` or `Todo`)",
5453
];
5554

5655
fn get_test_file(name: &str) -> TestFile {

0 commit comments

Comments
 (0)