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