Skip to content

Commit 8fb6392

Browse files
committed
refactor: move multiple inheritance check to class_field.rs
1 parent 3800bde commit 8fb6392

File tree

2 files changed

+46
-43
lines changed

2 files changed

+46
-43
lines changed

pyrefly/lib/alt/class/class_field.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use std::iter;
1111
use std::sync::Arc;
1212

1313
use dupe::Dupe;
14+
use itertools::Itertools;
1415
use pyrefly_derive::TypeEq;
1516
use pyrefly_derive::VisitMut;
1617
use pyrefly_python::dunder;
@@ -1957,6 +1958,50 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
19571958
}
19581959
}
19591960

1961+
/// For classes with multiple inheritance, check that fields inherited from multiple base classes are consistent.
1962+
pub fn check_consistent_multiple_inheritance(&self, cls: &Class, errors: &ErrorCollector) {
1963+
// Maps field from inherited class
1964+
let mro = self.get_mro_for_class(cls);
1965+
let mut inherited_fields: SmallMap<&Name, Vec<(&Name, Type)>> = SmallMap::new();
1966+
1967+
for parent_cls in mro.ancestors_no_object().iter() {
1968+
let class_fields = parent_cls.class_object().fields();
1969+
for field in class_fields {
1970+
let key = KeyClassField(parent_cls.class_object().index(), field.clone());
1971+
let field_entry = self.get_from_class(cls, &key);
1972+
if let Some(field_entry) = field_entry.as_ref() {
1973+
inherited_fields
1974+
.entry(field)
1975+
.or_default()
1976+
.push((parent_cls.name(), field_entry.ty()));
1977+
}
1978+
}
1979+
}
1980+
1981+
for (field_name, class_and_types) in inherited_fields.iter() {
1982+
if class_and_types.len() > 1 {
1983+
let types: Vec<Type> = class_and_types.iter().map(|(_, ty)| ty.clone()).collect();
1984+
let intersect = self.intersects(&types);
1985+
if matches!(intersect, Type::Never(_)) {
1986+
let class_and_types_str = class_and_types
1987+
.iter()
1988+
.map(|(cls, ty)| {
1989+
format!("`{}` from `{}`", self.for_display(ty.clone()), cls)
1990+
})
1991+
.join(", ");
1992+
self.error(
1993+
errors,
1994+
cls.range(),
1995+
ErrorInfo::Kind(ErrorKind::InconsistentOverload),
1996+
format!(
1997+
"Inconsistent types for field `{field_name}` inherited from multiple base classes: {class_and_types_str}",
1998+
),
1999+
);
2000+
}
2001+
}
2002+
}
2003+
}
2004+
19602005
fn get_non_synthesized_field_from_current_class_only(
19612006
&self,
19622007
cls: &Class,

pyrefly/lib/alt/solve.rs

Lines changed: 1 addition & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use std::ops::Deref;
1010
use std::sync::Arc;
1111

1212
use dupe::Dupe;
13-
use itertools::Itertools;
1413
use pyrefly_python::ast::Ast;
1514
use pyrefly_python::dunder;
1615
use pyrefly_python::short_identifier::ShortIdentifier;
@@ -75,7 +74,6 @@ use crate::binding::binding::FunctionParameter;
7574
use crate::binding::binding::FunctionStubOrImpl;
7675
use crate::binding::binding::IsAsync;
7776
use crate::binding::binding::Key;
78-
use crate::binding::binding::KeyClassField;
7977
use crate::binding::binding::KeyExport;
8078
use crate::binding::binding::KeyLegacyTypeParam;
8179
use crate::binding::binding::KeyUndecoratedFunction;
@@ -1563,47 +1561,7 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
15631561
// If we are inheriting from multiple base types, we should
15641562
// check whether the multiple inheritance is consistent
15651563
if class_bases.as_ref().base_type_count() > 1 {
1566-
// Maps field from inherited class
1567-
let mro = self.get_mro_for_class(cls);
1568-
let mut inherited_fields: SmallMap<&Name, Vec<(&Name, Type)>> = SmallMap::new();
1569-
1570-
for parent_cls in mro.ancestors_no_object().iter() {
1571-
let class_fields = parent_cls.class_object().fields();
1572-
for field in class_fields {
1573-
let key = KeyClassField(parent_cls.class_object().index(), field.clone());
1574-
let field_entry = self.get_from_class(cls, &key);
1575-
if let Some(field_entry) = field_entry.as_ref() {
1576-
inherited_fields
1577-
.entry(field)
1578-
.or_default()
1579-
.push((parent_cls.name(), field_entry.ty()));
1580-
}
1581-
}
1582-
}
1583-
1584-
for (field_name, class_and_types) in inherited_fields.iter() {
1585-
if class_and_types.len() > 1 {
1586-
let types: Vec<Type> =
1587-
class_and_types.iter().map(|(_, ty)| ty.clone()).collect();
1588-
let intersect = self.intersects(&types);
1589-
if matches!(intersect, Type::Never(_)) {
1590-
let class_and_types_str = class_and_types
1591-
.iter()
1592-
.map(|(cls, ty)| {
1593-
format!("`{}` from `{}`", self.for_display(ty.clone()), cls)
1594-
})
1595-
.join(", ");
1596-
self.error(
1597-
errors,
1598-
cls.range(),
1599-
ErrorInfo::Kind(ErrorKind::InconsistentOverload),
1600-
format!(
1601-
"Inconsistent types for field `{field_name}` inherited from multiple base classes: {class_and_types_str}",
1602-
),
1603-
);
1604-
}
1605-
}
1606-
}
1564+
self.check_consistent_multiple_inheritance(cls, errors);
16071565
}
16081566
}
16091567
Arc::new(EmptyAnswer)

0 commit comments

Comments
 (0)