Skip to content

Commit 0141269

Browse files
committed
Roll back most of the changes
1 parent 3c7f11e commit 0141269

File tree

10 files changed

+220
-140
lines changed

10 files changed

+220
-140
lines changed

crates/ty_python_semantic/src/types.rs

Lines changed: 51 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -717,7 +717,7 @@ impl<'db> DataclassParams<'db> {
717717
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, salsa::Update, get_size2::GetSize)]
718718
pub enum Type<'db> {
719719
/// The dynamic type: a statically unknown set of values
720-
Dynamic(DynamicType),
720+
Dynamic(DynamicType<'db>),
721721
/// The empty set of values
722722
Never,
723723
/// A specific function object
@@ -827,12 +827,12 @@ impl<'db> Type<'db> {
827827
Self::Dynamic(DynamicType::Unknown)
828828
}
829829

830-
pub(crate) fn divergent() -> Self {
831-
Self::Dynamic(DynamicType::Divergent)
830+
pub(crate) fn divergent(scope: Option<ScopeId<'db>>) -> Self {
831+
Self::Dynamic(DynamicType::Divergent(DivergentType { scope }))
832832
}
833833

834834
pub(crate) const fn is_divergent(&self) -> bool {
835-
matches!(self, Type::Dynamic(DynamicType::Divergent))
835+
matches!(self, Type::Dynamic(DynamicType::Divergent(_)))
836836
}
837837

838838
pub const fn is_unknown(&self) -> bool {
@@ -1044,7 +1044,7 @@ impl<'db> Type<'db> {
10441044
}
10451045
}
10461046

1047-
pub(crate) const fn as_dynamic(self) -> Option<DynamicType> {
1047+
pub(crate) const fn as_dynamic(self) -> Option<DynamicType<'db>> {
10481048
match self {
10491049
Type::Dynamic(dynamic_type) => Some(dynamic_type),
10501050
_ => None,
@@ -1058,7 +1058,7 @@ impl<'db> Type<'db> {
10581058
}
10591059
}
10601060

1061-
pub(crate) const fn expect_dynamic(self) -> DynamicType {
1061+
pub(crate) const fn expect_dynamic(self) -> DynamicType<'db> {
10621062
self.as_dynamic().expect("Expected a Type::Dynamic variant")
10631063
}
10641064

@@ -1639,8 +1639,8 @@ impl<'db> Type<'db> {
16391639
// In some specific situations, `Any`/`Unknown`/`@Todo` can be simplified out of unions and intersections,
16401640
// but this is not true for divergent types (and moving this case any lower down appears to cause
16411641
// "too many cycle iterations" panics).
1642-
(Type::Dynamic(DynamicType::Divergent), _)
1643-
| (_, Type::Dynamic(DynamicType::Divergent)) => {
1642+
(Type::Dynamic(DynamicType::Divergent(_)), _)
1643+
| (_, Type::Dynamic(DynamicType::Divergent(_))) => {
16441644
ConstraintSet::from(relation.is_assignability())
16451645
}
16461646

@@ -2457,8 +2457,8 @@ impl<'db> Type<'db> {
24572457
match (self, other) {
24582458
// The `Divergent` type is a special type that is not equivalent to other kinds of dynamic types,
24592459
// which prevents `Divergent` from being eliminated during union reduction.
2460-
(Type::Dynamic(_), Type::Dynamic(DynamicType::Divergent))
2461-
| (Type::Dynamic(DynamicType::Divergent), Type::Dynamic(_)) => {
2460+
(Type::Dynamic(_), Type::Dynamic(DynamicType::Divergent(_)))
2461+
| (Type::Dynamic(DynamicType::Divergent(_)), Type::Dynamic(_)) => {
24622462
ConstraintSet::from(false)
24632463
}
24642464
(Type::Dynamic(_), Type::Dynamic(_)) => ConstraintSet::from(true),
@@ -6656,13 +6656,7 @@ impl<'db> Type<'db> {
66566656
match self {
66576657
Type::TypeVar(bound_typevar) => match type_mapping {
66586658
TypeMapping::Specialization(specialization) => {
6659-
let ty = specialization.get(db, bound_typevar).unwrap_or(self);
6660-
6661-
if exceeds_max_specialization_depth(db, ty) {
6662-
Type::divergent()
6663-
} else {
6664-
ty
6665-
}
6659+
specialization.get(db, bound_typevar).unwrap_or(self).fallback_to_divergent(db)
66666660
}
66676661
TypeMapping::PartialSpecialization(partial) => {
66686662
partial.get(db, bound_typevar).unwrap_or(self)
@@ -7220,6 +7214,20 @@ impl<'db> Type<'db> {
72207214
_ => None,
72217215
}
72227216
}
7217+
7218+
pub(super) fn has_divergent_type(self, db: &'db dyn Db, div: Type<'db>) -> bool {
7219+
any_over_type(db, self, &|ty| ty == div, false)
7220+
}
7221+
7222+
/// If the specialization depth of `self` exceeds the maximum limit allowed,
7223+
/// return `Divergent`. Otherwise, return `self`.
7224+
pub(super) fn fallback_to_divergent(self, db: &'db dyn Db) -> Type<'db> {
7225+
if exceeds_max_specialization_depth(db, self) {
7226+
Type::divergent(None)
7227+
} else {
7228+
self
7229+
}
7230+
}
72237231
}
72247232

72257233
impl<'db> From<&Type<'db>> for Type<'db> {
@@ -7657,8 +7665,19 @@ impl<'db> KnownInstanceType<'db> {
76577665
}
76587666
}
76597667

7668+
/// A type that is determined to be divergent during recursive type inference.
7669+
/// This type must never be eliminated by dynamic type reduction
7670+
/// (e.g. `Divergent` is assignable to `@Todo`, but `@Todo | Divergent` must not be reducted to `@Todo`).
7671+
/// Otherwise, type inference cannot converge properly.
7672+
/// For detailed properties of this type, see the unit test at the end of the file.
7673+
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, salsa::Update, get_size2::GetSize)]
7674+
pub struct DivergentType<'db> {
7675+
/// The scope where this divergence was detected.
7676+
scope: Option<ScopeId<'db>>,
7677+
}
7678+
76607679
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, salsa::Update, get_size2::GetSize)]
7661-
pub enum DynamicType {
7680+
pub enum DynamicType<'db> {
76627681
/// An explicitly annotated `typing.Any`
76637682
Any,
76647683
/// An unannotated value, or a dynamic type resulting from an error
@@ -7682,24 +7701,20 @@ pub enum DynamicType {
76827701
/// A special Todo-variant for `Unpack[Ts]`, so that we can treat it specially in `Generic[Unpack[Ts]]`
76837702
TodoUnpack,
76847703
/// A type that is determined to be divergent during type inference for a recursive function.
7685-
/// This type must never be eliminated by dynamic type reduction
7686-
/// (e.g. `Divergent` is assignable to `@Todo`, but `@Todo | Divergent` must not be reducted to `@Todo`).
7687-
/// Otherwise, type inference cannot converge properly.
7688-
/// For detailed properties of this type, see the unit test at the end of the file.
7689-
Divergent,
7704+
Divergent(DivergentType<'db>),
76907705
}
76917706

7692-
impl DynamicType {
7707+
impl DynamicType<'_> {
76937708
fn normalized(self) -> Self {
7694-
if matches!(self, Self::Divergent) {
7709+
if matches!(self, Self::Divergent(_)) {
76957710
self
76967711
} else {
76977712
Self::Any
76987713
}
76997714
}
77007715
}
77017716

7702-
impl std::fmt::Display for DynamicType {
7717+
impl std::fmt::Display for DynamicType<'_> {
77037718
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77047719
match self {
77057720
DynamicType::Any => f.write_str("Any"),
@@ -7728,7 +7743,7 @@ impl std::fmt::Display for DynamicType {
77287743
f.write_str("@Todo")
77297744
}
77307745
}
7731-
DynamicType::Divergent => f.write_str("Divergent"),
7746+
DynamicType::Divergent(_) => f.write_str("Divergent"),
77327747
}
77337748
}
77347749
}
@@ -11676,6 +11691,8 @@ pub(crate) mod tests {
1167611691
use super::*;
1167711692
use crate::db::tests::{TestDbBuilder, setup_db};
1167811693
use crate::place::{typing_extensions_symbol, typing_symbol};
11694+
use crate::semantic_index::FileScopeId;
11695+
use ruff_db::files::system_path_to_file;
1167911696
use ruff_db::system::DbWithWritableSystem as _;
1168011697
use ruff_python_ast::PythonVersion;
1168111698
use test_case::test_case;
@@ -11762,9 +11779,14 @@ pub(crate) mod tests {
1176211779

1176311780
#[test]
1176411781
fn divergent_type() {
11765-
let db = setup_db();
11782+
let mut db = setup_db();
11783+
11784+
db.write_dedented("src/foo.py", "").unwrap();
11785+
let file = system_path_to_file(&db, "src/foo.py").unwrap();
11786+
let file_scope_id = FileScopeId::global();
11787+
let scope = file_scope_id.to_scope_id(&db, file);
1176611788

11767-
let div = Type::divergent();
11789+
let div = Type::Dynamic(DynamicType::Divergent(DivergentType { scope: Some(scope) }));
1176811790

1176911791
// The `Divergent` type must not be eliminated in union with other dynamic types,
1177011792
// as this would prevent detection of divergent type inference using `Divergent`.

crates/ty_python_semantic/src/types/bound_super.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ impl<'db> BoundSuperError<'db> {
172172

173173
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, get_size2::GetSize)]
174174
pub enum SuperOwnerKind<'db> {
175-
Dynamic(DynamicType),
175+
Dynamic(DynamicType<'db>),
176176
Class(ClassType<'db>),
177177
Instance(NominalInstanceType<'db>),
178178
}

crates/ty_python_semantic/src/types/class.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1617,8 +1617,11 @@ impl<'db> ClassLiteral<'db> {
16171617

16181618
for (idx, ty) in specialization.types(db).iter().enumerate() {
16191619
if exceeds_max_specialization_depth(db, *ty) {
1620-
specialization =
1621-
specialization.with_replaced_type(db, idx, Type::divergent());
1620+
specialization = specialization.with_replaced_type(
1621+
db,
1622+
idx,
1623+
Type::divergent(Some(self.body_scope(db))),
1624+
);
16221625
}
16231626
}
16241627

crates/ty_python_semantic/src/types/class_base.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use crate::types::{
1818
/// automatically construct the default specialization for that class.
1919
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, salsa::Update, get_size2::GetSize)]
2020
pub enum ClassBase<'db> {
21-
Dynamic(DynamicType),
21+
Dynamic(DynamicType<'db>),
2222
Class(ClassType<'db>),
2323
/// Although `Protocol` is not a class in typeshed's stubs, it is at runtime,
2424
/// and can appear in the MRO of a class.
@@ -54,7 +54,7 @@ impl<'db> ClassBase<'db> {
5454
| DynamicType::TodoTypeAlias
5555
| DynamicType::TodoUnpack,
5656
) => "@Todo",
57-
ClassBase::Dynamic(DynamicType::Divergent) => "Divergent",
57+
ClassBase::Dynamic(DynamicType::Divergent(_)) => "Divergent",
5858
ClassBase::Protocol => "Protocol",
5959
ClassBase::Generic => "Generic",
6060
ClassBase::TypedDict => "TypedDict",

0 commit comments

Comments
 (0)