flux_rustc_bridge/
lowering.rs

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