@@ -4983,13 +4983,60 @@ impl<'db> Type<'db> {
49834983 (Place::Undefined, true) => None,
49844984 };
49854985
4986+ // Three-layer constructor handling for mixed metaclass `__call__`:
4987+ // - Non-instance-returning metaclass overloads bypass `__new__`/`__init__`.
4988+ // - Instance-returning metaclass overloads must satisfy downstream constructor checks.
4989+ if let Some(metaclass_mixed_sigs) = metaclass_mixed_non_instance_sigs {
4990+ let downstream_bindings = if let Some(bindings) = missing_init_bindings {
4991+ Some(bindings)
4992+ } else if new_is_all_non_instance {
4993+ // `__new__` is still relevant for instance-returning metaclass paths, but
4994+ // `__init__` is skipped when `__new__` is all non-instance.
4995+ new_bindings.map(|(new_bindings, _)| new_bindings)
4996+ } else if let Some(new_mixed_sigs) = new_mixed_non_instance_sigs {
4997+ let mut bindings: Bindings<'db> =
4998+ CallableBinding::from_overloads(self_type, Vec::from(new_mixed_sigs)).into();
4999+ if let Some((init_bindings, _)) = init_bindings.as_ref() {
5000+ bindings.set_mixed_constructor_init(class.class_literal(db), init_bindings);
5001+ }
5002+ Some(bindings)
5003+ } else {
5004+ let mut all_bindings: SmallVec<[Bindings<'db>; 2]> = SmallVec::new();
5005+ let mut callable_type_builder = UnionBuilder::new(db);
5006+
5007+ if let Some((new_bindings, new_callable)) = new_bindings {
5008+ all_bindings.push(new_bindings);
5009+ callable_type_builder = callable_type_builder.add(new_callable);
5010+ }
5011+ if let Some((init_bindings, init_callable)) = init_bindings {
5012+ all_bindings.push(init_bindings);
5013+ callable_type_builder = callable_type_builder.add(init_callable);
5014+ }
5015+
5016+ match all_bindings.len() {
5017+ 0 => None,
5018+ 1 => Some(all_bindings.into_iter().next().unwrap()),
5019+ _ => {
5020+ let callable_type = callable_type_builder.build();
5021+ Some(Bindings::from_union(callable_type, all_bindings))
5022+ }
5023+ }
5024+ };
5025+
5026+ let mut bindings: Bindings<'db> =
5027+ CallableBinding::from_overloads(self, Vec::from(metaclass_mixed_sigs)).into();
5028+ if let Some(downstream_bindings) = downstream_bindings.as_ref() {
5029+ bindings.set_mixed_constructor_init(class.class_literal(db), downstream_bindings);
5030+ }
5031+ return bindings
5032+ .with_generic_context(db, class_generic_context)
5033+ .with_constructor_instance_type(constructor_instance_ty);
5034+ }
5035+
49865036 // Preserve legacy behavior when `__new__` always returns a non-instance and there are no
49875037 // metaclass constraints to additionally enforce: skip constructor synthesis and use the
49885038 // raw `__new__` return type directly.
4989- if new_is_all_non_instance
4990- && metaclass_instance_bindings.is_none()
4991- && metaclass_mixed_non_instance_sigs.is_none()
4992- {
5039+ if new_is_all_non_instance && metaclass_instance_bindings.is_none() {
49935040 let (new_bindings, _) = new_bindings.unwrap();
49945041 return new_bindings.with_generic_context(db, class_generic_context);
49955042 }
@@ -5004,28 +5051,15 @@ impl<'db> Type<'db> {
50045051 } else {
50055052 // Collect all bindings that must accept the constructor call.
50065053 // This may include `__new__`, `__init__`, and/or a metaclass `__call__`.
5007- let has_mixed_constructor_paths = new_mixed_non_instance_sigs.is_some()
5008- || metaclass_mixed_non_instance_sigs.is_some();
5009- let mut all_bindings: SmallVec<[Bindings<'db>; 4]> = SmallVec::new();
5054+ let has_mixed_constructor_paths = new_mixed_non_instance_sigs.is_some();
5055+ let mut all_bindings: SmallVec<[Bindings<'db>; 3]> = SmallVec::new();
50105056 let mut callable_type_builder = UnionBuilder::new(db);
50115057
50125058 if let Some((metaclass_bindings, metaclass_ty)) = metaclass_instance_bindings {
50135059 all_bindings.push(metaclass_bindings);
50145060 callable_type_builder = callable_type_builder.add(metaclass_ty);
50155061 }
50165062
5017- // If `__new__` or metaclass `__call__` had mixed return types (some non-instance,
5018- // some instance), keep all overloads with per-overload return types and attach
5019- // deferred `__init__` validation. If both are mixed, both constraint sets apply.
5020- if let Some(combined_sigs) = metaclass_mixed_non_instance_sigs {
5021- let mut bindings: Bindings<'db> =
5022- CallableBinding::from_overloads(self, Vec::from(combined_sigs)).into();
5023- if let Some((init_bindings, _)) = init_bindings.as_ref() {
5024- bindings.set_mixed_constructor_init(class.class_literal(db), init_bindings);
5025- }
5026- all_bindings.push(bindings);
5027- callable_type_builder = callable_type_builder.add(self);
5028- }
50295063 if let Some(combined_sigs) = new_mixed_non_instance_sigs {
50305064 let mut bindings: Bindings<'db> =
50315065 CallableBinding::from_overloads(self_type, Vec::from(combined_sigs)).into();
0 commit comments