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