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