Skip to main content

flux_rustc_bridge/
lowering.rs

1use std::rc::Rc;
2
3use flux_arc_interner::List;
4use flux_common::result::ResultExt;
5use flux_errors::FluxSession;
6use itertools::Itertools;
7use rustc_borrowck::consumers::BodyWithBorrowckFacts;
8use rustc_errors::ErrorGuaranteed;
9use rustc_hir::def_id::{DefId, LocalDefId};
10use rustc_infer::{
11    infer::{InferCtxt, TyCtxtInferExt},
12    traits::Obligation,
13};
14use rustc_macros::{Decodable, Encodable};
15use rustc_middle::{
16    mir::{self as rustc_mir},
17    traits::{ImplSource, ObligationCause},
18    ty::{
19        self as rustc_ty, GenericArgKind, ParamConst, ParamEnv, TyCtxt, TypingMode,
20        adjustment as rustc_adjustment,
21    },
22};
23use rustc_span::Span;
24use rustc_trait_selection::traits::SelectionContext;
25
26use super::{
27    mir::{
28        AggregateKind, AssertKind, BasicBlockData, BinOp, Body, CallArgs, CastKind, LocalDecl,
29        NonDivergingIntrinsic, Operand, Place, PlaceElem, PointerCast, Rvalue, Statement,
30        StatementKind, Terminator, TerminatorKind,
31    },
32    ty::{
33        AdtDef, AdtDefData, AliasKind, Binder, BoundRegion, BoundVariableKind, Clause, ClauseKind,
34        Const, ConstKind, ExistentialPredicate, ExistentialProjection, FieldDef, FnSig, GenericArg,
35        GenericParamDef, GenericParamDefKind, GenericPredicates, Generics, OutlivesPredicate,
36        TraitPredicate, TraitRef, Ty, TypeOutlivesPredicate, UnevaluatedConst, VariantDef,
37    },
38};
39use crate::{
40    mir::{BodyKind, BodyRoot, CallKind, ConstOperand},
41    ty::{
42        AliasTy, BoundRegionKind, ExistentialTraitRef, GenericArgs, ProjectionPredicate, Region,
43        RegionOutlivesPredicate,
44    },
45};
46
47pub trait Lower<'tcx> {
48    type R;
49
50    fn lower(self, tcx: TyCtxt<'tcx>) -> Self::R;
51}
52
53pub struct MirLoweringCtxt<'a, 'sess, 'tcx> {
54    tcx: TyCtxt<'tcx>,
55    param_env: ParamEnv<'tcx>,
56    selcx: SelectionContext<'a, 'tcx>,
57    sess: &'sess FluxSession,
58    rustc_mir: &'a rustc_mir::Body<'tcx>,
59}
60
61#[derive(Debug, Clone)]
62pub struct UnsupportedReason {
63    pub(crate) descr: String,
64}
65
66impl UnsupportedReason {
67    fn new(reason: impl ToString) -> Self {
68        UnsupportedReason { descr: reason.to_string() }
69    }
70
71    pub fn into_err(self) -> UnsupportedErr {
72        UnsupportedErr { descr: self.descr, span: None }
73    }
74}
75
76#[derive(Debug, Clone, Encodable, Decodable)]
77pub struct UnsupportedErr {
78    pub descr: String,
79    pub span: Option<Span>,
80}
81
82impl UnsupportedErr {
83    pub fn new(reason: UnsupportedReason) -> Self {
84        UnsupportedErr { descr: reason.descr, span: None }
85    }
86
87    pub fn with_span(mut self, span: Span) -> Self {
88        self.span = Some(span);
89        self
90    }
91}
92
93fn trait_ref_impl_id<'tcx>(
94    tcx: TyCtxt<'tcx>,
95    selcx: &mut SelectionContext<'_, 'tcx>,
96    param_env: ParamEnv<'tcx>,
97    trait_ref: rustc_ty::TraitRef<'tcx>,
98) -> Option<(DefId, rustc_middle::ty::GenericArgsRef<'tcx>)> {
99    let trait_ref = tcx.erase_and_anonymize_regions(trait_ref);
100    let obligation = Obligation::new(tcx, ObligationCause::dummy(), param_env, trait_ref);
101    let impl_source = selcx.select(&obligation).ok()??;
102    let impl_source = selcx.infcx.resolve_vars_if_possible(impl_source);
103    // let impl_source = selcx.infcx.fully_resolve(impl_source).ok()?;
104    let ImplSource::UserDefined(impl_data) = impl_source else { return None };
105    Some((impl_data.impl_def_id, impl_data.args))
106}
107
108pub fn resolve_trait_ref_impl_id<'tcx>(
109    tcx: TyCtxt<'tcx>,
110    def_id: DefId,
111    trait_ref: rustc_ty::TraitRef<'tcx>,
112) -> Option<(DefId, rustc_middle::ty::GenericArgsRef<'tcx>)> {
113    let param_env = tcx.param_env(def_id);
114    let infcx = tcx
115        .infer_ctxt()
116        .with_next_trait_solver(true)
117        .build(TypingMode::non_body_analysis());
118    trait_ref_impl_id(tcx, &mut SelectionContext::new(&infcx), param_env, trait_ref)
119}
120
121pub fn resolve_call_query<'tcx>(
122    tcx: TyCtxt<'tcx>,
123    selcx: &mut SelectionContext<'_, 'tcx>,
124    param_env: ParamEnv<'tcx>,
125    callee_id: DefId,
126    args: rustc_middle::ty::GenericArgsRef<'tcx>,
127) -> Option<(DefId, rustc_middle::ty::GenericArgsRef<'tcx>)> {
128    let trait_id = tcx.trait_of_assoc(callee_id)?;
129    let trait_ref = rustc_ty::TraitRef::from_assoc(tcx, trait_id, args);
130    let (impl_def_id, impl_args) = trait_ref_impl_id(tcx, selcx, param_env, trait_ref)?;
131    let impl_args = args.rebase_onto(tcx, trait_id, impl_args);
132    let assoc_id = tcx.impl_item_implementor_ids(impl_def_id).get(&callee_id)?;
133    let assoc_item = tcx.associated_item(assoc_id);
134    Some((assoc_item.def_id, impl_args))
135}
136
137impl<'sess, 'tcx> MirLoweringCtxt<'_, 'sess, 'tcx> {
138    // We used to call `replicate_infer_ctxt` to compute the `infcx`
139    // which replicated the [`InferCtxt`] used for mir typeck
140    // by generating region variables for every region the body.
141    // HOWEVER,the rustc folks hid access to the region-variables
142    // so instead we have to take care to call `tcx.erase_regions(..)`
143    // before using the `infcx` or `SelectionContext` to do any queries
144    // (eg. see `get_impl_id_of_alias_reft` in projections.rs)
145    pub fn lower_mir_body(
146        tcx: TyCtxt<'tcx>,
147        sess: &'sess FluxSession,
148        def_id: LocalDefId,
149        body_with_facts: Rc<BodyWithBorrowckFacts<'tcx>>,
150    ) -> Result<BodyRoot<'tcx>, ErrorGuaranteed> {
151        let infcx = tcx
152            .infer_ctxt()
153            .with_next_trait_solver(true)
154            .build(TypingMode::analysis_in_body(tcx, def_id));
155        let def_id = body_with_facts.body.source.def_id();
156
157        let body =
158            Self::lower_rustc_body(tcx, &infcx, sess, def_id, &body_with_facts, BodyKind::Main)?;
159        let promoted = body_with_facts
160            .promoted
161            .indices()
162            .map(|promoted| {
163                Self::lower_rustc_body(
164                    tcx,
165                    &infcx,
166                    sess,
167                    def_id,
168                    &body_with_facts,
169                    BodyKind::Promoted(promoted),
170                )
171            })
172            .try_collect()?;
173
174        let body_root = BodyRoot::new(body_with_facts, infcx, body, promoted);
175        Ok(body_root)
176    }
177
178    fn lower_rustc_body(
179        tcx: TyCtxt<'tcx>,
180        infcx: &InferCtxt<'tcx>,
181        sess: &'sess FluxSession,
182        def_id: DefId,
183        facts: &Rc<BodyWithBorrowckFacts<'tcx>>,
184        kind: BodyKind,
185    ) -> Result<Body<'tcx>, ErrorGuaranteed> {
186        let body = kind.select_body(facts);
187        let selcx = SelectionContext::new(infcx);
188        let param_env = tcx.param_env(def_id);
189        let mut lower = MirLoweringCtxt { tcx, selcx, param_env, sess, rustc_mir: body };
190
191        let basic_blocks = body
192            .basic_blocks
193            .iter()
194            .map(|bb_data| lower.lower_basic_block_data(bb_data))
195            .try_collect()?;
196
197        let local_decls = body
198            .local_decls
199            .iter()
200            .map(|local_decl| lower.lower_local_decl(local_decl))
201            .try_collect()?;
202
203        Ok(Body::new(basic_blocks, local_decls, Rc::clone(facts), kind))
204    }
205
206    fn lower_basic_block_data(
207        &mut self,
208        data: &rustc_mir::BasicBlockData<'tcx>,
209    ) -> Result<BasicBlockData<'tcx>, ErrorGuaranteed> {
210        let data = BasicBlockData {
211            statements: data
212                .statements
213                .iter()
214                .map(|stmt| self.lower_statement(stmt))
215                .try_collect()?,
216            terminator: data
217                .terminator
218                .as_ref()
219                .map(|terminator| self.lower_terminator(terminator))
220                .transpose()?,
221            is_cleanup: data.is_cleanup,
222        };
223        Ok(data)
224    }
225
226    fn lower_local_decl(
227        &self,
228        local_decl: &rustc_mir::LocalDecl<'tcx>,
229    ) -> Result<LocalDecl, ErrorGuaranteed> {
230        Ok(LocalDecl {
231            ty: local_decl
232                .ty
233                .lower(self.tcx)
234                .map_err(|err| errors::UnsupportedLocalDecl::new(local_decl, err))
235                .emit(self.sess)?,
236            source_info: local_decl.source_info,
237        })
238    }
239
240    fn lower_statement(
241        &self,
242        stmt: &rustc_mir::Statement<'tcx>,
243    ) -> Result<Statement<'tcx>, ErrorGuaranteed> {
244        let span = stmt.source_info.span;
245        let kind = match &stmt.kind {
246            rustc_mir::StatementKind::Assign(box (place, rvalue)) => {
247                StatementKind::Assign(
248                    lower_place(self.tcx, place)
249                        .map_err(|reason| errors::UnsupportedMir::statement(span, reason))
250                        .emit(self.sess)?,
251                    self.lower_rvalue(rvalue)
252                        .map_err(|reason| errors::UnsupportedMir::statement(span, reason))
253                        .emit(self.sess)?,
254                )
255            }
256            rustc_mir::StatementKind::SetDiscriminant { place, variant_index } => {
257                StatementKind::SetDiscriminant(
258                    lower_place(self.tcx, place)
259                        .map_err(|reason| errors::UnsupportedMir::statement(span, reason))
260                        .emit(self.sess)?,
261                    *variant_index,
262                )
263            }
264            rustc_mir::StatementKind::FakeRead(box (cause, place)) => {
265                StatementKind::FakeRead(Box::new((
266                    *cause,
267                    lower_place(self.tcx, place)
268                        .map_err(|reason| errors::UnsupportedMir::statement(span, reason))
269                        .emit(self.sess)?,
270                )))
271            }
272            rustc_mir::StatementKind::PlaceMention(place) => {
273                StatementKind::PlaceMention(
274                    lower_place(self.tcx, place)
275                        .map_err(|reason| errors::UnsupportedMir::statement(span, reason))
276                        .emit(self.sess)?,
277                )
278            }
279            rustc_mir::StatementKind::Nop
280            | rustc_mir::StatementKind::StorageLive(_)
281            | rustc_mir::StatementKind::StorageDead(_) => StatementKind::Nop,
282            rustc_mir::StatementKind::AscribeUserType(
283                box (place, rustc_mir::UserTypeProjection { projs, .. }),
284                variance,
285            ) if projs.is_empty() => {
286                StatementKind::AscribeUserType(
287                    lower_place(self.tcx, place)
288                        .map_err(|reason| errors::UnsupportedMir::statement(span, reason))
289                        .emit(self.sess)?,
290                    *variance,
291                )
292            }
293            rustc_mir::StatementKind::Intrinsic(ndi) => {
294                match ndi.as_ref() {
295                    rustc_mir::NonDivergingIntrinsic::Assume(op) => {
296                        let op = self
297                            .lower_operand(op)
298                            .map_err(|reason| errors::UnsupportedMir::statement(span, reason))
299                            .emit(self.sess)?;
300                        StatementKind::Intrinsic(NonDivergingIntrinsic::Assume(op))
301                    }
302                    rustc_mir::NonDivergingIntrinsic::CopyNonOverlapping(_) => {
303                        return Err(errors::UnsupportedMir::from(stmt)).emit(self.sess);
304                    }
305                }
306            }
307
308            rustc_mir::StatementKind::Retag(_, _)
309            | rustc_mir::StatementKind::AscribeUserType(..)
310            | rustc_mir::StatementKind::Coverage(_)
311            | rustc_mir::StatementKind::ConstEvalCounter
312            | rustc_mir::StatementKind::BackwardIncompatibleDropHint { .. } => {
313                return Err(errors::UnsupportedMir::from(stmt)).emit(self.sess);
314            }
315        };
316        Ok(Statement { kind, source_info: stmt.source_info })
317    }
318
319    fn lower_terminator(
320        &mut self,
321        terminator: &rustc_mir::Terminator<'tcx>,
322    ) -> Result<Terminator<'tcx>, ErrorGuaranteed> {
323        let span = terminator.source_info.span;
324        let kind = match &terminator.kind {
325            rustc_mir::TerminatorKind::Return => TerminatorKind::Return,
326            rustc_mir::TerminatorKind::Call { func, args, destination, target, unwind, .. } => {
327                let kind = {
328                    let func_ty = func.ty(self.rustc_mir, self.tcx);
329                    match func_ty.kind() {
330                        rustc_middle::ty::TyKind::FnDef(fn_def, args) => {
331                            let lowered = args
332                                .lower(self.tcx)
333                                .map_err(|reason| errors::UnsupportedMir::terminator(span, reason))
334                                .emit(self.sess)?;
335                            let def_id = *fn_def;
336                            let generic_args = CallArgs { orig: args, lowered };
337                            let (resolved_id, resolved_args) = self
338                                .resolve_call(def_id, generic_args.orig)
339                                .map_err(|reason| {
340                                    errors::UnsupportedMir::new(span, "terminator call", reason)
341                                })
342                                .emit(self.sess)?;
343                            CallKind::FnDef { def_id, generic_args, resolved_id, resolved_args }
344                        }
345                        rustc_middle::ty::TyKind::FnPtr(fn_sig_tys, header) => {
346                            let fn_sig = fnptr_as_fnsig(fn_sig_tys, header)
347                                .lower(self.tcx)
348                                .map_err(|reason| errors::UnsupportedMir::terminator(span, reason))
349                                .emit(self.sess)?;
350                            let operand = self
351                                .lower_operand(func)
352                                .map_err(|reason| {
353                                    errors::UnsupportedMir::new(
354                                        span,
355                                        "function pointer target",
356                                        reason,
357                                    )
358                                })
359                                .emit(self.sess)?;
360                            CallKind::FnPtr { fn_sig, operand }
361                        }
362                        _ => {
363                            Err(errors::UnsupportedMir::terminator(
364                                span,
365                                UnsupportedReason::new(format!(
366                                    "unsupported callee type `{func_ty:?}`"
367                                )),
368                            ))
369                            .emit(self.sess)?
370                        }
371                    }
372                };
373
374                let destination = lower_place(self.tcx, destination)
375                    .map_err(|reason| {
376                        errors::UnsupportedMir::new(span, "terminator destination", reason)
377                    })
378                    .emit(self.sess)?;
379
380                TerminatorKind::Call {
381                    kind,
382                    destination,
383                    target: *target,
384                    args: args
385                        .iter()
386                        .map(|arg| {
387                            self.lower_operand(&arg.node).map_err(|reason| {
388                                errors::UnsupportedMir::new(span, "terminator args", reason)
389                            })
390                        })
391                        .try_collect()
392                        .emit(self.sess)?,
393                    unwind: *unwind,
394                }
395            }
396            rustc_mir::TerminatorKind::SwitchInt { discr, targets, .. } => {
397                TerminatorKind::SwitchInt {
398                    discr: self
399                        .lower_operand(discr)
400                        .map_err(|reason| errors::UnsupportedMir::terminator(span, reason))
401                        .emit(self.sess)?,
402                    targets: targets.clone(),
403                }
404            }
405            rustc_mir::TerminatorKind::Goto { target } => TerminatorKind::Goto { target: *target },
406            rustc_mir::TerminatorKind::Drop { place, target, unwind, .. } => {
407                TerminatorKind::Drop {
408                    place: lower_place(self.tcx, place)
409                        .map_err(|reason| errors::UnsupportedMir::terminator(span, reason))
410                        .emit(self.sess)?,
411                    target: *target,
412                    unwind: *unwind,
413                }
414            }
415            rustc_mir::TerminatorKind::Assert { cond, target, expected, msg, .. } => {
416                TerminatorKind::Assert {
417                    cond: self
418                        .lower_operand(cond)
419                        .map_err(|reason| errors::UnsupportedMir::terminator(span, reason))
420                        .emit(self.sess)?,
421                    expected: *expected,
422                    target: *target,
423                    msg: self
424                        .lower_assert_msg(msg)
425                        .ok_or_else(|| errors::UnsupportedMir::from(terminator))
426                        .emit(self.sess)?,
427                }
428            }
429            rustc_mir::TerminatorKind::Unreachable => TerminatorKind::Unreachable,
430            rustc_mir::TerminatorKind::FalseEdge { real_target, imaginary_target } => {
431                TerminatorKind::FalseEdge {
432                    real_target: *real_target,
433                    imaginary_target: *imaginary_target,
434                }
435            }
436            rustc_mir::TerminatorKind::FalseUnwind { real_target, unwind } => {
437                TerminatorKind::FalseUnwind { real_target: *real_target, unwind: *unwind }
438            }
439            rustc_mir::TerminatorKind::Yield { value, resume, resume_arg, drop } => {
440                TerminatorKind::Yield {
441                    value: self
442                        .lower_operand(value)
443                        .map_err(|reason| errors::UnsupportedMir::terminator(span, reason))
444                        .emit(self.sess)?,
445                    resume: *resume,
446                    resume_arg: lower_place(self.tcx, resume_arg)
447                        .map_err(|reason| errors::UnsupportedMir::terminator(span, reason))
448                        .emit(self.sess)?,
449                    drop: *drop,
450                }
451            }
452            rustc_mir::TerminatorKind::CoroutineDrop => TerminatorKind::CoroutineDrop,
453            rustc_mir::TerminatorKind::UnwindResume => TerminatorKind::UnwindResume,
454            rustc_mir::TerminatorKind::UnwindTerminate(..)
455            | rustc_mir::TerminatorKind::TailCall { .. }
456            | rustc_mir::TerminatorKind::InlineAsm { .. } => {
457                return Err(errors::UnsupportedMir::from(terminator)).emit(self.sess);
458            }
459        };
460        Ok(Terminator { kind, source_info: terminator.source_info })
461    }
462
463    fn resolve_call(
464        &mut self,
465        callee_id: DefId,
466        args: rustc_middle::ty::GenericArgsRef<'tcx>,
467    ) -> Result<(DefId, CallArgs<'tcx>), UnsupportedReason> {
468        let (resolved_id, resolved_args) =
469            resolve_call_query(self.tcx, &mut self.selcx, self.param_env, callee_id, args)
470                .unwrap_or((callee_id, args));
471        let call_args = CallArgs { lowered: resolved_args.lower(self.tcx)?, orig: resolved_args };
472        Ok((resolved_id, call_args))
473    }
474
475    fn lower_rvalue(
476        &self,
477        rvalue: &rustc_mir::Rvalue<'tcx>,
478    ) -> Result<Rvalue<'tcx>, UnsupportedReason> {
479        match rvalue {
480            rustc_mir::Rvalue::Use(op) => Ok(Rvalue::Use(self.lower_operand(op)?)),
481            rustc_mir::Rvalue::Repeat(op, c) => {
482                let op = self.lower_operand(op)?;
483                let c = c.lower(self.tcx)?;
484                Ok(Rvalue::Repeat(op, c))
485            }
486            rustc_mir::Rvalue::Ref(region, bk, p) => {
487                Ok(Rvalue::Ref(region.lower(self.tcx)?, *bk, lower_place(self.tcx, p)?))
488            }
489            rustc_mir::Rvalue::RawPtr(kind, place) => {
490                Ok(Rvalue::RawPtr(*kind, lower_place(self.tcx, place)?))
491            }
492            rustc_mir::Rvalue::Cast(kind, op, ty) => {
493                let kind = self.lower_cast_kind(*kind).ok_or_else(|| {
494                    UnsupportedReason::new(format!("unsupported cast `{kind:?}`"))
495                })?;
496                let op = self.lower_operand(op)?;
497                let ty = ty.lower(self.tcx)?;
498                Ok(Rvalue::Cast(kind, op, ty))
499            }
500            rustc_mir::Rvalue::BinaryOp(bin_op, box (op1, op2)) => {
501                Ok(Rvalue::BinaryOp(
502                    self.lower_bin_op(*bin_op)?,
503                    self.lower_operand(op1)?,
504                    self.lower_operand(op2)?,
505                ))
506            }
507            rustc_mir::Rvalue::UnaryOp(un_op, op) => {
508                Ok(Rvalue::UnaryOp(*un_op, self.lower_operand(op)?))
509            }
510            rustc_mir::Rvalue::Discriminant(p) => {
511                Ok(Rvalue::Discriminant(lower_place(self.tcx, p)?))
512            }
513            rustc_mir::Rvalue::Aggregate(aggregate_kind, args) => {
514                let aggregate_kind = self.lower_aggregate_kind(aggregate_kind)?;
515                let args = args.iter().map(|op| self.lower_operand(op)).try_collect()?;
516                Ok(Rvalue::Aggregate(aggregate_kind, args))
517            }
518            rustc_mir::Rvalue::ShallowInitBox(op, ty) => {
519                Ok(Rvalue::ShallowInitBox(self.lower_operand(op)?, ty.lower(self.tcx)?))
520            }
521            rustc_mir::Rvalue::ThreadLocalRef(_)
522            | rustc_mir::Rvalue::CopyForDeref(_)
523            | rustc_mir::Rvalue::WrapUnsafeBinder(..) => {
524                Err(UnsupportedReason::new(format!("unsupported rvalue `{rvalue:?}`")))
525            }
526        }
527    }
528
529    fn lower_pointer_coercion(
530        &self,
531        coercion: rustc_adjustment::PointerCoercion,
532    ) -> Option<PointerCast> {
533        match coercion {
534            rustc_adjustment::PointerCoercion::MutToConstPointer => {
535                Some(crate::mir::PointerCast::MutToConstPointer)
536            }
537            rustc_adjustment::PointerCoercion::Unsize => Some(crate::mir::PointerCast::Unsize),
538            rustc_adjustment::PointerCoercion::ClosureFnPointer(_) => {
539                Some(crate::mir::PointerCast::ClosureFnPointer)
540            }
541            rustc_adjustment::PointerCoercion::ReifyFnPointer(safety) => {
542                Some(crate::mir::PointerCast::ReifyFnPointer(safety))
543            }
544            rustc_adjustment::PointerCoercion::UnsafeFnPointer
545            | rustc_adjustment::PointerCoercion::ArrayToPointer => None,
546        }
547    }
548    fn lower_cast_kind(&self, kind: rustc_mir::CastKind) -> Option<CastKind> {
549        match kind {
550            rustc_mir::CastKind::IntToInt => Some(CastKind::IntToInt),
551            rustc_mir::CastKind::IntToFloat => Some(CastKind::IntToFloat),
552            rustc_mir::CastKind::FloatToInt => Some(CastKind::FloatToInt),
553            rustc_mir::CastKind::FloatToFloat => Some(CastKind::FloatToFloat),
554            rustc_mir::CastKind::PtrToPtr => Some(CastKind::PtrToPtr),
555            rustc_mir::CastKind::PointerCoercion(ptr_coercion, _) => {
556                Some(CastKind::PointerCoercion(self.lower_pointer_coercion(ptr_coercion)?))
557            }
558            rustc_mir::CastKind::PointerExposeProvenance => Some(CastKind::PointerExposeProvenance),
559            rustc_mir::CastKind::PointerWithExposedProvenance => {
560                Some(CastKind::PointerWithExposedProvenance)
561            }
562            _ => None,
563        }
564    }
565
566    fn lower_aggregate_kind(
567        &self,
568        aggregate_kind: &rustc_mir::AggregateKind<'tcx>,
569    ) -> Result<AggregateKind, UnsupportedReason> {
570        match aggregate_kind {
571            rustc_mir::AggregateKind::Adt(
572                def_id,
573                variant_idx,
574                args,
575                user_type_annot_idx,
576                field_idx,
577            ) => {
578                Ok(AggregateKind::Adt(
579                    *def_id,
580                    *variant_idx,
581                    args.lower(self.tcx)?,
582                    *user_type_annot_idx,
583                    *field_idx,
584                ))
585            }
586            rustc_mir::AggregateKind::Array(ty) => Ok(AggregateKind::Array(ty.lower(self.tcx)?)),
587            rustc_mir::AggregateKind::Tuple => Ok(AggregateKind::Tuple),
588            rustc_mir::AggregateKind::Closure(did, args) => {
589                let args = args.lower(self.tcx)?;
590                Ok(AggregateKind::Closure(*did, args))
591            }
592            rustc_mir::AggregateKind::Coroutine(did, args) => {
593                let args = args.lower(self.tcx)?;
594                Ok(AggregateKind::Coroutine(*did, args))
595            }
596            rustc_mir::AggregateKind::RawPtr(_, _)
597            | rustc_mir::AggregateKind::CoroutineClosure(..) => {
598                Err(UnsupportedReason::new(format!(
599                    "unsupported aggregate kind `{aggregate_kind:?}`"
600                )))
601            }
602        }
603    }
604
605    fn lower_bin_op(&self, bin_op: rustc_mir::BinOp) -> Result<BinOp, UnsupportedReason> {
606        match bin_op {
607            rustc_mir::BinOp::Add => Ok(BinOp::Add),
608            rustc_mir::BinOp::Sub => Ok(BinOp::Sub),
609            rustc_mir::BinOp::Gt => Ok(BinOp::Gt),
610            rustc_mir::BinOp::Ge => Ok(BinOp::Ge),
611            rustc_mir::BinOp::Lt => Ok(BinOp::Lt),
612            rustc_mir::BinOp::Le => Ok(BinOp::Le),
613            rustc_mir::BinOp::Eq => Ok(BinOp::Eq),
614            rustc_mir::BinOp::Ne => Ok(BinOp::Ne),
615            rustc_mir::BinOp::Mul => Ok(BinOp::Mul),
616            rustc_mir::BinOp::Div => Ok(BinOp::Div),
617            rustc_mir::BinOp::Rem => Ok(BinOp::Rem),
618            rustc_mir::BinOp::BitAnd => Ok(BinOp::BitAnd),
619            rustc_mir::BinOp::BitOr => Ok(BinOp::BitOr),
620            rustc_mir::BinOp::BitXor => Ok(BinOp::BitXor),
621            rustc_mir::BinOp::Shl => Ok(BinOp::Shl),
622            rustc_mir::BinOp::Shr => Ok(BinOp::Shr),
623            rustc_mir::BinOp::AddUnchecked
624            | rustc_mir::BinOp::SubUnchecked
625            | rustc_mir::BinOp::MulUnchecked
626            | rustc_mir::BinOp::ShlUnchecked
627            | rustc_mir::BinOp::ShrUnchecked
628            | rustc_mir::BinOp::AddWithOverflow
629            | rustc_mir::BinOp::SubWithOverflow
630            | rustc_mir::BinOp::MulWithOverflow
631            | rustc_mir::BinOp::Cmp
632            | rustc_mir::BinOp::Offset => {
633                Err(UnsupportedReason::new(format!("unsupported binary op `{bin_op:?}`")))
634            }
635        }
636    }
637
638    fn lower_operand(
639        &self,
640        op: &rustc_mir::Operand<'tcx>,
641    ) -> Result<Operand<'tcx>, UnsupportedReason> {
642        match op {
643            rustc_mir::Operand::Copy(place) => Ok(Operand::Copy(lower_place(self.tcx, place)?)),
644            rustc_mir::Operand::Move(place) => Ok(Operand::Move(lower_place(self.tcx, place)?)),
645            rustc_mir::Operand::Constant(c) => Ok(Operand::Constant(self.lower_constant(c)?)),
646            rustc_mir::Operand::RuntimeChecks(..) => {
647                Err(UnsupportedReason::new(format!("unsupported operand `{op:?}`")))
648            }
649        }
650    }
651
652    fn lower_constant(
653        &self,
654        constant: &rustc_mir::ConstOperand<'tcx>,
655    ) -> Result<ConstOperand<'tcx>, UnsupportedReason> {
656        Ok(ConstOperand {
657            span: constant.span,
658            ty: constant.const_.ty().lower(self.tcx)?,
659            const_: constant.const_,
660        })
661    }
662
663    fn lower_assert_msg(&self, msg: &rustc_mir::AssertMessage) -> Option<AssertKind> {
664        use rustc_mir::AssertKind::*;
665        match msg {
666            BoundsCheck { .. } => Some(AssertKind::BoundsCheck),
667            DivisionByZero(_) => Some(AssertKind::DivisionByZero),
668            RemainderByZero(_) => Some(AssertKind::RemainderByZero),
669            Overflow(bin_op, ..) => Some(AssertKind::Overflow(self.lower_bin_op(*bin_op).ok()?)),
670            _ => None,
671        }
672    }
673}
674
675pub fn lower_place<'tcx>(
676    _tcx: TyCtxt<'tcx>,
677    place: &rustc_mir::Place<'tcx>,
678) -> Result<Place, UnsupportedReason> {
679    let mut projection = vec![];
680    for elem in place.projection {
681        match elem {
682            rustc_mir::PlaceElem::Deref => projection.push(PlaceElem::Deref),
683            rustc_mir::PlaceElem::Field(field, _) => projection.push(PlaceElem::Field(field)),
684            rustc_mir::PlaceElem::Downcast(name, idx) => {
685                projection.push(PlaceElem::Downcast(name, idx));
686            }
687            rustc_mir::PlaceElem::Index(v) => projection.push(PlaceElem::Index(v)),
688            rustc_mir::ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
689                projection.push(PlaceElem::ConstantIndex { offset, min_length, from_end });
690            }
691            _ => {
692                return Err(UnsupportedReason::new(format!("unsupported place `{place:?}`")));
693            }
694        }
695    }
696    Ok(Place { local: place.local, projection })
697}
698
699impl<'tcx> Lower<'tcx> for rustc_ty::FnSig<'tcx> {
700    type R = Result<FnSig, UnsupportedReason>;
701
702    fn lower(self, tcx: TyCtxt<'tcx>) -> Self::R {
703        let inputs_and_output = List::from_vec(
704            self.inputs_and_output
705                .iter()
706                .map(|ty| ty.lower(tcx))
707                .try_collect()?,
708        );
709        Ok(FnSig { safety: self.safety, abi: self.abi, inputs_and_output })
710    }
711}
712
713impl<'tcx> Lower<'tcx> for &'tcx rustc_ty::List<rustc_ty::BoundVariableKind<'tcx>> {
714    type R = Result<List<BoundVariableKind>, UnsupportedReason>;
715
716    fn lower(self, tcx: TyCtxt<'tcx>) -> Self::R {
717        let mut vars = vec![];
718        for var in self {
719            match var {
720                rustc_ty::BoundVariableKind::Region(kind) => {
721                    vars.push(BoundVariableKind::Region(kind.lower(tcx)));
722                }
723                _ => {
724                    return Err(UnsupportedReason {
725                        descr: format!("unsupported bound variable {var:?}"),
726                    });
727                }
728            }
729        }
730        Ok(List::from_vec(vars))
731    }
732}
733
734impl<'tcx> Lower<'tcx> for rustc_ty::BoundRegionKind<'tcx> {
735    type R = BoundRegionKind;
736
737    fn lower(self, _tcx: TyCtxt<'tcx>) -> Self::R {
738        match self {
739            rustc_ty::BoundRegionKind::Anon => BoundRegionKind::Anon,
740            rustc_ty::BoundRegionKind::NamedForPrinting(name) => {
741                BoundRegionKind::NamedForPrinting(name)
742            }
743            rustc_ty::BoundRegionKind::Named(def_id) => BoundRegionKind::Named(def_id),
744            rustc_ty::BoundRegionKind::ClosureEnv => BoundRegionKind::ClosureEnv,
745        }
746    }
747}
748
749impl<'tcx> Lower<'tcx> for rustc_ty::ValTree<'tcx> {
750    type R = Result<crate::ty::ValTree, UnsupportedReason>;
751
752    fn lower(self, tcx: TyCtxt<'tcx>) -> Self::R {
753        match &*self {
754            rustc_ty::ValTreeKind::Leaf(scalar_int) => Ok(crate::ty::ValTree::Leaf(*scalar_int)),
755            rustc_ty::ValTreeKind::Branch(consts) => {
756                let trees = consts.iter().map(|c| c.lower(tcx)).try_collect()?;
757                Ok(crate::ty::ValTree::Branch(trees))
758            }
759        }
760    }
761}
762
763impl<'tcx> Lower<'tcx> for rustc_ty::Const<'tcx> {
764    type R = Result<Const, UnsupportedReason>;
765
766    fn lower(self, tcx: TyCtxt<'tcx>) -> Self::R {
767        let kind = match self.kind() {
768            rustc_type_ir::ConstKind::Param(param_const) => {
769                ConstKind::Param(ParamConst { name: param_const.name, index: param_const.index })
770            }
771            rustc_type_ir::ConstKind::Value(value) => {
772                ConstKind::Value(value.ty.lower(tcx)?, value.valtree.lower(tcx)?)
773            }
774            rustc_type_ir::ConstKind::Unevaluated(c) => {
775                // TODO: raise unsupported if c.args is not empty?
776                let args = c.args.lower(tcx)?;
777                ConstKind::Unevaluated(UnevaluatedConst { def: c.def, args, promoted: None })
778            }
779            _ => return Err(UnsupportedReason::new(format!("unsupported const {self:?}"))),
780        };
781        Ok(Const { kind })
782    }
783}
784
785impl<'tcx, T, S> Lower<'tcx> for rustc_ty::Binder<'tcx, T>
786where
787    T: Lower<'tcx, R = Result<S, UnsupportedReason>>,
788{
789    type R = Result<Binder<S>, UnsupportedReason>;
790
791    fn lower(self, tcx: TyCtxt<'tcx>) -> Self::R {
792        let vars = self.bound_vars().lower(tcx)?;
793        Ok(Binder::bind_with_vars(self.skip_binder().lower(tcx)?, vars))
794    }
795}
796
797impl<'tcx> Lower<'tcx> for rustc_ty::Ty<'tcx> {
798    type R = Result<Ty, UnsupportedReason>;
799
800    fn lower(self, tcx: TyCtxt<'tcx>) -> Self::R {
801        match self.kind() {
802            rustc_ty::Ref(region, ty, mutability) => {
803                Ok(Ty::mk_ref(region.lower(tcx)?, ty.lower(tcx)?, *mutability))
804            }
805            rustc_ty::Bool => Ok(Ty::mk_bool()),
806            rustc_ty::Int(int_ty) => Ok(Ty::mk_int(*int_ty)),
807            rustc_ty::Uint(uint_ty) => Ok(Ty::mk_uint(*uint_ty)),
808            rustc_ty::Float(float_ty) => Ok(Ty::mk_float(*float_ty)),
809            rustc_ty::Param(param_ty) => Ok(Ty::mk_param(*param_ty)),
810            rustc_ty::Adt(adt_def, args) => {
811                let args = args.lower(tcx)?;
812                Ok(Ty::mk_adt(adt_def.lower(tcx), args))
813            }
814            rustc_ty::FnDef(def_id, args) => {
815                let args = args.lower(tcx)?;
816                Ok(Ty::mk_fn_def(*def_id, args))
817            }
818            rustc_ty::Never => Ok(Ty::mk_never()),
819            rustc_ty::Str => Ok(Ty::mk_str()),
820            rustc_ty::Char => Ok(Ty::mk_char()),
821            rustc_ty::Tuple(tys) => {
822                let tys = List::from_vec(tys.iter().map(|ty| ty.lower(tcx)).try_collect()?);
823                Ok(Ty::mk_tuple(tys))
824            }
825            rustc_ty::Array(ty, len) => Ok(Ty::mk_array(ty.lower(tcx)?, len.lower(tcx)?)),
826            rustc_ty::Slice(ty) => Ok(Ty::mk_slice(ty.lower(tcx)?)),
827            rustc_ty::RawPtr(ty, mutbl) => {
828                let ty = ty.lower(tcx)?;
829                Ok(Ty::mk_raw_ptr(ty, *mutbl))
830            }
831            rustc_ty::FnPtr(fn_sig_tys, header) => {
832                let fn_sig = fnptr_as_fnsig(fn_sig_tys, header).lower(tcx)?;
833                Ok(Ty::mk_fn_ptr(fn_sig))
834            }
835            rustc_ty::Closure(did, args) => {
836                let args = args.lower(tcx)?;
837                Ok(Ty::mk_closure(*did, args))
838            }
839
840            rustc_ty::Alias(kind, alias_ty) => {
841                let kind = kind.lower(tcx)?;
842                let args = alias_ty.args.lower(tcx)?;
843                Ok(Ty::mk_alias(kind, alias_ty.def_id, args))
844            }
845            rustc_ty::Coroutine(did, args) => {
846                let args = args.lower(tcx)?;
847                Ok(Ty::mk_coroutine(*did, args))
848            }
849            rustc_ty::CoroutineWitness(did, args) => {
850                let args = args.lower(tcx)?;
851                Ok(Ty::mk_generator_witness(*did, args))
852            }
853            rustc_ty::Dynamic(predicates, region) => {
854                let region = region.lower(tcx)?;
855
856                let exi_preds = List::from_vec(
857                    predicates
858                        .iter()
859                        .map(|pred| pred.lower(tcx))
860                        .try_collect()?,
861                );
862
863                Ok(Ty::mk_dynamic(exi_preds, region))
864            }
865            rustc_ty::Foreign(def_id) => Ok(Ty::mk_foreign(*def_id)),
866            rustc_ty::Pat(..) => Ok(Ty::mk_pat()),
867            _ => Err(UnsupportedReason::new(format!("unsupported type `{self:?}`"))),
868        }
869    }
870}
871
872fn fnptr_as_fnsig<'tcx>(
873    fn_sig_tys: &'tcx rustc_ty::Binder<'tcx, rustc_ty::FnSigTys<TyCtxt<'tcx>>>,
874    header: &'tcx rustc_ty::FnHeader<TyCtxt<'tcx>>,
875) -> rustc_ty::Binder<'tcx, rustc_ty::FnSig<'tcx>> {
876    fn_sig_tys.map_bound(|fn_sig_tys| {
877        rustc_ty::FnSig {
878            inputs_and_output: fn_sig_tys.inputs_and_output,
879            c_variadic: header.c_variadic,
880            safety: header.safety,
881            abi: header.abi,
882        }
883    })
884}
885
886impl<'tcx> Lower<'tcx> for rustc_ty::AliasTyKind {
887    type R = Result<AliasKind, UnsupportedReason>;
888
889    fn lower(self, _tcx: TyCtxt<'tcx>) -> Self::R {
890        match self {
891            rustc_type_ir::AliasTyKind::Projection => Ok(AliasKind::Projection),
892            rustc_type_ir::AliasTyKind::Opaque => Ok(AliasKind::Opaque),
893            _ => Err(UnsupportedReason::new(format!("unsupported alias kind `{self:?}`"))),
894        }
895    }
896}
897
898impl<'tcx> Lower<'tcx> for rustc_ty::AdtDef<'tcx> {
899    type R = AdtDef;
900
901    fn lower(self, tcx: TyCtxt<'tcx>) -> Self::R {
902        AdtDef::new(AdtDefData::new(
903            tcx,
904            self,
905            self.variants()
906                .iter()
907                .map(|variant| {
908                    VariantDef {
909                        def_id: variant.def_id,
910                        name: variant.name,
911                        fields: variant
912                            .fields
913                            .iter()
914                            .map(|f| FieldDef { did: f.did, name: f.name })
915                            .collect(),
916                    }
917                })
918                .collect(),
919        ))
920    }
921}
922
923impl<'tcx> Lower<'tcx> for rustc_ty::ExistentialPredicate<'tcx> {
924    type R = Result<ExistentialPredicate, UnsupportedReason>;
925
926    fn lower(self, tcx: TyCtxt<'tcx>) -> Self::R {
927        match self {
928            rustc_type_ir::ExistentialPredicate::Trait(trait_ref) => {
929                Ok(ExistentialPredicate::Trait(ExistentialTraitRef {
930                    def_id: trait_ref.def_id,
931                    args: trait_ref.args.lower(tcx)?,
932                }))
933            }
934            rustc_type_ir::ExistentialPredicate::Projection(proj) => {
935                let Some(term) = proj.term.as_type() else {
936                    return Err(UnsupportedReason::new(format!(
937                        "unsupported existential predicate `{self:?}`"
938                    )));
939                };
940                Ok(ExistentialPredicate::Projection(ExistentialProjection {
941                    def_id: proj.def_id,
942                    args: proj.args.lower(tcx)?,
943                    term: term.lower(tcx)?,
944                }))
945            }
946            rustc_type_ir::ExistentialPredicate::AutoTrait(def_id) => {
947                Ok(ExistentialPredicate::AutoTrait(def_id))
948            }
949        }
950    }
951}
952
953impl<'tcx> Lower<'tcx> for rustc_middle::ty::GenericArgsRef<'tcx> {
954    type R = Result<GenericArgs, UnsupportedReason>;
955
956    fn lower(self, tcx: TyCtxt<'tcx>) -> Self::R {
957        Ok(List::from_vec(self.iter().map(|arg| arg.lower(tcx)).try_collect()?))
958    }
959}
960
961impl<'tcx> Lower<'tcx> for rustc_middle::ty::GenericArg<'tcx> {
962    type R = Result<GenericArg, UnsupportedReason>;
963
964    fn lower(self, tcx: TyCtxt<'tcx>) -> Self::R {
965        match self.kind() {
966            GenericArgKind::Type(ty) => Ok(GenericArg::Ty(ty.lower(tcx)?)),
967            GenericArgKind::Lifetime(region) => Ok(GenericArg::Lifetime(region.lower(tcx)?)),
968            GenericArgKind::Const(c) => Ok(GenericArg::Const(c.lower(tcx)?)),
969        }
970    }
971}
972
973impl<'tcx> Lower<'tcx> for rustc_middle::ty::Region<'tcx> {
974    type R = Result<Region, UnsupportedReason>;
975
976    fn lower(self, tcx: TyCtxt<'tcx>) -> Self::R {
977        use rustc_middle::ty;
978        match self.kind() {
979            ty::ReVar(rvid) => Ok(Region::ReVar(rvid)),
980            ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), bregion) => {
981                Ok(Region::ReBound(
982                    debruijn,
983                    Ok(BoundRegion { kind: bregion.kind.lower(tcx), var: bregion.var })?,
984                ))
985            }
986            ty::ReEarlyParam(bregion) => Ok(Region::ReEarlyParam(bregion)),
987            ty::ReStatic => Ok(Region::ReStatic),
988            ty::ReErased => Ok(Region::ReErased),
989            ty::ReBound(ty::BoundVarIndexKind::Canonical, _)
990            | ty::ReLateParam(_)
991            | ty::RePlaceholder(_)
992            | ty::ReError(_) => {
993                Err(UnsupportedReason::new(format!("unsupported region `{self:?}`")))
994            }
995        }
996    }
997}
998
999impl<'tcx> Lower<'tcx> for &'tcx rustc_middle::ty::Generics {
1000    type R = Generics<'tcx>;
1001
1002    fn lower(self, tcx: TyCtxt<'tcx>) -> Self::R {
1003        let params = List::from_vec(
1004            self.own_params
1005                .iter()
1006                .map(|param| param.lower(tcx))
1007                .collect(),
1008        );
1009        Generics { params, orig: self }
1010    }
1011}
1012
1013impl<'tcx> Lower<'tcx> for &rustc_middle::ty::GenericParamDef {
1014    type R = GenericParamDef;
1015
1016    fn lower(self, _tcx: TyCtxt<'tcx>) -> Self::R {
1017        let kind = match self.kind {
1018            rustc_ty::GenericParamDefKind::Type { has_default, .. } => {
1019                GenericParamDefKind::Type { has_default }
1020            }
1021            rustc_ty::GenericParamDefKind::Lifetime => GenericParamDefKind::Lifetime,
1022            rustc_ty::GenericParamDefKind::Const { has_default, .. } => {
1023                GenericParamDefKind::Const { has_default }
1024            }
1025        };
1026        GenericParamDef { def_id: self.def_id, index: self.index, name: self.name, kind }
1027    }
1028}
1029
1030impl<'tcx> Lower<'tcx> for rustc_ty::GenericPredicates<'tcx> {
1031    type R = Result<GenericPredicates, UnsupportedErr>;
1032
1033    fn lower(self, tcx: TyCtxt<'tcx>) -> Self::R {
1034        let predicates = self
1035            .predicates
1036            .iter()
1037            .map(|(clause, span)| {
1038                clause
1039                    .lower(tcx)
1040                    .map_err(|reason| UnsupportedErr::new(reason).with_span(*span))
1041            })
1042            .try_collect()?;
1043        Ok(GenericPredicates { parent: self.parent, predicates })
1044    }
1045}
1046
1047impl<'tcx> Lower<'tcx> for rustc_ty::Clauses<'tcx> {
1048    type R = Result<List<Clause>, UnsupportedErr>;
1049
1050    fn lower(self, tcx: TyCtxt<'tcx>) -> Self::R {
1051        self.iter()
1052            .map(|clause| clause.lower(tcx).map_err(UnsupportedErr::new))
1053            .try_collect()
1054    }
1055}
1056
1057impl<'tcx> Lower<'tcx> for rustc_ty::ClauseKind<'tcx> {
1058    type R = Result<ClauseKind, UnsupportedReason>;
1059
1060    fn lower(self, tcx: TyCtxt<'tcx>) -> Self::R {
1061        let kind = match self {
1062            rustc_ty::ClauseKind::Trait(trait_pred) => {
1063                ClauseKind::Trait(TraitPredicate { trait_ref: trait_pred.trait_ref.lower(tcx)? })
1064            }
1065            rustc_ty::ClauseKind::Projection(proj_pred) => {
1066                let Some(term) = proj_pred.term.as_type() else {
1067                    return Err(UnsupportedReason::new(format!(
1068                        "unsupported projection predicate `{proj_pred:?}`"
1069                    )));
1070                };
1071                let proj_ty = proj_pred.projection_term;
1072                let args = proj_ty.args.lower(tcx)?;
1073
1074                let projection_ty = AliasTy { args, def_id: proj_ty.def_id };
1075                let term = term.lower(tcx)?;
1076                ClauseKind::Projection(ProjectionPredicate { projection_ty, term })
1077            }
1078            rustc_ty::ClauseKind::RegionOutlives(outlives) => {
1079                ClauseKind::RegionOutlives(outlives.lower(tcx)?)
1080            }
1081            rustc_ty::ClauseKind::TypeOutlives(outlives) => {
1082                ClauseKind::TypeOutlives(outlives.lower(tcx)?)
1083            }
1084            rustc_ty::ClauseKind::ConstArgHasType(const_, ty) => {
1085                ClauseKind::ConstArgHasType(const_.lower(tcx)?, ty.lower(tcx)?)
1086            }
1087            rustc_ty::ClauseKind::UnstableFeature(sym) => ClauseKind::UnstableFeature(sym),
1088            _ => {
1089                return Err(UnsupportedReason::new(format!("unsupported clause kind `{self:?}`")));
1090            }
1091        };
1092        Ok(kind)
1093    }
1094}
1095
1096impl<'tcx> Lower<'tcx> for rustc_ty::Clause<'tcx> {
1097    type R = Result<Clause, UnsupportedReason>;
1098
1099    fn lower(self, tcx: TyCtxt<'tcx>) -> Self::R {
1100        Ok(Clause::new(self.kind().lower(tcx)?))
1101    }
1102}
1103
1104impl<'tcx> Lower<'tcx> for rustc_ty::TraitRef<'tcx> {
1105    type R = Result<TraitRef, UnsupportedReason>;
1106
1107    fn lower(self, tcx: TyCtxt<'tcx>) -> Self::R {
1108        Ok(TraitRef { def_id: self.def_id, args: self.args.lower(tcx)? })
1109    }
1110}
1111
1112impl<'tcx> Lower<'tcx> for rustc_ty::TypeOutlivesPredicate<'tcx> {
1113    type R = Result<TypeOutlivesPredicate, UnsupportedReason>;
1114
1115    fn lower(self, tcx: TyCtxt<'tcx>) -> Self::R {
1116        Ok(OutlivesPredicate(self.0.lower(tcx)?, self.1.lower(tcx)?))
1117    }
1118}
1119
1120impl<'tcx> Lower<'tcx> for rustc_ty::RegionOutlivesPredicate<'tcx> {
1121    type R = Result<RegionOutlivesPredicate, UnsupportedReason>;
1122
1123    fn lower(self, tcx: TyCtxt<'tcx>) -> Self::R {
1124        Ok(OutlivesPredicate(self.0.lower(tcx)?, self.1.lower(tcx)?))
1125    }
1126}
1127
1128mod errors {
1129    use std::path::PathBuf;
1130
1131    use flux_errors::E0999;
1132    use flux_macros::Diagnostic;
1133    use rustc_middle::mir as rustc_mir;
1134    use rustc_span::Span;
1135
1136    use super::UnsupportedReason;
1137
1138    #[derive(Diagnostic)]
1139    #[diag(rustc_bridge_unsupported_local_decl, code = E0999)]
1140    pub(super) struct UnsupportedLocalDecl<'tcx> {
1141        #[primary_span]
1142        #[label]
1143        span: Span,
1144        ty: rustc_middle::ty::Ty<'tcx>,
1145    }
1146
1147    impl<'tcx> UnsupportedLocalDecl<'tcx> {
1148        pub(super) fn new(
1149            local_decl: &rustc_mir::LocalDecl<'tcx>,
1150            _err: UnsupportedReason,
1151        ) -> Self {
1152            Self { span: local_decl.source_info.span, ty: local_decl.ty }
1153        }
1154    }
1155
1156    #[derive(Diagnostic)]
1157    #[diag(rustc_bridge_unsupported_mir, code = E0999)]
1158    #[note]
1159    pub(super) struct UnsupportedMir {
1160        #[primary_span]
1161        span: Span,
1162        kind: &'static str,
1163        reason: UnsupportedReason,
1164    }
1165
1166    impl rustc_errors::IntoDiagArg for UnsupportedReason {
1167        fn into_diag_arg(self, _path: &mut Option<PathBuf>) -> rustc_errors::DiagArgValue {
1168            rustc_errors::DiagArgValue::Str(std::borrow::Cow::Owned(self.descr))
1169        }
1170    }
1171
1172    impl UnsupportedMir {
1173        pub(super) fn new(span: Span, kind: &'static str, reason: UnsupportedReason) -> Self {
1174            Self { span, kind, reason }
1175        }
1176
1177        pub(super) fn terminator(span: Span, reason: UnsupportedReason) -> Self {
1178            Self { span, kind: "terminator", reason }
1179        }
1180
1181        pub(super) fn statement(span: Span, reason: UnsupportedReason) -> Self {
1182            Self { span, kind: "statement", reason }
1183        }
1184    }
1185
1186    impl<'a, 'tcx> From<&'a rustc_mir::Terminator<'tcx>> for UnsupportedMir {
1187        fn from(terminator: &'a rustc_mir::Terminator<'tcx>) -> Self {
1188            Self::terminator(
1189                terminator.source_info.span,
1190                UnsupportedReason::new(format!("{terminator:?}",)),
1191            )
1192        }
1193    }
1194
1195    impl<'a, 'tcx> From<&'a rustc_mir::Statement<'tcx>> for UnsupportedMir {
1196        fn from(statement: &'a rustc_mir::Statement<'tcx>) -> Self {
1197            Self::statement(
1198                statement.source_info.span,
1199                UnsupportedReason::new(format!("{statement:?}")),
1200            )
1201        }
1202    }
1203}