Skip to content

Commit 93b022d

Browse files
committed
Less hacky implementation
1 parent e9c5c6a commit 93b022d

File tree

1 file changed

+96
-67
lines changed

1 file changed

+96
-67
lines changed

crates/ty_python_semantic/src/place.rs

Lines changed: 96 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -992,6 +992,84 @@ fn place_from_bindings_impl<'db>(
992992
}
993993
}
994994

995+
struct PublicTypeBuilder<'db> {
996+
queue: Vec<TypeAndQualifiers<'db>>,
997+
builder: UnionBuilder<'db>,
998+
qualifiers: TypeQualifiers,
999+
first_type: Option<Type<'db>>,
1000+
conflicting_types: Vec<Type<'db>>,
1001+
}
1002+
1003+
impl<'db> PublicTypeBuilder<'db> {
1004+
fn new(db: &'db dyn Db) -> Self {
1005+
PublicTypeBuilder {
1006+
queue: vec![],
1007+
builder: UnionBuilder::new(db),
1008+
qualifiers: TypeQualifiers::empty(),
1009+
first_type: None,
1010+
conflicting_types: vec![],
1011+
}
1012+
}
1013+
1014+
fn push_element(&mut self, db: &'db dyn Db, element: TypeAndQualifiers<'db>) {
1015+
let element_ty = element.inner_type();
1016+
1017+
if let Some(first_ty) = self.first_type {
1018+
if !first_ty.is_equivalent_to(db, element_ty) {
1019+
self.conflicting_types.push(element_ty);
1020+
}
1021+
} else {
1022+
self.first_type = Some(element_ty);
1023+
}
1024+
1025+
self.builder.add_in_place(element_ty);
1026+
self.qualifiers = self.qualifiers.union(element.qualifiers());
1027+
}
1028+
1029+
fn drain_queue(&mut self, db: &'db dyn Db) {
1030+
let mut queue = vec![];
1031+
std::mem::swap(&mut queue, &mut self.queue);
1032+
for queued_element in queue {
1033+
self.push_element(db, queued_element);
1034+
}
1035+
}
1036+
1037+
fn add(&mut self, db: &'db dyn Db, element: TypeAndQualifiers<'db>) {
1038+
let element_type = element.inner_type();
1039+
match element_type {
1040+
Type::FunctionLiteral(function) => {
1041+
if function.literal(db).last_definition(db).is_overload(db) {
1042+
self.queue.push(element);
1043+
} else {
1044+
self.queue.clear();
1045+
self.push_element(db, element);
1046+
}
1047+
}
1048+
_ => {
1049+
self.drain_queue(db);
1050+
self.push_element(db, element);
1051+
}
1052+
}
1053+
}
1054+
1055+
fn build(mut self, db: &'db dyn Db) -> (TypeAndQualifiers<'db>, Box<[Type<'db>]>) {
1056+
self.drain_queue(db);
1057+
1058+
if !self.conflicting_types.is_empty() {
1059+
self.conflicting_types.insert(
1060+
0,
1061+
self.first_type
1062+
.expect("there must be a first type if there are conflicting types"),
1063+
);
1064+
}
1065+
1066+
(
1067+
TypeAndQualifiers::new(self.builder.build(), self.qualifiers),
1068+
self.conflicting_types.into_boxed_slice(),
1069+
)
1070+
}
1071+
}
1072+
9951073
/// Implementation of [`place_from_declarations`].
9961074
///
9971075
/// ## Implementation Note
@@ -1048,79 +1126,30 @@ fn place_from_declarations_impl<'db>(
10481126
let mut types = types.peekable();
10491127

10501128
if types.peek().is_some() {
1051-
let mut union_elements = vec![];
1052-
let mut queue = vec![];
1053-
1054-
for ty in types {
1055-
match ty.inner_type() {
1056-
Type::FunctionLiteral(function) => {
1057-
if function.literal(db).last_definition(db).is_overload(db) {
1058-
queue.push(ty);
1059-
} else {
1060-
queue.clear();
1061-
union_elements.push(ty);
1062-
}
1063-
}
1064-
_ => {
1065-
union_elements.append(&mut queue);
1066-
1067-
union_elements.push(ty);
1068-
}
1069-
}
1129+
let mut builder = PublicTypeBuilder::new(db);
1130+
for element in types {
1131+
builder.add(db, element);
10701132
}
1071-
union_elements.append(&mut queue);
1072-
// dbg!(&union_elements);
1073-
1074-
let mut union_elements = union_elements.into_iter();
1075-
1076-
let first = union_elements
1077-
.next()
1078-
.expect("At least one type must be present");
1133+
let (declared, conflicting) = builder.build(db);
10791134

1080-
let mut conflicting: Vec<Type<'db>> = vec![];
1081-
let declared = if let Some(second) = union_elements.next() {
1082-
let ty_first = first.inner_type();
1083-
let mut qualifiers = first.qualifiers();
1135+
if !conflicting.is_empty() {
1136+
return Err((declared, conflicting));
1137+
}
10841138

1085-
let mut builder = UnionBuilder::new(db).add(ty_first);
1086-
for other in std::iter::once(second).chain(union_elements) {
1087-
let other_ty = other.inner_type();
1088-
if !ty_first.is_equivalent_to(db, other_ty) {
1089-
conflicting.push(other_ty);
1139+
let boundness = match considered_definitions {
1140+
ConsideredDefinitions::AllReachable => Boundness::Bound,
1141+
ConsideredDefinitions::AllLiveAtUse => match undeclared_reachability {
1142+
Truthiness::AlwaysTrue => {
1143+
unreachable!(
1144+
"If we have at least one declaration, the implicit `unbound` binding should not be definitely visible"
1145+
)
10901146
}
1091-
builder = builder.add(other_ty);
1092-
qualifiers = qualifiers.union(other.qualifiers());
1093-
}
1094-
TypeAndQualifiers::new(builder.build(), qualifiers)
1095-
} else {
1096-
first
1147+
Truthiness::AlwaysFalse => Boundness::Bound,
1148+
Truthiness::Ambiguous => Boundness::PossiblyUnbound,
1149+
},
10971150
};
1098-
if conflicting.is_empty() {
1099-
let boundness = match considered_definitions {
1100-
ConsideredDefinitions::AllReachable => Boundness::Bound,
1101-
ConsideredDefinitions::AllLiveAtUse => match undeclared_reachability {
1102-
Truthiness::AlwaysTrue => {
1103-
unreachable!(
1104-
"If we have at least one declaration, the implicit `unbound` binding should not be definitely visible"
1105-
)
1106-
}
1107-
Truthiness::AlwaysFalse => Boundness::Bound,
1108-
Truthiness::Ambiguous => Boundness::PossiblyUnbound,
1109-
},
1110-
};
11111151

1112-
Ok(
1113-
Place::Type(declared.inner_type(), boundness)
1114-
.with_qualifiers(declared.qualifiers()),
1115-
)
1116-
} else {
1117-
Err((
1118-
declared,
1119-
std::iter::once(first.inner_type())
1120-
.chain(conflicting)
1121-
.collect(),
1122-
))
1123-
}
1152+
Ok(Place::Type(declared.inner_type(), boundness).with_qualifiers(declared.qualifiers()))
11241153
} else {
11251154
Ok(Place::Unbound.into())
11261155
}

0 commit comments

Comments
 (0)