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