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