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_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(
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::DynStar
516 | rustc_adjustment::PointerCoercion::ArrayToPointer => None,
517 }
518 }
519 fn lower_cast_kind(&self, kind: rustc_mir::CastKind) -> Option<CastKind> {
520 match kind {
521 rustc_mir::CastKind::IntToInt => Some(CastKind::IntToInt),
522 rustc_mir::CastKind::IntToFloat => Some(CastKind::IntToFloat),
523 rustc_mir::CastKind::FloatToInt => Some(CastKind::FloatToInt),
524 rustc_mir::CastKind::PtrToPtr => Some(CastKind::PtrToPtr),
525 rustc_mir::CastKind::PointerCoercion(ptr_coercion, _) => {
526 Some(CastKind::PointerCoercion(self.lower_pointer_coercion(ptr_coercion)?))
527 }
528 rustc_mir::CastKind::PointerExposeProvenance => Some(CastKind::PointerExposeProvenance),
529 rustc_mir::CastKind::PointerWithExposedProvenance => {
530 Some(CastKind::PointerWithExposedProvenance)
531 }
532 _ => None,
533 }
534 }
535
536 fn lower_aggregate_kind(
537 &self,
538 aggregate_kind: &rustc_mir::AggregateKind<'tcx>,
539 ) -> Result<AggregateKind, UnsupportedReason> {
540 match aggregate_kind {
541 rustc_mir::AggregateKind::Adt(
542 def_id,
543 variant_idx,
544 args,
545 user_type_annot_idx,
546 field_idx,
547 ) => {
548 Ok(AggregateKind::Adt(
549 *def_id,
550 *variant_idx,
551 args.lower(self.tcx)?,
552 *user_type_annot_idx,
553 *field_idx,
554 ))
555 }
556 rustc_mir::AggregateKind::Array(ty) => Ok(AggregateKind::Array(ty.lower(self.tcx)?)),
557 rustc_mir::AggregateKind::Tuple => Ok(AggregateKind::Tuple),
558 rustc_mir::AggregateKind::Closure(did, args) => {
559 let args = args.lower(self.tcx)?;
560 Ok(AggregateKind::Closure(*did, args))
561 }
562 rustc_mir::AggregateKind::Coroutine(did, args) => {
563 let args = args.lower(self.tcx)?;
564 Ok(AggregateKind::Coroutine(*did, args))
565 }
566 rustc_mir::AggregateKind::RawPtr(_, _)
567 | rustc_mir::AggregateKind::CoroutineClosure(..) => {
568 Err(UnsupportedReason::new(format!(
569 "unsupported aggregate kind `{aggregate_kind:?}`"
570 )))
571 }
572 }
573 }
574
575 fn lower_bin_op(&self, bin_op: rustc_mir::BinOp) -> Result<BinOp, UnsupportedReason> {
576 match bin_op {
577 rustc_mir::BinOp::Add => Ok(BinOp::Add),
578 rustc_mir::BinOp::Sub => Ok(BinOp::Sub),
579 rustc_mir::BinOp::Gt => Ok(BinOp::Gt),
580 rustc_mir::BinOp::Ge => Ok(BinOp::Ge),
581 rustc_mir::BinOp::Lt => Ok(BinOp::Lt),
582 rustc_mir::BinOp::Le => Ok(BinOp::Le),
583 rustc_mir::BinOp::Eq => Ok(BinOp::Eq),
584 rustc_mir::BinOp::Ne => Ok(BinOp::Ne),
585 rustc_mir::BinOp::Mul => Ok(BinOp::Mul),
586 rustc_mir::BinOp::Div => Ok(BinOp::Div),
587 rustc_mir::BinOp::Rem => Ok(BinOp::Rem),
588 rustc_mir::BinOp::BitAnd => Ok(BinOp::BitAnd),
589 rustc_mir::BinOp::BitOr => Ok(BinOp::BitOr),
590 rustc_mir::BinOp::BitXor => Ok(BinOp::BitXor),
591 rustc_mir::BinOp::Shl => Ok(BinOp::Shl),
592 rustc_mir::BinOp::Shr => Ok(BinOp::Shr),
593 rustc_mir::BinOp::AddUnchecked
594 | rustc_mir::BinOp::SubUnchecked
595 | rustc_mir::BinOp::MulUnchecked
596 | rustc_mir::BinOp::ShlUnchecked
597 | rustc_mir::BinOp::ShrUnchecked
598 | rustc_mir::BinOp::AddWithOverflow
599 | rustc_mir::BinOp::SubWithOverflow
600 | rustc_mir::BinOp::MulWithOverflow
601 | rustc_mir::BinOp::Cmp
602 | rustc_mir::BinOp::Offset => {
603 Err(UnsupportedReason::new(format!("unsupported binary op `{bin_op:?}`")))
604 }
605 }
606 }
607
608 fn lower_null_op(&self, null_op: rustc_mir::NullOp) -> Result<NullOp, UnsupportedReason> {
609 match null_op {
610 rustc_mir::NullOp::SizeOf => Ok(NullOp::SizeOf),
611 rustc_mir::NullOp::AlignOf => Ok(NullOp::AlignOf),
612 rustc_mir::NullOp::OffsetOf(_)
613 | rustc_mir::NullOp::UbChecks
614 | rustc_mir::NullOp::ContractChecks => {
615 Err(UnsupportedReason::new(format!("unsupported nullary op `{null_op:?}`")))
616 }
617 }
618 }
619
620 fn lower_operand(&self, op: &rustc_mir::Operand<'tcx>) -> Result<Operand, UnsupportedReason> {
621 match op {
622 rustc_mir::Operand::Copy(place) => Ok(Operand::Copy(lower_place(self.tcx, place)?)),
623 rustc_mir::Operand::Move(place) => Ok(Operand::Move(lower_place(self.tcx, place)?)),
624 rustc_mir::Operand::Constant(c) => Ok(Operand::Constant(self.lower_constant(c)?)),
625 }
626 }
627
628 fn lower_constant(
629 &self,
630 constant: &rustc_mir::ConstOperand<'tcx>,
631 ) -> Result<Constant, UnsupportedReason> {
632 use rustc_middle::ty::TyKind;
633 use rustc_mir::{Const, interpret::Scalar};
634 let tcx = self.tcx;
635 let const_ = constant.const_;
636 let ty = constant.ty();
637 match (constant.const_, ty.kind()) {
638 (Const::Val(ConstValue::Scalar(Scalar::Int(scalar)), ty), _) => {
639 self.scalar_int_to_constant(scalar, ty)
640 }
641 (Const::Val(ct @ ConstValue::Slice { .. }, _), TyKind::Ref(_, ref_ty, _))
642 if ref_ty.is_str() =>
643 {
644 if let Some(data) = ct.try_get_slice_bytes_for_diagnostics(tcx) {
645 let str = String::from_utf8_lossy(data);
646 Some(Constant::Str(Symbol::intern(&str)))
647 } else {
648 None
649 }
650 }
651 (Const::Ty(ty, c), _) => {
652 match c.kind() {
653 rustc_ty::ConstKind::Value(value) => {
654 match &*value.valtree {
655 rustc_ty::ValTreeKind::Leaf(scalar_int) => {
656 self.scalar_int_to_constant(*scalar_int, value.ty)
657 }
658 rustc_ty::ValTreeKind::Branch(_) => None,
659 }
660 }
661 rustc_ty::ConstKind::Param(param_const) => {
662 let ty = ty.lower(tcx)?;
663 Some(Constant::Param(param_const, ty))
664 }
665 _ => None,
666 }
667 }
668 (_, TyKind::Tuple(tys)) if tys.is_empty() => return Ok(Constant::Unit),
669
670 (_, _) => {
671 if let Const::Unevaluated(uneval, _) = const_ {
672 if uneval.args.is_empty() {
673 return Ok(Constant::Unevaluated(ty.lower(tcx)?, uneval.def));
674 }
675 let typing_env = self.selcx.infcx.typing_env(self.param_env);
678 let const_ = constant
679 .const_
680 .eval(tcx, typing_env, rustc_span::DUMMY_SP)
681 .map(|val| Const::Val(val, constant.const_.ty()))
682 .unwrap_or(constant.const_);
683 if let Const::Val(ConstValue::Scalar(Scalar::Int(scalar)), ty) = const_
684 && let Some(constant) = self.scalar_int_to_constant(scalar, ty)
685 {
686 return Ok(constant);
687 }
688 }
689 Some(Constant::Opaque(ty.lower(tcx)?))
690 }
691 }
692 .ok_or_else(|| UnsupportedReason::new(format!("unsupported constant `{constant:?}`")))
693 }
694
695 fn scalar_int_to_constant(
698 &self,
699 scalar: rustc_ty::ScalarInt,
700 ty: rustc_middle::ty::Ty<'tcx>,
701 ) -> Option<Constant> {
702 use rustc_middle::ty::TyKind;
703 let kind = ty.kind();
704 match kind {
705 TyKind::Int(int_ty) => {
706 Some(Constant::Int(scalar_to_int(self.tcx, scalar, *int_ty), *int_ty))
707 }
708 TyKind::Uint(uint_ty) => {
709 Some(Constant::Uint(scalar_to_uint(self.tcx, scalar, *uint_ty), *uint_ty))
710 }
711 TyKind::Float(float_ty) => {
712 Some(Constant::Float(scalar_to_bits(self.tcx, scalar, ty).unwrap(), *float_ty))
713 }
714 TyKind::Char => Some(Constant::Char(scalar.try_into().unwrap())),
715 TyKind::Bool => Some(Constant::Bool(scalar.try_to_bool().unwrap())),
716 TyKind::Tuple(tys) if tys.is_empty() => Some(Constant::Unit),
717 _ => {
718 match ty.lower(self.tcx) {
719 Ok(ty) => Some(Constant::Opaque(ty)),
720 Err(_) => None,
721 }
722 }
723 }
724 }
725
726 fn lower_assert_msg(&self, msg: &rustc_mir::AssertMessage) -> Option<AssertKind> {
727 use rustc_mir::AssertKind::*;
728 match msg {
729 BoundsCheck { .. } => Some(AssertKind::BoundsCheck),
730 DivisionByZero(_) => Some(AssertKind::DivisionByZero),
731 RemainderByZero(_) => Some(AssertKind::RemainderByZero),
732 Overflow(bin_op, ..) => Some(AssertKind::Overflow(self.lower_bin_op(*bin_op).ok()?)),
733 _ => None,
734 }
735 }
736}
737
738pub fn lower_place<'tcx>(
739 _tcx: TyCtxt<'tcx>,
740 place: &rustc_mir::Place<'tcx>,
741) -> Result<Place, UnsupportedReason> {
742 let mut projection = vec![];
743 for elem in place.projection {
744 match elem {
745 rustc_mir::PlaceElem::Deref => projection.push(PlaceElem::Deref),
746 rustc_mir::PlaceElem::Field(field, _) => projection.push(PlaceElem::Field(field)),
747 rustc_mir::PlaceElem::Downcast(name, idx) => {
748 projection.push(PlaceElem::Downcast(name, idx));
749 }
750 rustc_mir::PlaceElem::Index(v) => projection.push(PlaceElem::Index(v)),
751 rustc_mir::ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
752 projection.push(PlaceElem::ConstantIndex { offset, min_length, from_end });
753 }
754 _ => {
755 return Err(UnsupportedReason::new(format!("unsupported place `{place:?}`")));
756 }
757 }
758 }
759 Ok(Place { local: place.local, projection })
760}
761
762impl<'tcx> Lower<'tcx> for rustc_ty::FnSig<'tcx> {
763 type R = Result<FnSig, UnsupportedReason>;
764
765 fn lower(self, tcx: TyCtxt<'tcx>) -> Self::R {
766 let inputs_and_output = List::from_vec(
767 self.inputs_and_output
768 .iter()
769 .map(|ty| ty.lower(tcx))
770 .try_collect()?,
771 );
772 Ok(FnSig { safety: self.safety, abi: self.abi, inputs_and_output })
773 }
774}
775
776impl<'tcx> Lower<'tcx> for &'tcx rustc_ty::List<rustc_ty::BoundVariableKind> {
777 type R = Result<List<BoundVariableKind>, UnsupportedReason>;
778
779 fn lower(self, _tcx: TyCtxt<'tcx>) -> Self::R {
780 let mut vars = vec![];
781 for var in self {
782 match var {
783 rustc_ty::BoundVariableKind::Region(kind) => {
784 vars.push(BoundVariableKind::Region(kind));
785 }
786 _ => {
787 return Err(UnsupportedReason {
788 descr: format!("unsupported bound variable {var:?}"),
789 });
790 }
791 }
792 }
793 Ok(List::from_vec(vars))
794 }
795}
796
797impl<'tcx> Lower<'tcx> for rustc_ty::ValTree<'tcx> {
798 type R = crate::ty::ValTree;
799
800 fn lower(self, _tcx: TyCtxt<'tcx>) -> Self::R {
801 match &*self {
802 rustc_ty::ValTreeKind::Leaf(scalar_int) => crate::ty::ValTree::Leaf(*scalar_int),
803 rustc_ty::ValTreeKind::Branch(trees) => {
804 let trees = trees.iter().map(|tree| tree.lower(_tcx)).collect();
805 crate::ty::ValTree::Branch(trees)
806 }
807 }
808 }
809}
810
811impl<'tcx> Lower<'tcx> for rustc_ty::Const<'tcx> {
812 type R = Result<Const, UnsupportedReason>;
813
814 fn lower(self, tcx: TyCtxt<'tcx>) -> Self::R {
815 let kind = match self.kind() {
816 rustc_type_ir::ConstKind::Param(param_const) => {
817 ConstKind::Param(ParamConst { name: param_const.name, index: param_const.index })
818 }
819 rustc_type_ir::ConstKind::Value(value) => {
820 ConstKind::Value(value.ty.lower(tcx)?, value.valtree.lower(tcx))
821 }
822 rustc_type_ir::ConstKind::Unevaluated(c) => {
823 let args = c.args.lower(tcx)?;
825 ConstKind::Unevaluated(UnevaluatedConst { def: c.def, args })
826 }
827 _ => return Err(UnsupportedReason::new(format!("unsupported const {self:?}"))),
828 };
829 Ok(Const { kind })
830 }
831}
832
833impl<'tcx, T, S> Lower<'tcx> for rustc_ty::Binder<'tcx, T>
834where
835 T: Lower<'tcx, R = Result<S, UnsupportedReason>>,
836{
837 type R = Result<Binder<S>, UnsupportedReason>;
838
839 fn lower(self, tcx: TyCtxt<'tcx>) -> Self::R {
840 let vars = self.bound_vars().lower(tcx)?;
841 Ok(Binder::bind_with_vars(self.skip_binder().lower(tcx)?, vars))
842 }
843}
844
845impl<'tcx> Lower<'tcx> for rustc_ty::Ty<'tcx> {
846 type R = Result<Ty, UnsupportedReason>;
847
848 fn lower(self, tcx: TyCtxt<'tcx>) -> Self::R {
849 match self.kind() {
850 rustc_ty::Ref(region, ty, mutability) => {
851 Ok(Ty::mk_ref(region.lower(tcx)?, ty.lower(tcx)?, *mutability))
852 }
853 rustc_ty::Bool => Ok(Ty::mk_bool()),
854 rustc_ty::Int(int_ty) => Ok(Ty::mk_int(*int_ty)),
855 rustc_ty::Uint(uint_ty) => Ok(Ty::mk_uint(*uint_ty)),
856 rustc_ty::Float(float_ty) => Ok(Ty::mk_float(*float_ty)),
857 rustc_ty::Param(param_ty) => Ok(Ty::mk_param(*param_ty)),
858 rustc_ty::Adt(adt_def, args) => {
859 let args = args.lower(tcx)?;
860 Ok(Ty::mk_adt(adt_def.lower(tcx), args))
861 }
862 rustc_ty::FnDef(def_id, args) => {
863 let args = args.lower(tcx)?;
864 Ok(Ty::mk_fn_def(*def_id, args))
865 }
866 rustc_ty::Never => Ok(Ty::mk_never()),
867 rustc_ty::Str => Ok(Ty::mk_str()),
868 rustc_ty::Char => Ok(Ty::mk_char()),
869 rustc_ty::Tuple(tys) => {
870 let tys = List::from_vec(tys.iter().map(|ty| ty.lower(tcx)).try_collect()?);
871 Ok(Ty::mk_tuple(tys))
872 }
873 rustc_ty::Array(ty, len) => Ok(Ty::mk_array(ty.lower(tcx)?, len.lower(tcx)?)),
874 rustc_ty::Slice(ty) => Ok(Ty::mk_slice(ty.lower(tcx)?)),
875 rustc_ty::RawPtr(ty, mutbl) => {
876 let ty = ty.lower(tcx)?;
877 Ok(Ty::mk_raw_ptr(ty, *mutbl))
878 }
879 rustc_ty::FnPtr(fn_sig_tys, header) => {
880 let fn_sig = fnptr_as_fnsig(fn_sig_tys, header).lower(tcx)?;
881 Ok(Ty::mk_fn_ptr(fn_sig))
882 }
883 rustc_ty::Closure(did, args) => {
884 let args = args.lower(tcx)?;
885 Ok(Ty::mk_closure(*did, args))
886 }
887
888 rustc_ty::Alias(kind, alias_ty) => {
889 let kind = kind.lower(tcx)?;
890 let args = alias_ty.args.lower(tcx)?;
891 Ok(Ty::mk_alias(kind, alias_ty.def_id, args))
892 }
893 rustc_ty::Coroutine(did, args) => {
894 let args = args.lower(tcx)?;
895 Ok(Ty::mk_coroutine(*did, args))
896 }
897 rustc_ty::CoroutineWitness(did, args) => {
898 let args = args.lower(tcx)?;
899 Ok(Ty::mk_generator_witness(*did, args))
900 }
901 rustc_ty::Dynamic(predicates, region, rustc_ty::DynKind::Dyn) => {
902 let region = region.lower(tcx)?;
903
904 let exi_preds = List::from_vec(
905 predicates
906 .iter()
907 .map(|pred| pred.lower(tcx))
908 .try_collect()?,
909 );
910
911 Ok(Ty::mk_dynamic(exi_preds, region))
912 }
913 rustc_ty::Foreign(def_id) => Ok(Ty::mk_foreign(*def_id)),
914 _ => Err(UnsupportedReason::new(format!("unsupported type `{self:?}`"))),
915 }
916 }
917}
918
919fn fnptr_as_fnsig<'tcx>(
920 fn_sig_tys: &'tcx rustc_ty::Binder<'tcx, rustc_ty::FnSigTys<TyCtxt<'tcx>>>,
921 header: &'tcx rustc_ty::FnHeader<TyCtxt<'tcx>>,
922) -> rustc_ty::Binder<'tcx, rustc_ty::FnSig<'tcx>> {
923 fn_sig_tys.map_bound(|fn_sig_tys| {
924 rustc_ty::FnSig {
925 inputs_and_output: fn_sig_tys.inputs_and_output,
926 c_variadic: header.c_variadic,
927 safety: header.safety,
928 abi: header.abi,
929 }
930 })
931}
932
933impl<'tcx> Lower<'tcx> for rustc_ty::AliasTyKind {
934 type R = Result<AliasKind, UnsupportedReason>;
935
936 fn lower(self, _tcx: TyCtxt<'tcx>) -> Self::R {
937 match self {
938 rustc_type_ir::AliasTyKind::Projection => Ok(AliasKind::Projection),
939 rustc_type_ir::AliasTyKind::Opaque => Ok(AliasKind::Opaque),
940 _ => Err(UnsupportedReason::new(format!("unsupported alias kind `{self:?}`"))),
941 }
942 }
943}
944
945impl<'tcx> Lower<'tcx> for rustc_ty::AdtDef<'tcx> {
946 type R = AdtDef;
947
948 fn lower(self, tcx: TyCtxt<'tcx>) -> Self::R {
949 AdtDef::new(AdtDefData::new(
950 tcx,
951 self,
952 self.variants()
953 .iter()
954 .map(|variant| {
955 VariantDef {
956 def_id: variant.def_id,
957 name: variant.name,
958 fields: variant
959 .fields
960 .iter()
961 .map(|f| FieldDef { did: f.did, name: f.name })
962 .collect(),
963 }
964 })
965 .collect(),
966 ))
967 }
968}
969
970impl<'tcx> Lower<'tcx> for rustc_ty::ExistentialPredicate<'tcx> {
971 type R = Result<ExistentialPredicate, UnsupportedReason>;
972
973 fn lower(self, tcx: TyCtxt<'tcx>) -> Self::R {
974 match self {
975 rustc_type_ir::ExistentialPredicate::Trait(trait_ref) => {
976 Ok(ExistentialPredicate::Trait(ExistentialTraitRef {
977 def_id: trait_ref.def_id,
978 args: trait_ref.args.lower(tcx)?,
979 }))
980 }
981 rustc_type_ir::ExistentialPredicate::Projection(proj) => {
982 let Some(term) = proj.term.as_type() else {
983 return Err(UnsupportedReason::new(format!(
984 "unsupported existential predicate `{self:?}`"
985 )));
986 };
987 Ok(ExistentialPredicate::Projection(ExistentialProjection {
988 def_id: proj.def_id,
989 args: proj.args.lower(tcx)?,
990 term: term.lower(tcx)?,
991 }))
992 }
993 rustc_type_ir::ExistentialPredicate::AutoTrait(def_id) => {
994 Ok(ExistentialPredicate::AutoTrait(def_id))
995 }
996 }
997 }
998}
999
1000impl<'tcx> Lower<'tcx> for rustc_middle::ty::GenericArgsRef<'tcx> {
1001 type R = Result<GenericArgs, UnsupportedReason>;
1002
1003 fn lower(self, tcx: TyCtxt<'tcx>) -> Self::R {
1004 Ok(List::from_vec(self.iter().map(|arg| arg.lower(tcx)).try_collect()?))
1005 }
1006}
1007
1008impl<'tcx> Lower<'tcx> for rustc_middle::ty::GenericArg<'tcx> {
1009 type R = Result<GenericArg, UnsupportedReason>;
1010
1011 fn lower(self, tcx: TyCtxt<'tcx>) -> Self::R {
1012 match self.kind() {
1013 GenericArgKind::Type(ty) => Ok(GenericArg::Ty(ty.lower(tcx)?)),
1014 GenericArgKind::Lifetime(region) => Ok(GenericArg::Lifetime(region.lower(tcx)?)),
1015 GenericArgKind::Const(c) => Ok(GenericArg::Const(c.lower(tcx)?)),
1016 }
1017 }
1018}
1019
1020impl<'tcx> Lower<'tcx> for rustc_middle::ty::Region<'tcx> {
1021 type R = Result<Region, UnsupportedReason>;
1022
1023 fn lower(self, _tcx: TyCtxt<'tcx>) -> Self::R {
1024 use rustc_middle::ty::RegionKind;
1025 match self.kind() {
1026 RegionKind::ReVar(rvid) => Ok(Region::ReVar(rvid)),
1027 RegionKind::ReBound(debruijn, bregion) => {
1028 Ok(Region::ReBound(
1029 debruijn,
1030 Ok(BoundRegion { kind: bregion.kind, var: bregion.var })?,
1031 ))
1032 }
1033 RegionKind::ReEarlyParam(bregion) => Ok(Region::ReEarlyParam(bregion)),
1034 RegionKind::ReStatic => Ok(Region::ReStatic),
1035 RegionKind::ReErased => Ok(Region::ReErased),
1036 RegionKind::ReLateParam(_) | RegionKind::RePlaceholder(_) | RegionKind::ReError(_) => {
1037 Err(UnsupportedReason::new(format!("unsupported region `{self:?}`")))
1038 }
1039 }
1040 }
1041}
1042
1043impl<'tcx> Lower<'tcx> for &'tcx rustc_middle::ty::Generics {
1044 type R = Generics<'tcx>;
1045
1046 fn lower(self, tcx: TyCtxt<'tcx>) -> Self::R {
1047 let params = List::from_vec(
1048 self.own_params
1049 .iter()
1050 .map(|param| param.lower(tcx))
1051 .collect(),
1052 );
1053 Generics { params, orig: self }
1054 }
1055}
1056
1057impl<'tcx> Lower<'tcx> for &rustc_middle::ty::GenericParamDef {
1058 type R = GenericParamDef;
1059
1060 fn lower(self, _tcx: TyCtxt<'tcx>) -> Self::R {
1061 let kind = match self.kind {
1062 rustc_ty::GenericParamDefKind::Type { has_default, .. } => {
1063 GenericParamDefKind::Type { has_default }
1064 }
1065 rustc_ty::GenericParamDefKind::Lifetime => GenericParamDefKind::Lifetime,
1066 rustc_ty::GenericParamDefKind::Const { has_default, .. } => {
1067 GenericParamDefKind::Const { has_default }
1068 }
1069 };
1070 GenericParamDef { def_id: self.def_id, index: self.index, name: self.name, kind }
1071 }
1072}
1073
1074impl<'tcx> Lower<'tcx> for rustc_ty::GenericPredicates<'tcx> {
1075 type R = Result<GenericPredicates, UnsupportedErr>;
1076
1077 fn lower(self, tcx: TyCtxt<'tcx>) -> Self::R {
1078 let predicates = self
1079 .predicates
1080 .iter()
1081 .map(|(clause, span)| {
1082 clause
1083 .lower(tcx)
1084 .map_err(|reason| UnsupportedErr::new(reason).with_span(*span))
1085 })
1086 .try_collect()?;
1087 Ok(GenericPredicates { parent: self.parent, predicates })
1088 }
1089}
1090
1091impl<'tcx> Lower<'tcx> for rustc_ty::Clauses<'tcx> {
1092 type R = Result<List<Clause>, UnsupportedErr>;
1093
1094 fn lower(self, tcx: TyCtxt<'tcx>) -> Self::R {
1095 self.iter()
1096 .map(|clause| clause.lower(tcx).map_err(UnsupportedErr::new))
1097 .try_collect()
1098 }
1099}
1100
1101impl<'tcx> Lower<'tcx> for rustc_ty::ClauseKind<'tcx> {
1102 type R = Result<ClauseKind, UnsupportedReason>;
1103
1104 fn lower(self, tcx: TyCtxt<'tcx>) -> Self::R {
1105 let kind = match self {
1106 rustc_ty::ClauseKind::Trait(trait_pred) => {
1107 ClauseKind::Trait(TraitPredicate { trait_ref: trait_pred.trait_ref.lower(tcx)? })
1108 }
1109 rustc_ty::ClauseKind::Projection(proj_pred) => {
1110 let Some(term) = proj_pred.term.as_type() else {
1111 return Err(UnsupportedReason::new(format!(
1112 "unsupported projection predicate `{proj_pred:?}`"
1113 )));
1114 };
1115 let proj_ty = proj_pred.projection_term;
1116 let args = proj_ty.args.lower(tcx)?;
1117
1118 let projection_ty = AliasTy { args, def_id: proj_ty.def_id };
1119 let term = term.lower(tcx)?;
1120 ClauseKind::Projection(ProjectionPredicate { projection_ty, term })
1121 }
1122 rustc_ty::ClauseKind::RegionOutlives(outlives) => {
1123 ClauseKind::RegionOutlives(outlives.lower(tcx)?)
1124 }
1125 rustc_ty::ClauseKind::TypeOutlives(outlives) => {
1126 ClauseKind::TypeOutlives(outlives.lower(tcx)?)
1127 }
1128 rustc_ty::ClauseKind::ConstArgHasType(const_, ty) => {
1129 ClauseKind::ConstArgHasType(const_.lower(tcx)?, ty.lower(tcx)?)
1130 }
1131 _ => {
1132 return Err(UnsupportedReason::new(format!("unsupported clause kind `{self:?}`")));
1133 }
1134 };
1135 Ok(kind)
1136 }
1137}
1138
1139impl<'tcx> Lower<'tcx> for rustc_ty::Clause<'tcx> {
1140 type R = Result<Clause, UnsupportedReason>;
1141
1142 fn lower(self, tcx: TyCtxt<'tcx>) -> Self::R {
1143 Ok(Clause::new(self.kind().lower(tcx)?))
1144 }
1145}
1146
1147impl<'tcx> Lower<'tcx> for rustc_ty::TraitRef<'tcx> {
1148 type R = Result<TraitRef, UnsupportedReason>;
1149
1150 fn lower(self, tcx: TyCtxt<'tcx>) -> Self::R {
1151 Ok(TraitRef { def_id: self.def_id, args: self.args.lower(tcx)? })
1152 }
1153}
1154
1155impl<'tcx> Lower<'tcx> for rustc_ty::TypeOutlivesPredicate<'tcx> {
1156 type R = Result<TypeOutlivesPredicate, UnsupportedReason>;
1157
1158 fn lower(self, tcx: TyCtxt<'tcx>) -> Self::R {
1159 Ok(OutlivesPredicate(self.0.lower(tcx)?, self.1.lower(tcx)?))
1160 }
1161}
1162
1163impl<'tcx> Lower<'tcx> for rustc_ty::RegionOutlivesPredicate<'tcx> {
1164 type R = Result<RegionOutlivesPredicate, UnsupportedReason>;
1165
1166 fn lower(self, tcx: TyCtxt<'tcx>) -> Self::R {
1167 Ok(OutlivesPredicate(self.0.lower(tcx)?, self.1.lower(tcx)?))
1168 }
1169}
1170
1171mod errors {
1172 use std::path::PathBuf;
1173
1174 use flux_errors::E0999;
1175 use flux_macros::Diagnostic;
1176 use rustc_middle::mir as rustc_mir;
1177 use rustc_span::Span;
1178
1179 use super::UnsupportedReason;
1180
1181 #[derive(Diagnostic)]
1182 #[diag(rustc_bridge_unsupported_local_decl, code = E0999)]
1183 pub(super) struct UnsupportedLocalDecl<'tcx> {
1184 #[primary_span]
1185 #[label]
1186 span: Span,
1187 ty: rustc_middle::ty::Ty<'tcx>,
1188 }
1189
1190 impl<'tcx> UnsupportedLocalDecl<'tcx> {
1191 pub(super) fn new(
1192 local_decl: &rustc_mir::LocalDecl<'tcx>,
1193 _err: UnsupportedReason,
1194 ) -> Self {
1195 Self { span: local_decl.source_info.span, ty: local_decl.ty }
1196 }
1197 }
1198
1199 #[derive(Diagnostic)]
1200 #[diag(rustc_bridge_unsupported_mir, code = E0999)]
1201 #[note]
1202 pub(super) struct UnsupportedMir {
1203 #[primary_span]
1204 span: Span,
1205 kind: &'static str,
1206 reason: UnsupportedReason,
1207 }
1208
1209 impl rustc_errors::IntoDiagArg for UnsupportedReason {
1210 fn into_diag_arg(self, _path: &mut Option<PathBuf>) -> rustc_errors::DiagArgValue {
1211 rustc_errors::DiagArgValue::Str(std::borrow::Cow::Owned(self.descr))
1212 }
1213 }
1214
1215 impl UnsupportedMir {
1216 pub(super) fn new(span: Span, kind: &'static str, reason: UnsupportedReason) -> Self {
1217 Self { span, kind, reason }
1218 }
1219
1220 pub(super) fn terminator(span: Span, reason: UnsupportedReason) -> Self {
1221 Self { span, kind: "terminator", reason }
1222 }
1223
1224 pub(super) fn statement(span: Span, reason: UnsupportedReason) -> Self {
1225 Self { span, kind: "statement", reason }
1226 }
1227 }
1228
1229 impl<'a, 'tcx> From<&'a rustc_mir::Terminator<'tcx>> for UnsupportedMir {
1230 fn from(terminator: &'a rustc_mir::Terminator<'tcx>) -> Self {
1231 Self::terminator(
1232 terminator.source_info.span,
1233 UnsupportedReason::new(format!("{terminator:?}",)),
1234 )
1235 }
1236 }
1237
1238 impl<'a, 'tcx> From<&'a rustc_mir::Statement<'tcx>> for UnsupportedMir {
1239 fn from(statement: &'a rustc_mir::Statement<'tcx>) -> Self {
1240 Self::statement(
1241 statement.source_info.span,
1242 UnsupportedReason::new(format!("{statement:?}")),
1243 )
1244 }
1245 }
1246}