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