Skip to main content

flux_infer/
projections.rs

1use std::iter;
2
3use flux_common::{bug, iter::IterExt, tracked_span_bug};
4use flux_middle::{
5    global_env::GlobalEnv,
6    queries::{QueryErr, QueryResult},
7    query_bug,
8    rty::{
9        self, AliasKind, AliasReft, AliasTerm, AliasTy, BaseTy, Binder, Clause, ClauseKind, Const,
10        ConstKind, EarlyBinder, Expr, ExprKind, GenericArg, List, ProjectionPredicate, RefineArgs,
11        Region, Sort, SubsetTy, SubsetTyCtor, Ty, TyKind, TyOrBase,
12        fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable, TypeVisitable},
13        refining::Refiner,
14        subst::{GenericsSubstDelegate, GenericsSubstFolder},
15    },
16};
17use flux_rustc_bridge::{ToRustc, lowering::Lower};
18use itertools::izip;
19use rustc_hir::def_id::DefId;
20use rustc_infer::traits::{BuiltinImplSource, Obligation};
21use rustc_middle::{
22    traits::{ImplSource, ObligationCause},
23    ty::{TyCtxt, Variance},
24};
25use rustc_trait_selection::{
26    solve::deeply_normalize,
27    traits::{FulfillmentError, SelectionContext},
28};
29use rustc_type_ir::TypeVisitableExt;
30
31use crate::{
32    infer::{InferCtxtAt, InferResult},
33    refine_tree::Scope,
34};
35
36pub trait NormalizeExt: TypeFoldable {
37    fn deeply_normalize(&self, infcx: &mut InferCtxtAt) -> QueryResult<Self>;
38
39    /// Deeply normalize projections but only inside sorts
40    fn deeply_normalize_sorts<'tcx>(
41        &self,
42        def_id: DefId,
43        genv: GlobalEnv<'_, 'tcx>,
44        infcx: &rustc_infer::infer::InferCtxt<'tcx>,
45    ) -> QueryResult<Self>;
46}
47
48impl<T: TypeFoldable> NormalizeExt for T {
49    fn deeply_normalize(&self, infcx: &mut InferCtxtAt) -> QueryResult<Self> {
50        let span = infcx.span;
51        let infcx_orig = &mut infcx.infcx;
52        let mut infcx = infcx_orig.branch();
53        let infcx = infcx.at(span);
54        let mut normalizer = Normalizer::new(infcx)?;
55        self.erase_regions().try_fold_with(&mut normalizer)
56    }
57
58    fn deeply_normalize_sorts<'tcx>(
59        &self,
60        def_id: DefId,
61        genv: GlobalEnv<'_, 'tcx>,
62        infcx: &rustc_infer::infer::InferCtxt<'tcx>,
63    ) -> QueryResult<Self> {
64        let mut normalizer = SortNormalizer::new(def_id, genv, infcx);
65        self.erase_regions().try_fold_with(&mut normalizer)
66    }
67}
68
69struct Normalizer<'a, 'infcx, 'genv, 'tcx> {
70    infcx: InferCtxtAt<'a, 'infcx, 'genv, 'tcx>,
71    selcx: SelectionContext<'infcx, 'tcx>,
72    param_env: List<Clause>,
73    scope: Scope,
74}
75
76impl<'a, 'infcx, 'genv, 'tcx> Normalizer<'a, 'infcx, 'genv, 'tcx> {
77    fn new(infcx: InferCtxtAt<'a, 'infcx, 'genv, 'tcx>) -> QueryResult<Self> {
78        let predicates = infcx.genv.predicates_of(infcx.def_id)?;
79        let param_env = predicates.instantiate_identity().predicates.clone();
80        let selcx = SelectionContext::new(infcx.region_infcx);
81        let scope = infcx.cursor().marker().scope().unwrap();
82        Ok(Normalizer { infcx, selcx, param_env, scope })
83    }
84
85    fn normalize_projection_ty(
86        &mut self,
87        obligation: &AliasTerm,
88    ) -> QueryResult<(bool, SubsetTyCtor)> {
89        // First we must recursively (i.e., deeply) normalize projection types before proceeding.
90        // For example, in `issue-1449.rs` when normalizing `<<MyChoice as Choice>::Session as FromState>::Role`
91        // we first recursively normalize to get `<End<B> as FromState>::Role`
92        let obligation = &obligation.try_fold_with(self)?;
93
94        let mut candidates = vec![];
95        self.assemble_candidates_from_param_env(obligation, &mut candidates);
96        self.assemble_candidates_from_trait_def(obligation, &mut candidates)
97            .unwrap_or_else(|err| tracked_span_bug!("{err:?}"));
98        self.assemble_candidates_from_impls(obligation, &mut candidates)?;
99        if candidates.is_empty() {
100            // TODO: This is a temporary hack that uses rustc's trait selection when FLUX fails;
101            //       The correct thing, e.g for `trait09.rs` is to make sure FLUX's param_env mirrors RUSTC,
102            //       by suitably chasing down the super-trait predicates,
103            //       see https://github.com/flux-rs/flux/issues/737
104            let (changed, ty_ctor) = normalize_projection_ty_with_rustc(
105                self.genv(),
106                self.def_id(),
107                self.infcx.region_infcx,
108                obligation,
109            )?;
110            return Ok((changed, ty_ctor));
111        }
112        if candidates.len() > 1 {
113            bug!("ambiguity when resolving `{obligation:?}` in {:?}", self.def_id());
114        }
115        let ctor = self.confirm_candidate(candidates.pop().unwrap(), obligation)?;
116        Ok((true, ctor))
117    }
118
119    fn find_resolved_predicates(
120        &self,
121        subst: &mut TVarSubst,
122        preds: Vec<EarlyBinder<ProjectionPredicate>>,
123    ) -> (Vec<ProjectionPredicate>, Vec<EarlyBinder<ProjectionPredicate>>) {
124        let mut resolved = vec![];
125        let mut unresolved = vec![];
126        for pred in preds {
127            let term = pred.clone().skip_binder().term;
128            let alias_term = pred.clone().map(|p| p.projection_term);
129            match subst.instantiate_partial(alias_term) {
130                Some(projection_term) => {
131                    let pred = ProjectionPredicate { projection_term, term };
132                    resolved.push(pred);
133                }
134                None => unresolved.push(pred.clone()),
135            }
136        }
137        (resolved, unresolved)
138    }
139
140    // See issue-829*.rs for an example of what this function is for.
141    fn resolve_projection_predicates(
142        &mut self,
143        subst: &mut TVarSubst,
144        impl_def_id: DefId,
145    ) -> QueryResult {
146        let mut projection_preds: Vec<_> = self
147            .genv()
148            .predicates_of(impl_def_id)?
149            .skip_binder()
150            .predicates
151            .iter()
152            .filter_map(|pred| {
153                if let ClauseKind::Projection(pred) = pred.kind_skipping_binder() {
154                    Some(EarlyBinder(pred.clone()))
155                } else {
156                    None
157                }
158            })
159            .collect();
160
161        while !projection_preds.is_empty() {
162            let (resolved, unresolved) = self.find_resolved_predicates(subst, projection_preds);
163
164            if resolved.is_empty() {
165                break; // failed: there is some unresolved projection pred!
166            }
167            for p in resolved {
168                let (_, ctor) = self.normalize_projection_ty(&p.projection_term)?;
169                subst.subset_tys(&p.term, &ctor);
170            }
171            projection_preds = unresolved;
172        }
173        Ok(())
174    }
175
176    fn confirm_candidate(
177        &mut self,
178        candidate: Candidate,
179        obligation: &AliasTerm,
180    ) -> QueryResult<SubsetTyCtor> {
181        let tcx = self.tcx();
182        match candidate {
183            Candidate::ParamEnv(pred) | Candidate::TraitDef(pred) => {
184                let rustc_obligation = obligation.to_rustc(tcx);
185                let parent_id = rustc_obligation.trait_ref(tcx).def_id;
186                // Do fn-subtyping if the candidate was a fn-trait
187                if tcx.is_fn_trait(parent_id) {
188                    let res = self
189                        .fn_subtype_projection_ty(pred, obligation)
190                        .unwrap_or_else(|err| tracked_span_bug!("{err:?}"));
191                    Ok(res)
192                } else {
193                    Ok(pred.skip_binder().term)
194                }
195            }
196            Candidate::UserDefinedImpl(impl_def_id) => {
197                // Given a projection obligation on a generic associated type
198                //     <Wrapper<bool> as Container>::Item<'r, i32[1]>
199                // and the id of a rust impl block
200                //     impl<T> Container for Wrapper<T> {
201                //         type Item<'a, U> = (&'a T, U);
202                //     }
203                //
204                // The obligation's args are the trait's args followed by the GAT's own args:
205                //     [Wrapper<bool>, 'r, i32[1]]
206                //      ^^^^^^^^^^^^^  ^^^^^^^^^^
207                //      trait args     GAT args
208
209                // 1. MATCH the self type of the rust impl block and the flux self type of the obligation
210                //    to infer a substitution
211                //        Wrapper<bool> MATCH Wrapper<T>
212                //            => {T -> bool}
213
214                let impl_trait_ref = self.genv().impl_trait_ref(impl_def_id)?.skip_binder();
215
216                let generics = self.tcx().generics_of(impl_def_id);
217
218                let mut subst = TVarSubst::new(generics);
219                for (a, b) in iter::zip(&impl_trait_ref.args, &obligation.args) {
220                    subst.generic_args(a, b);
221                }
222
223                // 2. Gather the ProjectionPredicates and solve them see issue-808.rs
224                self.resolve_projection_predicates(&mut subst, impl_def_id)?;
225
226                let mut args = subst.finish(self.tcx(), generics)?;
227
228                // 3. Append the GAT's own args (those after the trait args in the obligation)
229                //        [bool] ++ ['r, i32[1]]
230                //            => [bool, 'r, i32[1]]
231                //    For non-generic associated types there are no leftover args.
232                args.extend(
233                    obligation
234                        .args
235                        .iter()
236                        .skip(impl_trait_ref.args.len())
237                        .cloned(),
238                );
239
240                // 4. Get the associated type in the impl block and apply the substitution to it
241                //        (&'a T, U) => (&'r bool, i32[1])
242                let assoc_type_id = tcx
243                    .associated_items(impl_def_id)
244                    .in_definition_order()
245                    .find(|item| item.trait_item_def_id() == Some(obligation.def_id()))
246                    .map(|item| item.def_id)
247                    .ok_or_else(|| {
248                        query_bug!("no associated type for {obligation:?} in impl {impl_def_id:?}")
249                    })?;
250                Ok(self
251                    .genv()
252                    .type_of(assoc_type_id)?
253                    .instantiate(tcx, &args, &[])
254                    .expect_subset_ty_ctor())
255            }
256        }
257    }
258
259    fn fn_subtype_projection_ty(
260        &mut self,
261        actual: Binder<ProjectionPredicate>,
262        oblig: &AliasTerm,
263    ) -> InferResult<SubsetTyCtor> {
264        // Step 1: bs <- unpack(b1...)
265        let obligs: Vec<_> = oblig
266            .args
267            .iter()
268            .map(|arg| {
269                match arg {
270                    GenericArg::Ty(ty) => GenericArg::Ty(self.infcx.unpack(ty)),
271                    GenericArg::Base(ctor) => GenericArg::Ty(self.infcx.unpack(&ctor.to_ty())),
272                    _ => arg.clone(),
273                }
274            })
275            .collect();
276
277        let span = self.infcx.span;
278        let mut infcx = self.infcx.at(span);
279
280        let actual = infcx.ensure_resolved_evars(|infcx| {
281            // Step 2: as <- fresh(a1...)
282            let actual = actual
283                .replace_bound_vars(
284                    |_| rty::ReErased,
285                    |sort, mode, _| infcx.fresh_infer_var(sort, mode),
286                )
287                .deeply_normalize(infcx)?;
288
289            let actuals = actual.projection_term.args.iter().map(|arg| {
290                match arg {
291                    GenericArg::Base(ctor) => GenericArg::Ty(ctor.to_ty()),
292                    _ => arg.clone(),
293                }
294            });
295
296            // Step 3: bs <: as
297            for (a, b) in izip!(actuals.skip(1), obligs.iter().skip(1)) {
298                infcx.subtyping_generic_args(
299                    Variance::Contravariant,
300                    &a,
301                    b,
302                    crate::infer::ConstrReason::Predicate,
303                )?;
304            }
305            Ok(actual)
306        })?;
307        // Step 4: check all evars are solved, plug back into ProjectionPredicate
308        let actual = infcx.fully_resolve_evars(&actual);
309
310        // Step 5: generate "fresh" type for actual.term,
311        let oblig_term = actual.term.with_holes().replace_holes(|binders, kind| {
312            assert!(kind == rty::HoleKind::Pred);
313            let scope = &self.scope;
314            infcx.fresh_kvar_in_scope(binders, scope)
315        });
316
317        // Step 6: subtyping obligation on output
318        infcx.subtyping(
319            &actual.term.to_ty(),
320            &oblig_term.to_ty(),
321            crate::infer::ConstrReason::Predicate,
322        )?;
323        // Ok(ProjectionPredicate { projection_ty: actual.projection_ty, term: oblig_term })
324        Ok(oblig_term)
325    }
326
327    fn assemble_candidates_from_predicates(
328        &mut self,
329        predicates: &List<Clause>,
330        obligation: &AliasTerm,
331        ctor: fn(Binder<ProjectionPredicate>) -> Candidate,
332        candidates: &mut Vec<Candidate>,
333    ) {
334        let tcx = self.tcx();
335        let rustc_obligation = obligation.to_rustc(tcx);
336
337        for predicate in predicates {
338            if let Some(pred) = predicate.as_projection_clause()
339                && pred.skip_binder_ref().projection_term.to_rustc(tcx) == rustc_obligation
340            {
341                candidates.push(ctor(pred));
342            }
343        }
344    }
345
346    fn assemble_candidates_from_param_env(
347        &mut self,
348        obligation: &AliasTerm,
349        candidates: &mut Vec<Candidate>,
350    ) {
351        let predicates = self.param_env.clone();
352        self.assemble_candidates_from_predicates(
353            &predicates,
354            obligation,
355            Candidate::ParamEnv,
356            candidates,
357        );
358    }
359
360    fn assemble_candidates_from_trait_def(
361        &mut self,
362        obligation: &AliasTerm,
363        candidates: &mut Vec<Candidate>,
364    ) -> InferResult {
365        if let GenericArg::Base(ctor) = &obligation.args[0]
366            && let BaseTy::Alias(alias_ty @ AliasTy { kind: AliasKind::Opaque { def_id }, .. }) =
367                ctor.as_bty_skipping_binder()
368        {
369            debug_assert!(!alias_ty.has_escaping_bvars());
370            let bounds = self.genv().item_bounds(*def_id)?.instantiate(
371                self.tcx(),
372                &alias_ty.args,
373                &alias_ty.refine_args,
374            );
375            self.assemble_candidates_from_predicates(
376                &bounds,
377                obligation,
378                Candidate::TraitDef,
379                candidates,
380            );
381        }
382        Ok(())
383    }
384
385    fn assemble_candidates_from_impls(
386        &mut self,
387        obligation: &AliasTerm,
388        candidates: &mut Vec<Candidate>,
389    ) -> QueryResult {
390        let trait_ref = obligation.to_rustc(self.tcx()).trait_ref(self.tcx());
391        let trait_ref = self.tcx().erase_and_anonymize_regions(trait_ref);
392        let trait_pred = Obligation::new(
393            self.tcx(),
394            ObligationCause::dummy(),
395            self.rustc_param_env(),
396            trait_ref,
397        );
398        // FIXME(nilehmann) This is a patch to not panic inside rustc so we are
399        // able to catch the bug
400        if trait_pred.has_escaping_bound_vars() {
401            tracked_span_bug!();
402        }
403        match self.selcx.select(&trait_pred) {
404            Ok(Some(ImplSource::UserDefined(impl_data))) => {
405                candidates.push(Candidate::UserDefinedImpl(impl_data.impl_def_id));
406            }
407            Ok(_) => (),
408            Err(e) => bug!("error selecting {trait_pred:?}: {e:?}"),
409        }
410        Ok(())
411    }
412
413    fn def_id(&self) -> DefId {
414        self.infcx.def_id
415    }
416
417    fn genv(&self) -> GlobalEnv<'genv, 'tcx> {
418        self.infcx.genv
419    }
420
421    fn tcx(&self) -> TyCtxt<'tcx> {
422        self.selcx.tcx()
423    }
424
425    fn rustc_param_env(&self) -> rustc_middle::ty::ParamEnv<'tcx> {
426        self.selcx.tcx().param_env(self.def_id())
427    }
428}
429
430impl FallibleTypeFolder for Normalizer<'_, '_, '_, '_> {
431    type Error = QueryErr;
432
433    fn try_fold_sort(&mut self, sort: &Sort) -> Result<Sort, Self::Error> {
434        match sort {
435            Sort::Alias(AliasTy { kind: AliasKind::Free { def_id }, args, refine_args }) => {
436                self.genv()
437                    .normalize_free_alias_sort(*def_id, args, refine_args)?
438                    .try_fold_with(self)
439            }
440            Sort::Alias(alias_ty @ AliasTy { kind: AliasKind::Projection { .. }, .. }) => {
441                let (changed, ctor) = self.normalize_projection_ty(&alias_ty.to_alias_term())?;
442                let sort = ctor.sort();
443                if changed { sort.try_fold_with(self) } else { Ok(sort) }
444            }
445            _ => sort.try_super_fold_with(self),
446        }
447    }
448
449    // As shown in https://github.com/flux-rs/flux/issues/711 one round of `normalize_projections`
450    // can replace one projection e.g. `<Rev<Iter<[i32]> as Iterator>::Item` with another e.g.
451    // `<Iter<[i32]> as Iterator>::Item` We want to compute a "fixpoint" i.e. keep going until no
452    // change, so that e.g. the above is normalized all the way to `i32`, which is what the `changed`
453    // is for.
454    fn try_fold_ty(&mut self, ty: &Ty) -> Result<Ty, Self::Error> {
455        match ty.kind() {
456            TyKind::Indexed(
457                BaseTy::Alias(AliasTy { kind: AliasKind::Free { def_id }, args, refine_args }),
458                idx,
459            ) => {
460                Ok(self
461                    .genv()
462                    .type_of(*def_id)?
463                    .instantiate(self.tcx(), args, refine_args)
464                    .expect_ctor()
465                    .replace_bound_reft(idx))
466            }
467            TyKind::Indexed(
468                BaseTy::Alias(alias_ty @ AliasTy { kind: AliasKind::Projection { .. }, .. }),
469                idx,
470            ) => {
471                let (changed, ctor) = self.normalize_projection_ty(&alias_ty.to_alias_term())?;
472                let ty = ctor.replace_bound_reft(idx).to_ty();
473                if changed { ty.try_fold_with(self) } else { Ok(ty) }
474            }
475            _ => ty.try_super_fold_with(self),
476        }
477    }
478
479    fn try_fold_subset_ty(&mut self, sty: &SubsetTy) -> Result<SubsetTy, Self::Error> {
480        match &sty.bty {
481            BaseTy::Alias(AliasTy { kind: AliasKind::Free { .. }, .. }) => {
482                // Weak aliases are always expanded during conversion. We could in theory normalize
483                // them here but we don't guaranatee that type aliases expand to a subset ty. If we
484                // ever stop expanding aliases during conv we would need to guarantee that aliases
485                // used as a generic base expand to a subset type.
486                tracked_span_bug!()
487            }
488            BaseTy::Alias(alias_ty @ AliasTy { kind: AliasKind::Projection { .. }, .. }) => {
489                let (changed, ctor) = self.normalize_projection_ty(&alias_ty.to_alias_term())?;
490                let ty = ctor.replace_bound_reft(&sty.idx).strengthen(&sty.pred);
491                if changed { ty.try_fold_with(self) } else { Ok(ty) }
492            }
493            _ => sty.try_super_fold_with(self),
494        }
495    }
496
497    fn try_fold_expr(&mut self, expr: &Expr) -> Result<Expr, Self::Error> {
498        if let ExprKind::Alias(alias_pred, refine_args) = expr.kind() {
499            let (changed, e) = normalize_alias_reft(
500                self.genv(),
501                self.def_id(),
502                self.selcx.infcx,
503                alias_pred,
504                refine_args,
505            )?;
506            if changed { e.try_fold_with(self) } else { Ok(e) }
507        } else {
508            expr.try_super_fold_with(self)
509        }
510    }
511
512    fn try_fold_const(&mut self, c: &Const) -> Result<Const, Self::Error> {
513        let c = c.to_rustc(self.tcx());
514        rustc_trait_selection::traits::evaluate_const(self.selcx.infcx, c, self.rustc_param_env())
515            .lower(self.tcx())
516            .map_err(|e| QueryErr::unsupported(self.def_id(), e.into_err()))
517    }
518}
519
520#[derive(Debug)]
521pub enum Candidate {
522    UserDefinedImpl(DefId),
523    ParamEnv(Binder<ProjectionPredicate>),
524    TraitDef(Binder<ProjectionPredicate>),
525}
526
527#[derive(Debug)]
528struct TVarSubst {
529    args: Vec<Option<GenericArg>>,
530}
531
532impl GenericsSubstDelegate for &TVarSubst {
533    type Error = ();
534
535    fn ty_for_param(&mut self, param_ty: rustc_middle::ty::ParamTy) -> Result<Ty, Self::Error> {
536        match self.args.get(param_ty.index as usize) {
537            Some(Some(GenericArg::Ty(ty))) => Ok(ty.clone()),
538            Some(None) => Err(()),
539            arg => tracked_span_bug!("expected type for generic parameter, found `{arg:?}`"),
540        }
541    }
542
543    fn sort_for_param(&mut self, param_ty: rustc_middle::ty::ParamTy) -> Result<Sort, Self::Error> {
544        match self.args.get(param_ty.index as usize) {
545            Some(Some(GenericArg::Base(ctor))) => Ok(ctor.sort()),
546            Some(None) => Err(()),
547            arg => tracked_span_bug!("expected type for generic parameter, found `{arg:?}`"),
548        }
549    }
550
551    fn ctor_for_param(
552        &mut self,
553        param_ty: rustc_middle::ty::ParamTy,
554    ) -> Result<SubsetTyCtor, Self::Error> {
555        match self.args.get(param_ty.index as usize) {
556            Some(Some(GenericArg::Base(ctor))) => Ok(ctor.clone()),
557            Some(None) => Err(()),
558            arg => tracked_span_bug!("expected type for generic parameter, found `{arg:?}`"),
559        }
560    }
561
562    fn region_for_param(
563        &mut self,
564        ebr: rustc_middle::ty::EarlyParamRegion,
565    ) -> Result<Region, Self::Error> {
566        match self.args.get(ebr.index as usize) {
567            Some(Some(GenericArg::Lifetime(region))) => Ok(*region),
568            Some(None) => Err(()),
569            arg => tracked_span_bug!("expected region for generic parameter, found `{arg:?}`"),
570        }
571    }
572
573    fn expr_for_param_const(&self, _param_const: rustc_middle::ty::ParamConst) -> Expr {
574        tracked_span_bug!()
575    }
576
577    fn const_for_param(&mut self, _param: &Const) -> Const {
578        tracked_span_bug!()
579    }
580}
581
582struct SortNormalizer<'infcx, 'genv, 'tcx> {
583    def_id: DefId,
584    infcx: &'infcx rustc_infer::infer::InferCtxt<'tcx>,
585    genv: GlobalEnv<'genv, 'tcx>,
586}
587
588impl<'infcx, 'genv, 'tcx> SortNormalizer<'infcx, 'genv, 'tcx> {
589    fn new(
590        def_id: DefId,
591        genv: GlobalEnv<'genv, 'tcx>,
592        infcx: &'infcx rustc_infer::infer::InferCtxt<'tcx>,
593    ) -> Self {
594        Self { def_id, infcx, genv }
595    }
596}
597
598impl FallibleTypeFolder for SortNormalizer<'_, '_, '_> {
599    type Error = QueryErr;
600    fn try_fold_sort(&mut self, sort: &Sort) -> Result<Sort, Self::Error> {
601        match sort {
602            Sort::Alias(AliasTy { kind: AliasKind::Free { def_id }, args, refine_args }) => {
603                self.genv
604                    .normalize_free_alias_sort(*def_id, args, refine_args)?
605                    .try_fold_with(self)
606            }
607            Sort::Alias(alias_ty @ AliasTy { kind: AliasKind::Projection { .. }, .. }) => {
608                let (changed, ctor) = normalize_projection_ty_with_rustc(
609                    self.genv,
610                    self.def_id,
611                    self.infcx,
612                    &alias_ty.to_alias_term(),
613                )?;
614                let sort = ctor.sort();
615                if changed { sort.try_fold_with(self) } else { Ok(sort) }
616            }
617            _ => sort.try_super_fold_with(self),
618        }
619    }
620}
621
622impl TVarSubst {
623    fn new(generics: &rustc_middle::ty::Generics) -> Self {
624        Self { args: vec![None; generics.count()] }
625    }
626
627    fn instantiate_partial<T: TypeFoldable>(&mut self, pred: EarlyBinder<T>) -> Option<T> {
628        let mut folder = GenericsSubstFolder::new(&*self, &[]);
629        pred.skip_binder().try_fold_with(&mut folder).ok()
630    }
631
632    fn finish<'tcx>(
633        self,
634        tcx: TyCtxt<'tcx>,
635        generics: &'tcx rustc_middle::ty::Generics,
636    ) -> QueryResult<Vec<GenericArg>> {
637        self.args
638            .into_iter()
639            .enumerate()
640            .map(|(idx, arg)| {
641                if let Some(arg) = arg {
642                    Ok(arg)
643                } else {
644                    let param = generics.param_at(idx, tcx);
645                    Err(QueryErr::bug(
646                        None,
647                        format!("cannot infer substitution for {param:?} at index {idx}"),
648                    ))
649                }
650            })
651            .try_collect_vec()
652    }
653
654    fn generic_args(&mut self, a: &GenericArg, b: &GenericArg) {
655        match (a, b) {
656            (GenericArg::Ty(a), GenericArg::Ty(b)) => self.tys(a, b),
657            (GenericArg::Lifetime(a), GenericArg::Lifetime(b)) => self.regions(*a, *b),
658            (GenericArg::Base(a), GenericArg::Base(b)) => {
659                self.subset_tys(a, b);
660            }
661            (GenericArg::Const(a), GenericArg::Const(b)) => self.consts(a, b),
662            _ => {}
663        }
664    }
665
666    fn tys(&mut self, a: &Ty, b: &Ty) {
667        if let TyKind::Param(param_ty) = a.kind() {
668            if !b.has_escaping_bvars() {
669                self.insert_generic_arg(param_ty.index, GenericArg::Ty(b.clone()));
670            }
671        } else {
672            let a = a.shallow_canonicalize().as_ty_or_base();
673            let b = b.shallow_canonicalize().as_ty_or_base();
674            if let (TyOrBase::Base(a_ctor), TyOrBase::Base(b_ctor)) = (a, b) {
675                self.subset_tys(&a_ctor, &b_ctor);
676            }
677        }
678    }
679
680    fn subset_tys(&mut self, a: &SubsetTyCtor, b: &SubsetTyCtor) {
681        let bty_a = a.as_bty_skipping_binder();
682        let bty_b = b.as_bty_skipping_binder();
683        if let BaseTy::Param(param_ty) = bty_a {
684            if !b.has_escaping_bvars() {
685                self.insert_generic_arg(param_ty.index, GenericArg::Base(b.clone()));
686            }
687        } else {
688            self.btys(bty_a, bty_b);
689        }
690    }
691
692    fn btys(&mut self, a: &BaseTy, b: &BaseTy) {
693        match (a, b) {
694            (BaseTy::Param(param_ty), _) => {
695                if !b.has_escaping_bvars() {
696                    let sort = b.sort();
697                    let ctor =
698                        Binder::bind_with_sort(SubsetTy::trivial(b.clone(), Expr::nu()), sort);
699                    self.insert_generic_arg(param_ty.index, GenericArg::Base(ctor));
700                }
701            }
702            (BaseTy::Adt(_, a_args), BaseTy::Adt(_, b_args)) => {
703                debug_assert_eq!(a_args.len(), b_args.len());
704                for (a_arg, b_arg) in iter::zip(a_args, b_args) {
705                    self.generic_args(a_arg, b_arg);
706                }
707            }
708            (BaseTy::Array(a_ty, a_n), BaseTy::Array(b_ty, b_n)) => {
709                self.tys(a_ty, b_ty);
710                self.consts(a_n, b_n);
711            }
712            (BaseTy::Tuple(a_tys), BaseTy::Tuple(b_tys)) => {
713                debug_assert_eq!(a_tys.len(), b_tys.len());
714                for (a_ty, b_ty) in iter::zip(a_tys, b_tys) {
715                    self.tys(a_ty, b_ty);
716                }
717            }
718            (BaseTy::Ref(a_re, a_ty, _), BaseTy::Ref(b_re, b_ty, _)) => {
719                self.regions(*a_re, *b_re);
720                self.tys(a_ty, b_ty);
721            }
722            (BaseTy::Slice(a_ty), BaseTy::Slice(b_ty)) => {
723                self.tys(a_ty, b_ty);
724            }
725            _ => {}
726        }
727    }
728
729    fn regions(&mut self, a: Region, b: Region) {
730        if let Region::ReEarlyParam(ebr) = a {
731            self.insert_generic_arg(ebr.index, GenericArg::Lifetime(b));
732        }
733    }
734
735    fn consts(&mut self, a: &Const, b: &Const) {
736        if let ConstKind::Param(param_const) = a.kind {
737            self.insert_generic_arg(param_const.index, GenericArg::Const(b.clone()));
738        }
739    }
740
741    fn insert_generic_arg(&mut self, idx: u32, arg: GenericArg) {
742        if let Some(old) = &self.args[idx as usize]
743            && old != &arg
744        {
745            tracked_span_bug!("ambiguous substitution: old=`{old:?}`, new: `{arg:?}`");
746        }
747        self.args[idx as usize].replace(arg);
748    }
749}
750
751/// Normalize an [`rty::AliasTy`] by converting it to rustc, normalizing it using rustc api, and
752/// then mapping the result back to `rty`. This will lose refinements and it should only be used
753/// to normalize sorts because they should only contain unrefined types. However, we are also using
754/// it as a hack to normalize types in cases where we fail to collect a candidate, this is unsound
755/// and should be removed.
756///
757/// [`rty::AliasTy`]: AliasTy
758fn normalize_projection_ty_with_rustc<'tcx>(
759    genv: GlobalEnv<'_, 'tcx>,
760    def_id: DefId,
761    infcx: &rustc_infer::infer::InferCtxt<'tcx>,
762    obligation: &AliasTerm,
763) -> QueryResult<(bool, SubsetTyCtor)> {
764    let tcx = genv.tcx();
765    let projection_ty = obligation.to_rustc(tcx).expect_ty();
766    let projection_ty = tcx.erase_and_anonymize_regions(projection_ty);
767    let cause = ObligationCause::dummy();
768    let param_env = tcx.param_env(def_id);
769
770    let pre_ty = projection_ty.to_ty(tcx, rustc_middle::ty::IsRigid::No);
771    let at = infcx.at(&cause, param_env);
772    let ty = deeply_normalize::<rustc_middle::ty::Ty<'tcx>, FulfillmentError>(
773        at,
774        rustc_middle::ty::Unnormalized::new(pre_ty),
775    )
776    .map_err(|err| query_bug!("{err:?}"))?;
777
778    // `deeply_normalize` marks aliases it couldn't reduce as `IsRigid::Yes`. Since `IsRigid` is
779    // part of `TyKind::Alias`, comparing the types directly would always report a change for rigid
780    // projections, so reset the flag on both sides before comparing.
781    let changed = rustc_middle::ty::set_aliases_to_non_rigid(tcx, ty).skip_normalization()
782        != rustc_middle::ty::set_aliases_to_non_rigid(tcx, pre_ty).skip_normalization();
783    let rustc_ty = ty.lower(tcx).map_err(|reason| query_bug!("{reason:?}"))?;
784
785    Ok((
786        changed,
787        Refiner::default_for_item(genv, def_id)?
788            .refine_ty_or_base(&rustc_ty)?
789            .expect_base(),
790    ))
791}
792
793/// Do one step of normalization, unfolding associated refinements if they are concrete.
794///
795/// Use this if you are about to match structurally on an [`ExprKind`] and you need associated
796/// refinements to be normalized.
797pub fn structurally_normalize_expr<'tcx>(
798    genv: GlobalEnv<'_, 'tcx>,
799    def_id: DefId,
800    infcx: &rustc_infer::infer::InferCtxt<'tcx>,
801    expr: &Expr,
802) -> QueryResult<Expr> {
803    if let ExprKind::Alias(alias_pred, refine_args) = expr.kind() {
804        let (_, e) = normalize_alias_reft(genv, def_id, infcx, alias_pred, refine_args)?;
805        Ok(e)
806    } else {
807        Ok(expr.clone())
808    }
809}
810
811/// Normalizes an [`AliasReft`]. This uses the trait solver to find the [`ImplSourceUserDefinedData`]
812/// and uses the `args` there, which we map back to Flux via refining. This loses refinements,
813/// but that's fine because [`AliasReft`] should not rely on refinements for trait solving.
814fn normalize_alias_reft<'tcx>(
815    genv: GlobalEnv<'_, 'tcx>,
816    def_id: DefId,
817    infcx: &rustc_infer::infer::InferCtxt<'tcx>,
818    alias_reft: &AliasReft,
819    refine_args: &RefineArgs,
820) -> QueryResult<(bool, Expr)> {
821    let tcx = genv.tcx();
822
823    let is_final = genv.assoc_refinement(alias_reft.assoc_id)?.final_;
824    if is_final {
825        let e = genv
826            .default_assoc_refinement_body(alias_reft.assoc_id)?
827            .unwrap_or_else(|| {
828                bug!("final associated refinement without body - should be caught in desugar")
829            })
830            .instantiate(genv.tcx(), &alias_reft.args, &[])
831            .apply(refine_args);
832        return Ok((true, e));
833    }
834
835    // Get impl source
836    let mut selcx = SelectionContext::new(infcx);
837    let param_env = tcx.param_env(def_id);
838    let trait_ref = alias_reft.to_rustc_trait_ref(tcx);
839    let trait_ref = tcx.erase_and_anonymize_regions(trait_ref);
840    let trait_pred = Obligation::new(tcx, ObligationCause::dummy(), param_env, trait_ref);
841
842    let impl_source = selcx
843        .select(&trait_pred)
844        .map_err(|e| query_bug!("error selecting {trait_pred:?}: {e:?}"))?;
845
846    match impl_source {
847        Some(ImplSource::UserDefined(impl_data)) => {
848            let impl_def_id = impl_data.impl_def_id;
849            let args = Refiner::default_for_item(genv, def_id)?.refine_generic_args(
850                impl_def_id,
851                &impl_data
852                    .args
853                    .lower(tcx)
854                    .map_err(|reason| query_bug!("{reason:?}"))?,
855            )?;
856            let e = genv
857                .assoc_refinement_body_for_impl(alias_reft.assoc_id, impl_def_id)?
858                .instantiate(tcx, &args, &[])
859                .apply(refine_args);
860            Ok((true, e))
861        }
862        Some(ImplSource::Builtin(BuiltinImplSource::Misc | BuiltinImplSource::Trivial, _))
863            if let Some(body) =
864                genv.builtin_assoc_reft_body(infcx.typing_env(param_env), alias_reft) =>
865        {
866            Ok((true, body.apply(refine_args)))
867        }
868        _ => Ok((false, Expr::alias(alias_reft.clone(), refine_args.clone()))),
869    }
870}