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