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