Repository: astral-sh/ruff
File: crates/ty_python_semantic/src/types/generics.rs (Rust)

Code before:
                            );
                        self.add_type_mappings_from_constraint_set(formal, when, &mut f);
                    } else {
                        for actual_signature in &actual_callable.signatures(self.db).overloads {
                            let when = actual_signature
                                .when_constraint_set_assignable_to_signatures(
                                    self.db,
                                    formal_callable,
                                    self.inferable,
                                );
                            self.add_type_mappings_from_constraint_set(formal, when, &mut f);
                        }
                    }
                }
            }

            // Expand type aliases in actual type for structural matching.
            // This is placed at the END of the match block (after TypeVar) to preserve
            // alias wrappers when they can be matched directly (e.g. reveal_type(alias) -> alias).
            (formal, Type::TypeAlias(alias)) => {
                return self.infer_map_impl(formal, alias.value_type(self.db), polarity, f);
            }

            // If the actual type is a union that wasn't handled by earlier union-specific arms,
            // try matching the formal type against each element of the union.
            (formal, Type::Union(actual_union)) => {
                for element in actual_union.elements(self.db) {
                    self.infer_map_impl(formal, *element, polarity, f)?;
                }
            }

            // TODO: Add more forms that we can structurally induct into: type[C]
            _ => {}
        }

        Ok(())
    }

    /// Infer type mappings for the specialization in the reverse direction, i.e., where the
    /// actual type, not the formal type, contains inferable type variables.
    pub(crate) fn infer_reverse(
        &mut self,
        formal: Type<'db>,
        actual: Type<'db>,
    ) -> Result<(), SpecializationError<'db>> {
        self.infer_reverse_map(formal, actual, |(_, _, ty)| Some(ty))
    }

    /// Infer type mappings for the specialization in the reverse direction, i.e., where the
    /// actual type, not the formal type, contains inferable type variables.
    ///

Review comment (suggestion):
This seems unrelated to the type alias change? Handling of unions is a known limitation of the current constraint solver, I don't think it should be addressed in this PR.

Code after:
                            .variables(self.db);
                        let formal_specialization =
                            formal_alias.specialization(self.db).types(self.db);
                        let base_specialization = base_alias.specialization(self.db).types(self.db);
                        for (typevar, formal_ty, base_ty) in itertools::izip!(
                            generic_context,
                            formal_specialization,
                            base_specialization
                        ) {
                            let variance = typevar.variance_with_polarity(self.db, polarity);
                            self.infer_map_impl(*formal_ty, *base_ty, variance, &mut f, seen)?;
                        }
                        return Ok(());
                    }
                }
            }

            (Type::Callable(formal_callable), _) => {
                let Some(actual_callables) = actual.try_upcast_to_callable(self.db) else {
                    return Ok(());
                };

                let formal_callable = formal_callable.signatures(self.db);
                let formal_is_single_paramspec = formal_callable.is_single_paramspec().is_some();

                for actual_callable in actual_callables.as_slice() {
                    if formal_is_single_paramspec {
                        let when = actual_callable
                            .signatures(self.db)
                            .when_constraint_set_assignable_to(
                                self.db,
                                formal_callable,
                                self.inferable,
                            );
                        self.add_type_mappings_from_constraint_set(formal, when, &mut f);
                    } else {
                        for actual_signature in &actual_callable.signatures(self.db).overloads {
                            let when = actual_signature
                                .when_constraint_set_assignable_to_signatures(
                                    self.db,
                                    formal_callable,
                                    self.inferable,
                                );
                            self.add_type_mappings_from_constraint_set(formal, when, &mut f);
                        }
                    }
                }
            }

            // Expand type aliases in the actual type.
            //