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