1use flux_common::{bug, iter::IterExt, result::ErrorEmitter as _};
4use flux_errors::ErrorGuaranteed;
5use flux_middle::{
6 def_id::MaybeExternId,
7 fhir::{self, FhirId, FluxOwnerId},
8 try_alloc_slice,
9};
10use rustc_hir::{
11 self as hir, FnHeader,
12 def_id::{DefId, LocalDefId},
13};
14use rustc_span::Span;
15
16use super::{DesugarCtxt, RustItemCtxt};
17
18type Result<T = ()> = std::result::Result<T, ErrorGuaranteed>;
19
20impl<'genv> RustItemCtxt<'_, 'genv, '_> {
21 pub fn lift_generics(&mut self) -> fhir::Generics<'genv> {
22 let generics = self.genv.tcx().hir_get_generics(self.local_id()).unwrap();
23 self.lift_generics_inner(generics)
24 }
25
26 pub fn lift_generic_param(&mut self, param: &hir::GenericParam) -> fhir::GenericParam<'genv> {
27 let kind = match param.kind {
28 hir::GenericParamKind::Lifetime { .. } => fhir::GenericParamKind::Lifetime,
29 hir::GenericParamKind::Type { default, .. } => {
30 fhir::GenericParamKind::Type { default: default.map(|ty| self.lift_ty(ty)) }
31 }
32 hir::GenericParamKind::Const { ty, .. } => {
33 let ty = self.lift_ty(ty);
34 fhir::GenericParamKind::Const { ty }
35 }
36 };
37 fhir::GenericParam {
38 def_id: self.genv.maybe_extern_id(param.def_id),
39 name: param.name,
40 kind,
41 }
42 }
43
44 fn lift_generics_inner(&mut self, generics: &hir::Generics) -> fhir::Generics<'genv> {
45 let params = self.genv.alloc_slice_fill_iter(
46 generics
47 .params
48 .iter()
49 .map(|param| self.lift_generic_param(param)),
50 );
51
52 fhir::Generics { params, refinement_params: &[], predicates: None }
53 }
54
55 fn lift_generic_bound(
56 &mut self,
57 bound: &hir::GenericBound,
58 ) -> Result<fhir::GenericBound<'genv>> {
59 match bound {
60 hir::GenericBound::Trait(poly_trait_ref) => {
61 Ok(fhir::GenericBound::Trait(self.lift_poly_trait_ref(*poly_trait_ref)?))
62 }
63 hir::GenericBound::Outlives(lft) => {
64 let lft = self.lift_lifetime(lft);
65 Ok(fhir::GenericBound::Outlives(lft))
66 }
67 _ => Err(self.emit_unsupported(&format!("unsupported generic bound: `{bound:?}`"))),
68 }
69 }
70
71 fn lift_poly_trait_ref(
72 &mut self,
73 poly_trait_ref: hir::PolyTraitRef,
74 ) -> Result<fhir::PolyTraitRef<'genv>> {
75 let modifiers = match poly_trait_ref.modifiers {
76 rustc_hir::TraitBoundModifiers {
77 constness: rustc_hir::BoundConstness::Never,
78 polarity: rustc_hir::BoundPolarity::Positive,
79 } => fhir::TraitBoundModifier::None,
80 rustc_hir::TraitBoundModifiers {
81 constness: rustc_hir::BoundConstness::Never,
82 polarity: rustc_hir::BoundPolarity::Maybe(_),
83 } => fhir::TraitBoundModifier::Maybe,
84 _ => {
85 return Err(self.emit_unsupported(&format!(
86 "unsupported trait modifiers: `{:?}`",
87 poly_trait_ref.modifiers,
88 )));
89 }
90 };
91 let bound_generic_params = self.genv.alloc_slice_fill_iter(
92 poly_trait_ref
93 .bound_generic_params
94 .iter()
95 .map(|param| self.lift_generic_param(param)),
96 );
97 let trait_ref = self.lift_path(poly_trait_ref.trait_ref.path)?;
98 Ok(fhir::PolyTraitRef {
99 bound_generic_params,
100 refine_params: &[],
101 modifiers,
102 trait_ref,
103 span: poly_trait_ref.span,
104 })
105 }
106
107 fn lift_opaque_ty(&mut self, opaque_ty: &hir::OpaqueTy) -> Result<fhir::OpaqueTy<'genv>> {
108 let bounds =
109 try_alloc_slice!(self.genv, &opaque_ty.bounds, |bound| self.lift_generic_bound(bound))?;
110
111 Ok(fhir::OpaqueTy { def_id: MaybeExternId::Local(opaque_ty.def_id), bounds })
112 }
113
114 pub fn lift_fn_header(&mut self) -> FnHeader {
115 let hir_id = self.genv.tcx().local_def_id_to_hir_id(self.local_id());
116 self.genv
117 .tcx()
118 .hir_fn_sig_by_hir_id(hir_id)
119 .expect("item does not have a `FnDecl`")
120 .header
121 }
122
123 pub fn lift_fn_decl(&mut self) -> fhir::FnDecl<'genv> {
124 let hir_id = self.genv.tcx().local_def_id_to_hir_id(self.local_id());
125 let fn_sig = self
126 .genv
127 .tcx()
128 .hir_fn_sig_by_hir_id(hir_id)
129 .expect("item does not have a `FnDecl`");
130
131 self.lift_fn_decl_inner(fn_sig.span, fn_sig.decl)
132 }
133
134 fn lift_fn_decl_inner(&mut self, span: Span, decl: &hir::FnDecl) -> fhir::FnDecl<'genv> {
135 let inputs = self
136 .genv
137 .alloc_slice_fill_iter(decl.inputs.iter().map(|ty| self.lift_ty(ty)));
138
139 let output =
140 fhir::FnOutput { params: &[], ensures: &[], ret: self.lift_fn_ret_ty(&decl.output) };
141
142 fhir::FnDecl { requires: &[], inputs, output, span, lifted: true }
143 }
144
145 fn lift_fn_ret_ty(&mut self, ret_ty: &hir::FnRetTy) -> fhir::Ty<'genv> {
146 match ret_ty {
147 hir::FnRetTy::DefaultReturn(_) => {
148 let kind = fhir::TyKind::Tuple(&[]);
149 fhir::Ty { kind, span: ret_ty.span() }
150 }
151 hir::FnRetTy::Return(ty) => self.lift_ty(ty),
152 }
153 }
154
155 pub fn lift_type_alias(&mut self) -> fhir::Item<'genv> {
156 let item = self.genv.tcx().hir_expect_item(self.local_id());
157 let hir::ItemKind::TyAlias(_, _, ty) = item.kind else {
158 bug!("expected type alias");
159 };
160
161 let generics = self.lift_generics();
162 let ty = self.lift_ty(ty);
163 let ty_alias =
164 self.genv
165 .alloc(fhir::TyAlias { index: None, ty, span: item.span, lifted: true });
166
167 fhir::Item { generics, kind: fhir::ItemKind::TyAlias(ty_alias), owner_id: self.owner }
168 }
169
170 pub fn lift_field_def(&mut self, field_def: &hir::FieldDef) -> fhir::FieldDef<'genv> {
171 let ty = self.lift_ty(field_def.ty);
172 fhir::FieldDef { ty, lifted: true }
173 }
174
175 pub fn lift_enum_variant(&mut self, variant: &hir::Variant) -> fhir::VariantDef<'genv> {
176 let item = self.genv.tcx().hir_expect_item(self.local_id());
177 let hir::ItemKind::Enum(_, generics, _) = &item.kind else { bug!("expected an enum") };
178
179 let fields = self.genv.alloc_slice_fill_iter(
180 variant
181 .data
182 .fields()
183 .iter()
184 .map(|field| self.lift_field_def(field)),
185 );
186
187 let ret = self.lift_variant_ret_inner(generics);
188
189 fhir::VariantDef {
190 def_id: variant.def_id,
191 params: &[],
192 fields,
193 ret,
194 span: variant.span,
195 lifted: true,
196 }
197 }
198
199 pub fn lift_variant_ret(&mut self) -> fhir::VariantRet<'genv> {
200 let item = self.genv.tcx().hir_expect_item(self.local_id());
201 let hir::ItemKind::Enum(_, generics, _) = &item.kind else { bug!("expected an enum") };
202 self.lift_variant_ret_inner(generics)
203 }
204
205 fn lift_variant_ret_inner(&mut self, generics: &hir::Generics) -> fhir::VariantRet<'genv> {
206 let kind = fhir::ExprKind::Record(&[]);
207 fhir::VariantRet {
208 enum_id: self.owner.resolved_id(),
209 idx: fhir::Expr {
210 kind,
211 fhir_id: self.next_fhir_id(),
212 span: generics.span.shrink_to_hi(),
213 },
214 }
215 }
216
217 pub fn lift_ty(&mut self, ty: &hir::Ty) -> fhir::Ty<'genv> {
218 let kind = match ty.kind {
219 hir::TyKind::Slice(ty) => {
220 let ty = self.lift_ty(ty);
221 let kind = fhir::BaseTyKind::Slice(self.genv.alloc(ty));
222 let bty = fhir::BaseTy { kind, fhir_id: self.next_fhir_id(), span: ty.span };
223 return fhir::Ty { kind: fhir::TyKind::BaseTy(bty), span: ty.span };
224 }
225 hir::TyKind::Array(ty, len) => {
226 let ty = self.lift_ty(ty);
227 fhir::TyKind::Array(self.genv.alloc(ty), self.lift_const_arg(len))
228 }
229 hir::TyKind::Ref(lft, mut_ty) => {
230 fhir::TyKind::Ref(self.lift_lifetime(lft), self.lift_mut_ty(mut_ty))
231 }
232 hir::TyKind::FnPtr(fn_ptr) => {
233 let bare_fn = self.lift_bare_fn(ty.span, fn_ptr);
234 fhir::TyKind::BareFn(self.genv.alloc(bare_fn))
235 }
236 hir::TyKind::Never => fhir::TyKind::Never,
237 hir::TyKind::Tup(tys) => {
238 let tys = self
239 .genv
240 .alloc_slice_fill_iter(tys.iter().map(|ty| self.lift_ty(ty)));
241 fhir::TyKind::Tuple(tys)
242 }
243 hir::TyKind::Path(qpath) => {
244 match self.lift_qpath(qpath) {
245 Ok(qpath) => {
246 let bty = fhir::BaseTy::from_qpath(qpath, self.next_fhir_id());
247 fhir::TyKind::BaseTy(bty)
248 }
249 Err(err) => fhir::TyKind::Err(err),
250 }
251 }
252 hir::TyKind::Ptr(mut_ty) => {
253 let ty = self.lift_ty(mut_ty.ty);
254 fhir::TyKind::RawPtr(self.genv.alloc(ty), mut_ty.mutbl)
255 }
256 hir::TyKind::OpaqueDef(opaque_ty) => {
257 match self.lift_opaque_ty(opaque_ty) {
258 Ok(opaque_ty) => {
259 let opaque_ty = self.insert_opaque_ty(opaque_ty);
260 fhir::TyKind::OpaqueDef(opaque_ty)
261 }
262 Err(err) => fhir::TyKind::Err(err),
263 }
264 }
265 hir::TyKind::TraitObject(poly_traits, lt) => {
266 let poly_traits = try_alloc_slice!(self.genv, poly_traits, |poly_trait| {
267 if poly_trait.modifiers != hir::TraitBoundModifiers::NONE {
268 return Err(self.emit_unsupported(&format!(
269 "unsupported type: `{}`",
270 rustc_hir_pretty::ty_to_string(&self.genv.tcx(), ty)
271 )));
272 }
273 self.lift_poly_trait_ref(*poly_trait)
274 });
275 match poly_traits {
276 Ok(poly_traits) => {
277 let lft = self.lift_lifetime(lt.pointer());
278 fhir::TyKind::TraitObject(poly_traits, lft, lt.tag())
279 }
280 Err(err) => fhir::TyKind::Err(err),
281 }
282 }
283 _ => {
284 fhir::TyKind::Err(self.emit_unsupported(&format!(
285 "unsupported type: `{}`",
286 rustc_hir_pretty::ty_to_string(&self.genv.tcx(), ty)
287 )))
288 }
289 };
290 fhir::Ty { kind, span: ty.span }
291 }
292
293 fn lift_bare_fn(&mut self, span: Span, fn_ptr: &hir::FnPtrTy) -> fhir::BareFnTy<'genv> {
294 let generic_params = self.genv.alloc_slice_fill_iter(
295 fn_ptr
296 .generic_params
297 .iter()
298 .map(|param| self.lift_generic_param(param)),
299 );
300 let decl = self.lift_fn_decl_inner(span, fn_ptr.decl);
301 fhir::BareFnTy {
302 safety: fn_ptr.safety,
303 abi: fn_ptr.abi,
304 generic_params,
305 decl: self.genv.alloc(decl),
306 param_idents: self.genv.alloc_slice(fn_ptr.param_idents),
307 }
308 }
309
310 fn lift_lifetime(&self, lft: &hir::Lifetime) -> fhir::Lifetime {
311 if let Some(resolved) = self.genv.tcx().named_bound_var(lft.hir_id) {
312 fhir::Lifetime::Resolved(resolved)
313 } else {
314 self.mk_lft_hole()
315 }
316 }
317
318 fn lift_mut_ty(&mut self, mut_ty: hir::MutTy) -> fhir::MutTy<'genv> {
319 let ty = self.lift_ty(mut_ty.ty);
320 fhir::MutTy { ty: self.genv.alloc(ty), mutbl: mut_ty.mutbl }
321 }
322
323 fn lift_qpath(&mut self, qpath: hir::QPath) -> Result<fhir::QPath<'genv>> {
324 match qpath {
325 hir::QPath::Resolved(qself, path) => {
326 let qself = if let Some(ty) = qself {
327 let ty = self.lift_ty(ty);
328 Some(self.genv.alloc(ty))
329 } else {
330 None
331 };
332 let path = self.lift_path(path)?;
333 Ok(fhir::QPath::Resolved(qself, path))
334 }
335 hir::QPath::TypeRelative(qself, segment) => {
336 let qself = self.lift_ty(qself);
337 let segment = self.lift_path_segment(segment)?;
338 Ok(fhir::QPath::TypeRelative(self.genv.alloc(qself), self.genv.alloc(segment)))
339 }
340 hir::QPath::LangItem(_, _) => {
341 Err(self.emit_unsupported(&format!(
342 "unsupported type: `{}`",
343 rustc_hir_pretty::qpath_to_string(&self.genv.tcx(), &qpath)
344 )))
345 }
346 }
347 }
348
349 fn lift_path(&mut self, path: &hir::Path) -> Result<fhir::Path<'genv>> {
350 let Ok(res) = path.res.try_into() else {
351 return Err(self.emit_unsupported(&format!("unsupported res: `{:?}`", path.res)));
352 };
353 let segments =
354 try_alloc_slice!(self.genv, path.segments, |segment| self.lift_path_segment(segment))?;
355
356 Ok(fhir::Path {
357 res: self.fix_maybe_extern_id_in_res(res),
358 fhir_id: self.next_fhir_id(),
359 segments,
360 refine: &[],
361 span: path.span,
362 })
363 }
364
365 fn lift_path_segment(
366 &mut self,
367 segment: &hir::PathSegment,
368 ) -> Result<fhir::PathSegment<'genv>> {
369 let Ok(res) = segment.res.try_into() else {
370 return Err(self.emit_unsupported(&format!("unsupported res: `{:?}`", segment.res)));
371 };
372 let (args, bindings) = {
373 match segment.args {
374 Some(args) => {
375 (
376 self.lift_generic_args(args.args)?,
377 self.lift_assoc_item_constraints(args.constraints)?,
378 )
379 }
380 None => ([].as_slice(), [].as_slice()),
381 }
382 };
383
384 Ok(fhir::PathSegment { res, ident: segment.ident, args, constraints: bindings })
385 }
386
387 fn lift_generic_args(
388 &mut self,
389 args: &[hir::GenericArg<'_>],
390 ) -> Result<&'genv [fhir::GenericArg<'genv>]> {
391 try_alloc_slice!(self.genv, args, |arg| {
392 match arg {
393 hir::GenericArg::Lifetime(lft) => {
394 let lft = self.lift_lifetime(lft);
395 Ok(fhir::GenericArg::Lifetime(lft))
396 }
397 hir::GenericArg::Type(ty) => {
398 let ty = self.lift_ty(ty.as_unambig_ty());
399 Ok(fhir::GenericArg::Type(self.genv.alloc(ty)))
400 }
401 hir::GenericArg::Const(const_arg) => {
402 Ok(fhir::GenericArg::Const(self.lift_const_arg(const_arg.as_unambig_ct())))
403 }
404 hir::GenericArg::Infer(_) => {
405 Err(self.emit_unsupported("unsupported inference generic argument"))
406 }
407 }
408 })
409 }
410
411 fn lift_assoc_item_constraints(
412 &mut self,
413 constraints: &[hir::AssocItemConstraint<'_>],
414 ) -> Result<&'genv [fhir::AssocItemConstraint<'genv>]> {
415 try_alloc_slice!(self.genv, constraints, |cstr| {
416 let hir::AssocItemConstraintKind::Equality { term } = cstr.kind else {
417 return Err(self.emit_unsupported("unsupported type binding"));
418 };
419 let hir::Term::Ty(term) = term else {
420 return Err(self.emit_unsupported("unsupported type binding"));
421 };
422 let kind = fhir::AssocItemConstraintKind::Equality { term: self.lift_ty(term) };
423 Ok(fhir::AssocItemConstraint { ident: cstr.ident, kind })
424 })
425 }
426
427 fn lift_const_arg(&mut self, const_arg: &hir::ConstArg) -> fhir::ConstArg {
428 fhir::ConstArg { kind: fhir::ConstArgKind::Infer, span: const_arg.span() }
429 }
430
431 #[track_caller]
432 fn emit_unsupported(&self, note: &str) -> ErrorGuaranteed {
433 let tcx = self.genv.tcx();
434 let local_id = self.owner.local_id().def_id;
435 let span = tcx.def_span(local_id);
436 let def_kind = tcx.def_descr(local_id.to_def_id());
437 self.emit(errors::UnsupportedHir { span, def_kind, note })
438 }
439
440 fn next_fhir_id(&self) -> FhirId {
441 FhirId {
442 owner: FluxOwnerId::Rust(self.owner.local_id()),
443 local_id: self.local_id_gen.fresh(),
444 }
445 }
446
447 fn local_id(&self) -> LocalDefId {
448 self.owner.local_id().def_id
449 }
450
451 fn lift_fn_sig(&mut self, fn_sig: hir::FnSig) -> fhir::FnSig<'genv> {
452 let decl = self.lift_fn_decl_inner(fn_sig.span, fn_sig.decl);
453 fhir::FnSig {
454 header: fn_sig.header,
455 qualifiers: &[],
456 reveals: &[],
457 decl: self.genv.alloc(decl),
458 }
459 }
460
461 pub fn lift_foreign_item(
462 &mut self,
463 foreign_item: hir::ForeignItem,
464 ) -> Result<fhir::ForeignItem<'genv>> {
465 let hir::ForeignItemKind::Fn(fnsig, _, _) = foreign_item.kind else {
466 return Err(self.emit_unsupported("Static and type in extern_item are not supported."));
467 };
468
469 let lifted_fnsig = self.lift_fn_sig(fnsig);
470 let fnsig = self.genv.alloc(lifted_fnsig);
471 let lifted_generics = self.lift_generics();
472 let generics = self.genv.alloc(lifted_generics);
473 let kind = fhir::ForeignItemKind::Fn(*fnsig, generics);
474
475 Ok(fhir::ForeignItem {
476 ident: foreign_item.ident,
477 kind,
478 owner_id: MaybeExternId::Local(foreign_item.owner_id),
479 span: foreign_item.span,
480 })
481 }
482
483 fn fix_maybe_extern_id_in_res(&self, res: fhir::Res) -> fhir::Res {
485 match res {
486 fhir::Res::SelfTyParam { trait_ } => {
487 fhir::Res::SelfTyParam { trait_: self.fix_maybe_extern_id(trait_) }
488 }
489 fhir::Res::SelfTyAlias { alias_to, is_trait_impl } => {
490 fhir::Res::SelfTyAlias {
491 alias_to: self.fix_maybe_extern_id(alias_to),
492 is_trait_impl,
493 }
494 }
495 fhir::Res::Def(kind, def_id) => fhir::Res::Def(kind, self.fix_maybe_extern_id(def_id)),
496 _ => res,
497 }
498 }
499
500 #[allow(
504 clippy::disallowed_methods,
505 reason = "we are fixing the def_id to uphold the invariant on extern specs"
506 )]
507 fn fix_maybe_extern_id(&self, def_id: DefId) -> DefId {
508 if let Some(def_id) = def_id.as_local() {
509 self.genv.maybe_extern_id(def_id).resolved_id()
510 } else {
511 def_id
512 }
513 }
514}
515
516pub mod errors {
517 use flux_errors::E0999;
518 use flux_macros::Diagnostic;
519 use rustc_span::Span;
520
521 #[derive(Diagnostic)]
522 #[diag(desugar_unsupported_hir, code = E0999)]
523 #[note]
524 pub(super) struct UnsupportedHir<'a> {
525 #[primary_span]
526 #[label]
527 pub span: Span,
528 pub def_kind: &'static str,
529 pub note: &'a str,
530 }
531}