diff --git a/crates/red_knot_python_semantic/resources/mdtest/annotations/deferred.md b/crates/red_knot_python_semantic/resources/mdtest/annotations/deferred.md index 7ee6e84060..8db8d90409 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/annotations/deferred.md +++ b/crates/red_knot_python_semantic/resources/mdtest/annotations/deferred.md @@ -156,3 +156,24 @@ def _(): def f(self) -> C: return self ``` + +## Base class references + +### Not deferred by __future__.annotations + +```py +from __future__ import annotations + +class A(B): # error: [unresolved-reference] + pass + +class B: + pass +``` + +### Deferred in stub files + +```pyi +class A(B): ... +class B: ... +``` diff --git a/crates/red_knot_python_semantic/src/types/infer.rs b/crates/red_knot_python_semantic/src/types/infer.rs index 29a92c058d..c2d5467c4c 100644 --- a/crates/red_knot_python_semantic/src/types/infer.rs +++ b/crates/red_knot_python_semantic/src/types/infer.rs @@ -585,8 +585,8 @@ impl<'db> TypeInferenceBuilder<'db> { /// Are we currently inferring types in file with deferred types? /// This is true for stub files and files with `__future__.annotations` - fn are_all_types_deferred(&self) -> bool { - self.index.has_future_annotations() || self.file().is_stub(self.db().upcast()) + fn defer_annotations(&self) -> bool { + self.index.has_future_annotations() || self.in_stub() } /// Are we currently inferring deferred types? @@ -1467,7 +1467,7 @@ impl<'db> TypeInferenceBuilder<'db> { // If there are type params, parameters and returns are evaluated in that scope, that is, in // `infer_function_type_params`, rather than here. if type_params.is_none() { - if self.are_all_types_deferred() { + if self.defer_annotations() { self.types.deferred.insert(definition); } else { self.infer_optional_annotation_expression( @@ -1791,9 +1791,7 @@ impl<'db> TypeInferenceBuilder<'db> { // TODO: Only defer the references that are actually string literals, instead of // deferring the entire class definition if a string literal occurs anywhere in the // base class list. - if self.are_all_types_deferred() - || class_node.bases().iter().any(contains_string_literal) - { + if self.in_stub() || class_node.bases().iter().any(contains_string_literal) { self.types.deferred.insert(definition); } else { for base in class_node.bases() { @@ -2919,7 +2917,7 @@ impl<'db> TypeInferenceBuilder<'db> { let mut declared_ty = self.infer_annotation_expression( annotation, - DeferredExpressionState::from(self.are_all_types_deferred()), + DeferredExpressionState::from(self.defer_annotations()), ); if target