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