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 rustc_data_structures::unord::UnordMap;
17
18fluent_messages! { "../locales/en-US.ftl" }
19
20mod desugar;
21mod errors;
22pub mod resolver;
23
24use flux_middle::{
25 ResolverOutput, Specs,
26 def_id::FluxLocalDefId,
27 fhir,
28 global_env::GlobalEnv,
29 queries::{Providers, QueryErr, QueryResult},
30 query_bug,
31};
32use flux_syntax::surface;
33use rustc_errors::ErrorGuaranteed;
34use rustc_hir::{self as hir, OwnerId};
35use rustc_span::def_id::LocalDefId;
36
37type Result<T = ()> = std::result::Result<T, ErrorGuaranteed>;
38
39pub fn provide(providers: &mut Providers) {
40 providers.resolve_crate = resolver::resolve_crate;
41 providers.desugar = desugar;
42 providers.fhir_crate = desugar_crate;
43}
44
45pub fn desugar<'genv>(
46 genv: GlobalEnv<'genv, '_>,
47 def_id: LocalDefId,
48) -> QueryResult<UnordMap<LocalDefId, fhir::Node<'genv>>> {
49 if genv.ignored(def_id) {
50 return Err(QueryErr::Ignored { def_id: def_id.to_def_id() });
51 }
52
53 let cx = DesugarCtxt { genv, resolver_output: genv.resolve_crate() };
54 let specs = genv.collect_specs();
55 let owner_id = OwnerId { def_id };
56 let mut nodes = UnordMap::default();
57
58 match genv.tcx().hir_node_by_def_id(def_id) {
59 rustc_hir::Node::Item(item) => {
60 match item.kind {
61 hir::ItemKind::Fn { .. } => {
62 let fn_spec = specs.fn_sigs.get(&owner_id).unwrap();
63 let mut opaque_tys = Default::default();
64 let item = cx.with_rust_item_ctxt(owner_id, Some(&mut opaque_tys), |cx| {
65 cx.desugar_item_fn(fn_spec)
66 })?;
67 nodes.extend(opaque_tys.into_iter().map(|opaque_ty| {
68 (opaque_ty.def_id.local_id(), fhir::Node::OpaqueTy(opaque_ty))
69 }));
70 nodes.insert(def_id, fhir::Node::Item(genv.alloc(item)));
71 }
72 hir::ItemKind::TyAlias(..) => {
73 let ty_alias = specs.ty_aliases[&owner_id].as_ref();
74 nodes.insert(
75 def_id,
76 fhir::Node::Item(genv.alloc(cx.with_rust_item_ctxt(
77 owner_id,
78 None,
79 |cx| Ok(cx.desugar_type_alias(ty_alias)),
80 )?)),
81 );
82 }
83
84 hir::ItemKind::Enum(..) => {
85 let enum_def = &specs.enums[&owner_id];
86 nodes.insert(
87 def_id,
88 fhir::Node::Item(genv.alloc(cx.with_rust_item_ctxt(
89 owner_id,
90 None,
91 |cx| cx.desugar_enum_def(enum_def),
92 )?)),
93 );
94 }
95 hir::ItemKind::Union(..) => {
96 let union_def = &specs.structs[&owner_id];
97 nodes.insert(
98 def_id,
99 fhir::Node::Item(genv.alloc(cx.with_rust_item_ctxt(
100 owner_id,
101 None,
102 |cx| Ok(cx.desugar_struct_def(union_def)),
103 )?)),
104 );
105 }
106 hir::ItemKind::Struct(..) => {
107 let struct_def = &specs.structs[&owner_id];
108 nodes.insert(
109 def_id,
110 fhir::Node::Item(genv.alloc(cx.with_rust_item_ctxt(
111 owner_id,
112 None,
113 |cx| Ok(cx.desugar_struct_def(struct_def)),
114 )?)),
115 );
116 }
117 hir::ItemKind::Trait(..) => {
118 let trait_ = &specs.traits[&owner_id];
119 nodes.insert(
120 def_id,
121 fhir::Node::Item(genv.alloc(cx.with_rust_item_ctxt(
122 owner_id,
123 None,
124 |cx| cx.desugar_trait(trait_),
125 )?)),
126 );
127 }
128 hir::ItemKind::Impl(..) => {
129 let impl_ = &specs.impls[&owner_id];
130 nodes.insert(
131 def_id,
132 fhir::Node::Item(genv.alloc(cx.with_rust_item_ctxt(
133 owner_id,
134 None,
135 |cx| Ok(cx.desugar_impl(impl_)),
136 )?)),
137 );
138 }
139 hir::ItemKind::Const(..) => {
140 let constant_ = match specs.constants.get(&owner_id) {
141 Some(constant_) => constant_,
142 None => &surface::ConstantInfo { expr: None },
143 };
144
145 nodes.insert(
146 def_id,
147 fhir::Node::Item(genv.alloc(cx.with_rust_item_ctxt(
148 owner_id,
149 None,
150 |cx| Ok(cx.desugar_const(constant_)),
151 )?)),
152 );
153 }
154 _ => Err(query_bug!(def_id, "unsupported item"))?,
155 }
156 }
157 rustc_hir::Node::TraitItem(trait_item) => {
158 match trait_item.kind {
159 rustc_hir::TraitItemKind::Fn(..) => {
160 let fn_spec = specs.fn_sigs.get(&owner_id).unwrap();
161 let mut opaque_tys = Default::default();
162 let item = cx.with_rust_item_ctxt(owner_id, Some(&mut opaque_tys), |cx| {
163 cx.desugar_trait_fn(fn_spec)
164 })?;
165 nodes.extend(opaque_tys.into_iter().map(|opaque_ty| {
166 (opaque_ty.def_id.local_id(), fhir::Node::OpaqueTy(opaque_ty))
167 }));
168 nodes.insert(def_id, fhir::Node::TraitItem(genv.alloc(item)));
169 }
170 rustc_hir::TraitItemKind::Type(..) => {
171 let item = cx.with_rust_item_ctxt(owner_id, None, |cx| {
172 Ok(cx.desugar_trait_assoc_ty())
173 })?;
174 nodes.insert(owner_id.def_id, fhir::Node::TraitItem(genv.alloc(item)));
175 }
176 rustc_hir::TraitItemKind::Const(..) => {
177 nodes.insert(
178 def_id,
179 fhir::Node::TraitItem(genv.alloc(cx.with_rust_item_ctxt(
180 owner_id,
181 None,
182 |cx| Ok(cx.desugar_trait_const()),
183 )?)),
184 );
185 }
186 }
187 }
188 rustc_hir::Node::ImplItem(impl_item) => {
189 match &impl_item.kind {
190 rustc_hir::ImplItemKind::Fn(..) => {
191 let fn_spec = specs.fn_sigs.get(&owner_id).unwrap();
192 let mut opaque_tys = Default::default();
193 let item = cx.with_rust_item_ctxt(owner_id, Some(&mut opaque_tys), |cx| {
194 cx.desugar_impl_fn(fn_spec)
195 })?;
196 nodes.extend(opaque_tys.into_iter().map(|opaque_ty| {
197 (opaque_ty.def_id.local_id(), fhir::Node::OpaqueTy(opaque_ty))
198 }));
199 nodes.insert(def_id, fhir::Node::ImplItem(genv.alloc(item)));
200 }
201 rustc_hir::ImplItemKind::Type(..) => {
202 let item = cx
203 .with_rust_item_ctxt(owner_id, None, |cx| Ok(cx.desugar_impl_assoc_ty()))?;
204 nodes.insert(owner_id.def_id, fhir::Node::ImplItem(genv.alloc(item)));
205 }
206 rustc_hir::ImplItemKind::Const(..) => {
207 nodes.insert(
208 def_id,
209 fhir::Node::ImplItem(genv.alloc(cx.with_rust_item_ctxt(
210 owner_id,
211 None,
212 |cx| Ok(cx.desugar_impl_const()),
213 )?)),
214 );
215 }
216 }
217 }
218 rustc_hir::Node::AnonConst(..) => {
219 nodes.insert(def_id, fhir::Node::AnonConst);
220 }
221 rustc_hir::Node::Expr(..) => {
222 nodes.insert(def_id, fhir::Node::Expr);
223 }
224 rustc_hir::Node::ForeignItem(foreign) => {
225 let foreign_item = fhir::Node::ForeignItem(genv.alloc(cx.with_rust_item_ctxt(
226 owner_id,
227 None,
228 |cx| cx.desugar_foreign_item(*foreign),
229 )?));
230 nodes.insert(def_id, foreign_item);
231 }
232 rustc_hir::Node::Ctor(rustc_hir::VariantData::Tuple(_, _, _)) => {
233 nodes.insert(def_id, fhir::Node::Ctor);
234 }
235 node => {
236 if let Some(ident) = node.ident() {
237 Err(query_bug!(def_id, "unsupported item {ident:?}"))?;
238 } else {
239 Err(query_bug!(def_id, "unsupported item"))?;
240 }
241 }
242 }
243 Ok(nodes)
244}
245
246struct DesugarCtxt<'genv, 'tcx> {
247 genv: GlobalEnv<'genv, 'tcx>,
248 resolver_output: &'genv ResolverOutput,
249}
250
251impl<'genv, 'tcx> DesugarCtxt<'genv, 'tcx> {
252 fn with_rust_item_ctxt<'a, T>(
253 &'a self,
254 owner_id: OwnerId,
255 opaque_tys: Option<&'a mut Vec<&'genv fhir::OpaqueTy<'genv>>>,
256 f: impl FnOnce(&mut RustItemCtxt<'a, 'genv, 'tcx>) -> Result<T>,
257 ) -> Result<T> {
258 let owner_id = self
259 .genv
260 .maybe_extern_id(owner_id.def_id)
261 .map(|def_id| OwnerId { def_id });
262 RustItemCtxt::with(self.genv, owner_id, self.resolver_output, opaque_tys, f)
263 }
264}
265
266fn desugar_crate<'genv>(genv: GlobalEnv<'genv, '_>) -> fhir::FluxItems<'genv> {
267 match try_desugar_crate(genv) {
268 Ok(fhir) => fhir,
269 Err(err) => {
270 genv.sess().abort(err);
275 }
276 }
277}
278
279fn try_desugar_crate<'genv>(genv: GlobalEnv<'genv, '_>) -> Result<fhir::FluxItems<'genv>> {
280 let specs = genv.collect_specs();
281 let fhir = fhir::FluxItems::new();
282 let resolver_output = genv.resolve_crate();
283 let mut cx = CrateDesugar::new(genv, fhir, resolver_output);
284 cx.desugar_flux_items(specs);
285
286 cx.err.into_result()?;
287 Ok(cx.fhir)
288}
289
290struct CrateDesugar<'genv, 'tcx> {
291 genv: GlobalEnv<'genv, 'tcx>,
292 fhir: fhir::FluxItems<'genv>,
293 resolver_output: &'genv ResolverOutput,
294 err: Option<ErrorGuaranteed>,
295}
296
297impl<'genv, 'tcx> CrateDesugar<'genv, 'tcx> {
298 fn new(
299 genv: GlobalEnv<'genv, 'tcx>,
300 fhir: fhir::FluxItems<'genv>,
301 resolver_output: &'genv ResolverOutput,
302 ) -> Self {
303 Self { genv, fhir, resolver_output, err: None }
304 }
305}
306
307impl CrateDesugar<'_, '_> {
308 #[allow(clippy::disallowed_methods, reason = "`flux_items_by_parent` is the source of truth")]
309 fn desugar_flux_items(&mut self, specs: &Specs) {
310 for (parent, items) in &specs.flux_items_by_parent {
311 for item in items {
312 let def_id = FluxLocalDefId::new(parent.def_id, item.name().name);
313 match item {
314 surface::Item::Qualifier(qual) => {
315 self.desugar_qualifier(def_id, qual)
316 .collect_err(&mut self.err);
317 }
318 surface::Item::FuncDef(defn) => {
319 self.desugar_func_defn(def_id, defn)
320 .collect_err(&mut self.err);
321 }
322 surface::Item::SortDecl(_) => {}
323 surface::Item::PrimOpProp(primop_prop) => {
324 self.desugar_primop_prop(def_id, primop_prop)
325 .collect_err(&mut self.err);
326 }
327 }
328 }
329 }
330 }
331
332 fn desugar_primop_prop(
333 &mut self,
334 def_id: FluxLocalDefId,
335 prop: &surface::PrimOpProp,
336 ) -> Result {
337 let prop = desugar::desugar_primop_prop(self.genv, self.resolver_output, def_id, prop)?;
338 self.fhir
339 .items
340 .insert(def_id, fhir::FluxItem::PrimOpProp(self.genv.alloc(prop)));
341 Ok(())
342 }
343
344 fn desugar_func_defn(&mut self, def_id: FluxLocalDefId, func: &surface::SpecFunc) -> Result {
345 let func = desugar::desugar_spec_func(self.genv, self.resolver_output, def_id, func)?;
346 self.fhir
347 .items
348 .insert(def_id, fhir::FluxItem::Func(self.genv.alloc(func)));
349 Ok(())
350 }
351
352 fn desugar_qualifier(
353 &mut self,
354 def_id: FluxLocalDefId,
355 qualifier: &surface::Qualifier,
356 ) -> Result {
357 let qualifier =
358 desugar::desugar_qualifier(self.genv, self.resolver_output, def_id, qualifier)?;
359 self.fhir
360 .items
361 .insert(def_id, fhir::FluxItem::Qualifier(self.genv.alloc(qualifier)));
362 Ok(())
363 }
364}