1#![feature(rustc_private, min_specialization, box_patterns, never_type, unwrap_infallible)]
4
5extern crate rustc_data_structures;
6extern crate rustc_errors;
7
8extern crate rustc_hir;
9extern crate rustc_hir_pretty;
10extern crate rustc_middle;
11extern crate rustc_span;
12
13use desugar::RustItemCtxt;
14use flux_common::result::{ErrorCollector, ResultExt};
15use flux_macros::fluent_messages;
16use flux_syntax::surface;
17use itertools::Itertools as _;
18use rustc_data_structures::unord::UnordMap;
19
20fluent_messages! { "../locales/en-US.ftl" }
21
22mod desugar;
23mod errors;
24pub mod resolver;
25
26use flux_middle::{
27 ResolverOutput,
28 def_id::FluxLocalDefId,
29 fhir,
30 global_env::GlobalEnv,
31 queries::{Providers, QueryErr, QueryResult},
32 query_bug,
33};
34use rustc_errors::ErrorGuaranteed;
35use rustc_hir::OwnerId;
36use rustc_span::def_id::LocalDefId;
37
38use crate::desugar::FluxItemCtxt;
39
40type Result<T = ()> = std::result::Result<T, ErrorGuaranteed>;
41
42pub fn provide(providers: &mut Providers) {
43 providers.resolve_crate = resolver::resolve_crate;
44 providers.desugar = desugar;
45 providers.fhir_attr_map = fhir_attr_map;
46 providers.fhir_crate = desugar_crate;
47}
48
49pub fn desugar<'genv>(
50 genv: GlobalEnv<'genv, '_>,
51 def_id: LocalDefId,
52) -> QueryResult<UnordMap<LocalDefId, fhir::Node<'genv>>> {
53 if genv.ignored(def_id) {
54 return Err(QueryErr::Ignored { def_id: def_id.to_def_id() });
55 }
56
57 let cx = DesugarCtxt { genv, resolver_output: genv.resolve_crate() };
58 let specs = genv.collect_specs();
59 let owner_id = OwnerId { def_id };
60 let mut nodes = UnordMap::default();
61
62 let mut opaque_tys = Default::default();
63 let node = match genv.tcx().hir_node_by_def_id(def_id) {
64 rustc_hir::Node::Item(_) => {
65 let item = cx.with_rust_item_ctxt(owner_id, Some(&mut opaque_tys), |cx| {
66 match specs.get_item(owner_id) {
67 Some(item) => cx.desugar_item(item),
68 None => cx.lift_item(),
69 }
70 })?;
71 fhir::Node::Item(genv.alloc(item))
72 }
73 rustc_hir::Node::TraitItem(_) => {
74 let item = cx.with_rust_item_ctxt(owner_id, Some(&mut opaque_tys), |cx| {
75 match specs.get_trait_item(owner_id) {
76 Some(item) => cx.desugar_trait_item(item),
77 None => Ok(cx.lift_trait_item()),
78 }
79 })?;
80 fhir::Node::TraitItem(genv.alloc(item))
81 }
82 rustc_hir::Node::ImplItem(..) => {
83 let item = cx.with_rust_item_ctxt(owner_id, Some(&mut opaque_tys), |cx| {
84 match specs.get_impl_item(owner_id) {
85 Some(item) => cx.desugar_impl_item(item),
86 None => Ok(cx.lift_impl_item()),
87 }
88 })?;
89 fhir::Node::ImplItem(genv.alloc(item))
90 }
91 rustc_hir::Node::AnonConst(..) => fhir::Node::AnonConst,
92 rustc_hir::Node::Expr(..) => fhir::Node::Expr,
93 rustc_hir::Node::ForeignItem(foreign) => {
94 let item =
95 cx.with_rust_item_ctxt(owner_id, None, |cx| cx.lift_foreign_item(*foreign))?;
96 fhir::Node::ForeignItem(genv.alloc(item))
97 }
98 rustc_hir::Node::Ctor(rustc_hir::VariantData::Tuple(_, _, _)) => fhir::Node::Ctor,
99
100 _ => {
101 return Err(query_bug!(
102 def_id,
103 "unexpected {} found in desugaring",
104 genv.tcx().def_descr(def_id.to_def_id())
105 ));
106 }
107 };
108 nodes.insert(def_id, node);
109 nodes.extend(
110 opaque_tys
111 .into_iter()
112 .map(|opaque_ty| (opaque_ty.def_id.local_id(), fhir::Node::OpaqueTy(opaque_ty))),
113 );
114 Ok(nodes)
115}
116
117struct DesugarCtxt<'genv, 'tcx> {
118 genv: GlobalEnv<'genv, 'tcx>,
119 resolver_output: &'genv ResolverOutput,
120}
121
122impl<'genv, 'tcx> DesugarCtxt<'genv, 'tcx> {
123 fn with_rust_item_ctxt<'a, T>(
124 &'a self,
125 owner_id: OwnerId,
126 opaque_tys: Option<&'a mut Vec<&'genv fhir::OpaqueTy<'genv>>>,
127 f: impl FnOnce(&mut RustItemCtxt<'a, 'genv, 'tcx>) -> Result<T>,
128 ) -> Result<T> {
129 let owner_id = self
130 .genv
131 .maybe_extern_id(owner_id.def_id)
132 .map(|def_id| OwnerId { def_id });
133 RustItemCtxt::with(self.genv, owner_id, self.resolver_output, opaque_tys, f)
134 }
135}
136
137fn desugar_crate<'genv>(genv: GlobalEnv<'genv, '_>) -> fhir::FluxItems<'genv> {
138 match try_desugar_crate(genv) {
139 Ok(fhir) => fhir,
140 Err(err) => {
141 genv.sess().abort(err);
146 }
147 }
148}
149
150#[allow(clippy::disallowed_methods, reason = "Ths is the source of truth for FluxDefId's")]
151fn try_desugar_crate<'genv>(genv: GlobalEnv<'genv, '_>) -> Result<fhir::FluxItems<'genv>> {
152 let specs = genv.collect_specs();
153 let resolver_output = genv.resolve_crate();
154
155 let mut fhir = fhir::FluxItems::new();
156 let mut err: Option<ErrorGuaranteed> = None;
157 for (parent, items) in &specs.flux_items_by_parent {
158 for item in items {
159 let def_id = FluxLocalDefId::new(parent.def_id, item.name().name);
160 FluxItemCtxt::with(genv, resolver_output, def_id, |cx| {
161 fhir.items.insert(def_id, cx.desugar_flux_item(item));
162 })
163 .collect_err(&mut err);
164 }
165 }
166 err.into_result()?;
167
168 Ok(fhir)
169}
170
171fn fhir_attr_map<'genv>(genv: GlobalEnv<'genv, '_>, def_id: LocalDefId) -> fhir::AttrMap<'genv> {
172 let owner_id = OwnerId { def_id };
173 let specs = genv.collect_specs();
174
175 let (node_id, attrs) = if let Some(item) = specs.get_item(owner_id) {
176 (item.node_id, &item.attrs)
177 } else if let Some(impl_item) = specs.get_impl_item(owner_id) {
178 (impl_item.node_id, &impl_item.attrs)
179 } else if let Some(trait_item) = specs.get_trait_item(owner_id) {
180 (trait_item.node_id, &trait_item.attrs)
181 } else {
182 return fhir::AttrMap::default();
183 };
184
185 let resolver_output = genv.resolve_crate();
186 fhir::AttrMap {
187 attrs: genv.alloc_slice_fill_iter(
188 attrs
189 .iter()
190 .filter_map(|attr| {
191 match *attr {
192 surface::Attr::Trusted(trusted) => Some(fhir::Attr::Trusted(trusted)),
193 surface::Attr::TrustedImpl(trusted) => {
194 Some(fhir::Attr::TrustedImpl(trusted))
195 }
196 surface::Attr::Ignore(ignored) => Some(fhir::Attr::Ignore(ignored)),
197 surface::Attr::ProvenExternally => Some(fhir::Attr::ProvenExternally),
198 surface::Attr::ShouldFail => Some(fhir::Attr::ShouldFail),
199 surface::Attr::InferOpts(opts) => Some(fhir::Attr::InferOpts(opts)),
200 surface::Attr::NoPanic => Some(fhir::Attr::NoPanic),
201 surface::Attr::Qualifiers(_) | surface::Attr::Reveal(_) => None,
202 }
203 })
204 .collect_vec(),
205 ),
206 qualifiers: resolver_output
207 .qualifier_res_map
208 .get(&node_id)
209 .map_or(&[][..], Vec::as_slice),
210 reveals: resolver_output
211 .reveal_res_map
212 .get(&node_id)
213 .map_or(&[][..], Vec::as_slice),
214 }
215}