@@ -2596,96 +2596,25 @@ impl Solver {
25962596 . collect ( ) ;
25972597 let mut roots: SmallSet < Var > = vs. 0 . into_iter ( ) . collect ( ) ;
25982598 roots. extend ( tracked_fresh_vars. 0 ) ;
2599- // Forall instantiation during call analysis can unify call-scope vars
2600- // with additional fresh vars that are only visible through Answer /
2601- // ResidualAnswer payloads. Finish the full reachable closure so no
2602- // reachable Variable::Quantified can leak to pinning.
2603- //
2604- // We also must include reachable vars that already became Answer but
2605- // still have pending instantiation errors. Those errors are surfaced by
2606- // finish_quantified, so excluding Answer vars here can silently drop
2607- // call-site specialization diagnostics.
2608- let roots = roots. into_iter ( ) . collect :: < Vec < _ > > ( ) ;
2609- let mut already_finished: SmallSet < Var > = SmallSet :: new ( ) ;
2610- loop {
2611- // Fixed-point: finishing can mutate solver state and expose new
2612- // reachable vars that also require finishing.
2613- let reachable_finish_vars = self . reachable_finish_vars_from_roots ( & roots) ;
2614- let mut next_round: Vec < Var > = reachable_finish_vars
2615- . into_iter ( )
2616- . filter ( |var| !already_finished. contains ( var) )
2617- . collect ( ) ;
2618- // Payload-driven overload pruning must consider solved vars even if
2619- // they already collapsed to `Answer` before finishing and therefore
2620- // are not selected by reachability-based finishing alone.
2621- next_round. extend (
2622- payload_vars
2623- . iter ( )
2624- . copied ( )
2625- . filter ( |var| !already_finished. contains ( var) ) ,
2626- ) ;
2627- next_round. sort_unstable ( ) ;
2628- next_round. dedup ( ) ;
2629- if next_round. is_empty ( ) {
2630- break ;
2631- }
2632- already_finished. extend ( next_round. iter ( ) . copied ( ) ) ;
2633- let mut subset = self . subset ( type_order) ;
2634- self . finish_quantified_with_subset_and_payloads (
2635- QuantifiedHandle ( next_round) ,
2636- infer_with_first_use,
2637- & mut |got, want| subset. is_subset_eq_probe_for_pruning ( got, want) ,
2638- Some ( & overload_witness_payloads) ,
2639- ) ?;
2640- }
2641- Ok ( ( ) )
2642- }
2643-
2644- fn reachable_finish_vars_from_roots ( & self , roots : & [ Var ] ) -> SmallSet < Var > {
2645- if roots. is_empty ( ) {
2646- return SmallSet :: new ( ) ;
2647- }
2648- let variables = self . variables . lock ( ) ;
2649- let instantiation_errors = self . instantiation_errors . read ( ) ;
2650- let mut visited: SmallSet < Var > = SmallSet :: new ( ) ;
2651- let mut reachable_finish_vars: SmallSet < Var > = SmallSet :: new ( ) ;
2652- let mut stack = roots. to_vec ( ) ;
2653- while let Some ( var) = stack. pop ( ) {
2654- if !visited. insert ( var) {
2655- continue ;
2656- }
2657- let variable = variables. get ( var) ;
2658- let needs_finish = match & * variable {
2659- Variable :: Quantified { .. } => true ,
2660- Variable :: Answer ( _) | Variable :: ResidualAnswer { .. } => {
2661- instantiation_errors. contains_key ( & var)
2662- }
2663- _ => false ,
2664- } ;
2665- if needs_finish {
2666- reachable_finish_vars. insert ( var) ;
2667- }
2668- match & * variable {
2669- Variable :: Answer ( ty) => {
2670- stack. extend ( ty. collect_maybe_placeholder_vars ( ) ) ;
2671- }
2672- Variable :: ResidualAnswer { target_vars : _, ty } => {
2673- // `target_vars` are read-gates for residual visibility,
2674- // not ownership edges for finishing reachability.
2675- stack. extend ( ty. collect_maybe_placeholder_vars ( ) ) ;
2676- }
2677- Variable :: Quantified { .. } => { }
2678- Variable :: Unwrap ( bounds) => {
2679- for ty in bounds. lower . iter ( ) . chain ( bounds. upper . iter ( ) ) {
2680- stack. extend ( ty. collect_maybe_placeholder_vars ( ) ) ;
2681- }
2682- }
2683- Variable :: PartialQuantified ( _)
2684- | Variable :: PartialContained ( _)
2685- | Variable :: Recursive => { }
2686- }
2599+ // Solve boundaries explicitly own fresh quantified tracking. We finish
2600+ // the exact boundary set (explicit roots + fresh vars + payload vars),
2601+ // rather than using reachability expansion that can miss or overreach.
2602+ let mut all_boundary_vars: Vec < Var > = roots. into_iter ( ) . collect ( ) ;
2603+ // Payload-driven overload pruning must include solved vars even if they
2604+ // already collapsed to `Answer` before boundary finishing.
2605+ all_boundary_vars. extend ( payload_vars) ;
2606+ all_boundary_vars. sort_unstable ( ) ;
2607+ all_boundary_vars. dedup ( ) ;
2608+ if all_boundary_vars. is_empty ( ) {
2609+ return Ok ( ( ) ) ;
26872610 }
2688- reachable_finish_vars
2611+ let mut subset = self . subset ( type_order) ;
2612+ self . finish_quantified_with_subset_and_payloads (
2613+ QuantifiedHandle ( all_boundary_vars) ,
2614+ infer_with_first_use,
2615+ & mut |got, want| subset. is_subset_eq_probe_for_pruning ( got, want) ,
2616+ Some ( & overload_witness_payloads) ,
2617+ )
26892618 }
26902619
26912620 /// Finish all quantified vars reachable from `ty` using the solver default
0 commit comments