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