Skip to main content

flux_fhir_analysis/
lib.rs

1#![feature(rustc_private)]
2
3extern crate rustc_abi;
4extern crate rustc_ast;
5extern crate rustc_data_structures;
6extern crate rustc_errors;
7extern crate rustc_hir;
8extern crate rustc_index;
9extern crate rustc_infer;
10extern crate rustc_middle;
11extern crate rustc_span;
12extern crate rustc_trait_selection;
13extern crate rustc_type_ir;
14
15mod conv;
16mod wf;
17use std::{iter, rc::Rc};
18
19use conv::{AfterSortck, ConvPhase, struct_compat};
20use flux_common::{
21    bug, dbg,
22    iter::IterExt,
23    result::{ErrorEmitter as _, ResultExt},
24};
25use flux_config as config;
26use flux_errors::Errors;
27use flux_middle::{
28    def_id::{FluxDefId, FluxId, MaybeExternId},
29    fhir::{
30        self, ForeignItem, ForeignItemKind, ImplItem, ImplItemKind, Item, ItemKind, TraitItem,
31        TraitItemKind, visit::Visitor as _,
32    },
33    global_env::GlobalEnv,
34    queries::{Providers, QueryErr, QueryResult},
35    query_bug,
36    rty::{
37        self, AssocReft, Binder, WfckResults,
38        fold::TypeFoldable,
39        refining::{self, Refiner},
40    },
41};
42use flux_rustc_bridge::lowering::Lower;
43use itertools::Itertools;
44use rustc_abi::FIRST_VARIANT;
45use rustc_data_structures::unord::{UnordMap, UnordSet};
46use rustc_errors::ErrorGuaranteed;
47use rustc_hir::{
48    OwnerId,
49    def::{CtorOf, DefKind},
50    def_id::{DefId, LocalDefId},
51};
52use rustc_span::Span;
53
54pub fn provide(providers: &mut Providers) {
55    providers.normalized_defns = normalized_defns;
56    providers.func_sort = func_sort;
57    providers.func_span = flux_def_ident_span;
58    providers.qualifiers = qualifiers;
59    providers.prim_rel = prim_rel;
60    providers.adt_sort_def_of = adt_sort_def_of;
61    providers.check_wf = check_wf;
62    providers.late_bound_refinement_params = late_bound_refinement_params;
63    providers.adt_def = adt_def;
64    providers.invariants_of = invariants_of;
65    providers.constant_info = constant_info;
66    providers.static_info = static_info;
67    providers.type_of = type_of;
68    providers.variants_of = variants_of;
69    providers.fn_sig = fn_sig;
70    providers.generics_of = generics_of;
71    providers.refinement_generics_of = refinement_generics_of;
72    providers.predicates_of = predicates_of;
73    providers.assoc_refinements_of = assoc_refinements_of;
74    providers.sort_of_assoc_reft = sort_of_assoc_reft;
75    providers.assoc_refinement_body = assoc_refinement_body;
76    providers.default_assoc_refinement_body = default_assoc_refinement_body;
77    providers.item_bounds = item_bounds;
78    providers.sort_decl_param_count = sort_decl_param_count;
79}
80
81fn sort_decl_param_count(genv: GlobalEnv, def_id: FluxId<MaybeExternId>) -> usize {
82    genv.fhir_sort_decl(def_id.local_id()).unwrap().params
83}
84
85fn adt_sort_def_of(genv: GlobalEnv, def_id: MaybeExternId) -> QueryResult<rty::AdtSortDef> {
86    let kind = genv.fhir_expect_refinement_kind(def_id.local_id())?;
87    conv::conv_adt_sort_def(genv, def_id, kind)
88}
89
90fn func_sort(genv: GlobalEnv, def_id: FluxId<MaybeExternId>) -> rty::PolyFuncSort {
91    let func = genv.fhir_spec_func_body(def_id.local_id()).unwrap();
92    match conv::conv_func_decl(genv, func).emit(&genv) {
93        Ok(normalized) => normalized,
94        Err(err) => {
95            genv.sess().abort(err);
96        }
97    }
98}
99
100fn flux_def_ident_span(genv: GlobalEnv, def_id: FluxId<MaybeExternId>) -> Span {
101    genv.fhir_spec_func_body(def_id.local_id())
102        .unwrap()
103        .ident_span
104}
105
106fn normalized_defns(genv: GlobalEnv) -> rty::NormalizedDefns {
107    match try_normalized_defns(genv) {
108        Ok(normalized) => normalized,
109        Err(err) => {
110            genv.sess().abort(err);
111        }
112    }
113}
114
115fn try_normalized_defns(genv: GlobalEnv) -> Result<rty::NormalizedDefns, ErrorGuaranteed> {
116    let mut defns = vec![];
117
118    // Collect and emit all errors
119    let mut errors = Errors::new(genv.sess());
120    for (_, item) in genv.fhir_iter_flux_items() {
121        let fhir::FluxItem::Func(func) = item else { continue };
122        let Some(wfckresults) = wf::check_flux_item(genv, item).collect_err(&mut errors) else {
123            continue;
124        };
125        let mut cx = AfterSortck::new(genv, &wfckresults).into_conv_ctxt();
126        let Ok(defn) = cx.conv_defn(func).emit(&errors) else { continue };
127        defns.push((func.def_id, defn, func.hide));
128    }
129    errors.to_result()?;
130
131    let defns = rty::NormalizedDefns::new(genv, &defns)
132        .map_err(|cycle| {
133            let span = genv
134                .fhir_spec_func_body(cycle[0])
135                .unwrap()
136                .body
137                .unwrap()
138                .span;
139            errors::DefinitionCycle::new(span, cycle)
140        })
141        .emit(&genv)?;
142
143    Ok(defns)
144}
145
146fn qualifiers(genv: GlobalEnv) -> QueryResult<Vec<rty::Qualifier>> {
147    genv.fhir_qualifiers()
148        .map(|qualifier| {
149            let wfckresults = wf::check_flux_item(genv, fhir::FluxItem::Qualifier(qualifier))?;
150            Ok(AfterSortck::new(genv, &wfckresults)
151                .into_conv_ctxt()
152                .conv_qualifier(qualifier)?
153                .normalize(genv))
154        })
155        .try_collect()
156}
157
158fn primop_props(genv: GlobalEnv) -> QueryResult<Vec<rty::PrimOpProp>> {
159    genv.fhir_primop_props()
160        .map(|primop_prop| {
161            let wfckresults = wf::check_flux_item(genv, fhir::FluxItem::PrimOpProp(primop_prop))?;
162            Ok(AfterSortck::new(genv, &wfckresults)
163                .into_conv_ctxt()
164                .conv_primop_prop(primop_prop)?
165                .normalize(genv))
166        })
167        .try_collect()
168}
169
170fn conjoin_bind_exprs(exprs: Vec<Binder<rty::Expr>>) -> Binder<rty::Expr> {
171    let mut iter = exprs.into_iter();
172    let first = iter.next().unwrap();
173    let sorts = first.sorts();
174    let bodies = iter::once(first.skip_binder()).chain(iter.map(|expr| expr.skip_binder()));
175    let expr = rty::Expr::and_from_iter(bodies);
176    Binder::bind_with_sorts(expr, &sorts)
177}
178
179fn prim_rel(genv: GlobalEnv) -> QueryResult<UnordMap<rty::BinOp, rty::PrimRel>> {
180    let primop_props = primop_props(genv)?
181        .into_iter()
182        .into_group_map_by(|primop_prop| primop_prop.op.clone());
183
184    let mut res = UnordMap::default();
185    for (op, props) in primop_props {
186        let exprs = props
187            .iter()
188            .map(|prop| prop.body.clone())
189            .collect::<Vec<_>>();
190        let body = conjoin_bind_exprs(exprs);
191        res.insert(op, rty::PrimRel { body });
192    }
193    Ok(res)
194}
195
196fn adt_def(genv: GlobalEnv, def_id: MaybeExternId) -> QueryResult<rty::AdtDef> {
197    let item = genv.fhir_expect_item(def_id.local_id())?;
198
199    let adt_def = genv.tcx().adt_def(def_id.resolved_id()).lower(genv.tcx());
200
201    let is_opaque = matches!(item.kind, fhir::ItemKind::Struct(def) if def.is_opaque());
202
203    Ok(rty::AdtDef::new(adt_def, genv.adt_sort_def_of(def_id)?, is_opaque))
204}
205
206fn constant_info(genv: GlobalEnv, def_id: MaybeExternId) -> QueryResult<rty::ConstantInfo> {
207    let node = genv.fhir_node(def_id.local_id())?;
208    let Some(sort) = genv.sort_of_def_id(def_id.resolved_id()).emit(&genv)? else {
209        return Ok(rty::ConstantInfo::Uninterpreted);
210    };
211    let tcx = genv.tcx();
212    match node {
213        fhir::Node::Item(fhir::Item { kind: fhir::ItemKind::Const(Some(expr)), .. }) => {
214            // If the constant has a `#[consant(expr)]` annotation we use that
215            let owner = def_id.map(|def_id| rustc_hir::OwnerId { def_id });
216            let wfckresults = wf::check_constant_expr(genv, owner, expr, &sort)?;
217            let expr = AfterSortck::new(genv, &wfckresults)
218                .into_conv_ctxt()
219                .conv_constant_expr(expr)?;
220            Ok(rty::ConstantInfo::Interpreted(expr, sort))
221        }
222        fhir::Node::Item(fhir::Item { kind: fhir::ItemKind::Const(None), .. })
223        | fhir::Node::AnonConst
224        | fhir::Node::ImplItem(fhir::ImplItem { kind: fhir::ImplItemKind::Const, .. }) => {
225            // For other constants, we try to evaluate them if they are integral
226            if let Some(ty) = tcx.type_of(def_id).no_bound_vars()
227                && ty.is_integral()
228                && let Ok(val) = tcx.const_eval_poly(def_id.resolved_id())
229                && let Some(val) = val.try_to_scalar_int()
230                && let Some(constant_) = rty::Constant::from_scalar_int(tcx, val, &ty)
231            {
232                // FIXME(nilehmann) we should probably report an error in case const evaluation
233                // fails instead of silently ignore it.
234                Ok(rty::ConstantInfo::Interpreted(rty::Expr::constant(constant_), rty::Sort::Int))
235            } else {
236                Ok(rty::ConstantInfo::Uninterpreted)
237            }
238        }
239        fhir::Node::TraitItem(fhir::TraitItem { kind: fhir::TraitItemKind::Const, .. }) => {
240            Ok(rty::ConstantInfo::Uninterpreted)
241        }
242        _ => Err(query_bug!(def_id.local_id(), "expected const item"))?,
243    }
244}
245
246fn static_info(genv: GlobalEnv, def_id: MaybeExternId) -> QueryResult<rty::StaticInfo> {
247    let node = genv.fhir_node(def_id.local_id())?;
248    match node {
249        fhir::Node::Item(fhir::Item { kind: fhir::ItemKind::Static(ty), .. }) => {
250            if let Some(ty) = ty {
251                let wfckresults = genv.check_wf(def_id.local_id())?;
252                let rty_ty = AfterSortck::new(genv, &wfckresults)
253                    .into_conv_ctxt()
254                    .conv_static_ty(ty)?;
255                Ok(rty::StaticInfo::Known(rty_ty))
256            } else {
257                Ok(rty::StaticInfo::Unknown)
258            }
259        }
260        _ => Ok(rty::StaticInfo::Unknown),
261    }
262}
263
264/// Errors are reported at the definition of the adt. If the invariants fail to convert, we
265/// continue as if the adt had no invariants. This is sound because the invariants are then
266/// neither checked (when constructing the adt) nor assumed (when using it).
267fn invariants_of(
268    genv: GlobalEnv,
269    def_id: MaybeExternId,
270) -> rty::EarlyBinder<rty::List<rty::Invariant>> {
271    let invariants = try_invariants_of(genv, def_id).unwrap_or_else(|err| {
272        if !matches!(err, QueryErr::Emitted(_)) {
273            genv.emit(err);
274        }
275        vec![]
276    });
277    rty::EarlyBinder(rty::List::from_vec(invariants))
278}
279
280fn try_invariants_of(genv: GlobalEnv, def_id: MaybeExternId) -> QueryResult<Vec<rty::Invariant>> {
281    let item = genv.fhir_expect_item(def_id.local_id())?;
282    let (params, invariants) = match &item.kind {
283        fhir::ItemKind::Enum(enum_def) => (enum_def.params, enum_def.invariants),
284        fhir::ItemKind::Struct(struct_def) => (struct_def.params, struct_def.invariants),
285        _ => Err(query_bug!(item.owner_id.local_id(), "expected struct or enum"))?,
286    };
287    let wfckresults = wf::check_invariants(genv, item.owner_id, params, invariants)?;
288    AfterSortck::new(genv, &wfckresults)
289        .into_conv_ctxt()
290        .conv_invariants(item.owner_id.map(|it| it.def_id), params, invariants)
291}
292
293fn predicates_of(
294    genv: GlobalEnv,
295    def_id: MaybeExternId,
296) -> QueryResult<rty::EarlyBinder<rty::GenericPredicates>> {
297    match genv.def_kind(def_id) {
298        DefKind::Impl { .. }
299        | DefKind::Struct
300        | DefKind::Enum
301        | DefKind::Union
302        | DefKind::TyAlias
303        | DefKind::AssocFn
304        | DefKind::AssocTy
305        | DefKind::Trait
306        | DefKind::Fn => {
307            let did = def_id.local_id();
308            let generics = genv
309                .fhir_get_generics(did)?
310                .ok_or_else(|| query_bug!(did, "no generics for {def_id:?}"))?;
311            let wfckresults = genv.check_wf(did)?;
312            AfterSortck::new(genv, &wfckresults)
313                .into_conv_ctxt()
314                .conv_generic_predicates(def_id, generics)
315        }
316        DefKind::OpaqueTy | DefKind::Closure | DefKind::Static { .. } => {
317            Ok(rty::EarlyBinder(rty::GenericPredicates {
318                parent: genv.tcx().clauses_of(def_id).parent,
319                predicates: rty::List::empty(),
320            }))
321        }
322        kind => {
323            Err(query_bug!(
324                def_id.local_id(),
325                "predicates_of called on `{def_id:?}` with kind `{kind:?}`"
326            ))?
327        }
328    }
329}
330
331fn assoc_refinements_of(
332    genv: GlobalEnv,
333    def_id: MaybeExternId,
334) -> QueryResult<rty::AssocRefinements> {
335    #[allow(
336        clippy::disallowed_methods,
337        reason = "We are iterationg over associated refinemens in fhir, so this is the *source of of truth*"
338    )]
339    let predicates = match &genv.fhir_expect_item(def_id.local_id())?.kind {
340        fhir::ItemKind::Trait(trait_) => {
341            trait_
342                .assoc_refinements
343                .iter()
344                .map(|assoc_reft| {
345                    AssocReft::new(
346                        FluxDefId::new(def_id.resolved_id(), assoc_reft.name),
347                        assoc_reft.final_,
348                        assoc_reft.span,
349                    )
350                })
351                .collect()
352        }
353        fhir::ItemKind::Impl(impl_) => {
354            impl_
355                .assoc_refinements
356                .iter()
357                .map(|assoc_reft| {
358                    AssocReft::new(
359                        FluxDefId::new(def_id.resolved_id(), assoc_reft.name),
360                        false,
361                        assoc_reft.span,
362                    )
363                })
364                .collect()
365        }
366        _ => Err(query_bug!(def_id.resolved_id(), "expected trait or impl"))?,
367    };
368    Ok(rty::AssocRefinements { items: predicates })
369}
370
371fn default_assoc_refinement_body(
372    genv: GlobalEnv,
373    trait_assoc_id: FluxId<MaybeExternId>,
374) -> QueryResult<Option<rty::EarlyBinder<rty::Lambda>>> {
375    let trait_id = trait_assoc_id.parent();
376    let assoc_reft = genv
377        .fhir_expect_item(trait_id.local_id())?
378        .expect_trait()
379        .find_assoc_reft(trait_assoc_id.name())
380        .unwrap();
381    let Some(body) = assoc_reft.body else { return Ok(None) };
382    let wfckresults = genv.check_wf(trait_id.local_id())?;
383    let mut cx = AfterSortck::new(genv, &wfckresults).into_conv_ctxt();
384    let body = cx.conv_assoc_reft_body(assoc_reft.params, &body, &assoc_reft.output)?;
385    Ok(Some(rty::EarlyBinder(body)))
386}
387
388fn assoc_refinement_body(
389    genv: GlobalEnv,
390    impl_assoc_id: FluxId<MaybeExternId>,
391) -> QueryResult<rty::EarlyBinder<rty::Lambda>> {
392    let impl_id = impl_assoc_id.parent();
393
394    let assoc_reft = genv
395        .fhir_expect_item(impl_id.local_id())?
396        .expect_impl()
397        .find_assoc_reft(impl_assoc_id.name())
398        .unwrap();
399
400    let wfckresults = genv.check_wf(impl_id.local_id())?;
401    let mut cx = AfterSortck::new(genv, &wfckresults).into_conv_ctxt();
402    let body = cx.conv_assoc_reft_body(assoc_reft.params, &assoc_reft.body, &assoc_reft.output)?;
403    Ok(rty::EarlyBinder(body))
404}
405
406fn sort_of_assoc_reft(
407    genv: GlobalEnv,
408    assoc_id: FluxId<MaybeExternId>,
409) -> QueryResult<rty::EarlyBinder<rty::FuncSort>> {
410    let container_id = assoc_id.parent();
411
412    match &genv.fhir_expect_item(container_id.local_id())?.kind {
413        fhir::ItemKind::Trait(trait_) => {
414            let assoc_reft = trait_.find_assoc_reft(assoc_id.name()).unwrap();
415            let wfckresults = WfckResults::new(container_id.map(|def_id| OwnerId { def_id }));
416            let mut cx = AfterSortck::new(genv, &wfckresults).into_conv_ctxt();
417            let inputs = assoc_reft
418                .params
419                .iter()
420                .map(|p| cx.conv_sort(&p.sort))
421                .try_collect_vec()?;
422            let output = cx.conv_sort(&assoc_reft.output)?;
423            Ok(rty::EarlyBinder(rty::FuncSort::new(inputs, output)))
424        }
425        fhir::ItemKind::Impl(impl_) => {
426            let assoc_reft = impl_.find_assoc_reft(assoc_id.name()).unwrap();
427            let wfckresults = WfckResults::new(container_id.map(|def_id| OwnerId { def_id }));
428            let mut cx = AfterSortck::new(genv, &wfckresults).into_conv_ctxt();
429            let inputs = assoc_reft
430                .params
431                .iter()
432                .map(|p| cx.conv_sort(&p.sort))
433                .try_collect_vec()?;
434            let output = cx.conv_sort(&assoc_reft.output)?;
435            Ok(rty::EarlyBinder(rty::FuncSort::new(inputs, output)))
436        }
437        _ => Err(query_bug!(container_id.local_id(), "expected trait or impl")),
438    }
439}
440
441fn item_bounds(
442    genv: GlobalEnv,
443    def_id: MaybeExternId,
444) -> QueryResult<rty::EarlyBinder<rty::Clauses>> {
445    let parent = genv.tcx().local_parent(def_id.local_id());
446    let wfckresults = genv.check_wf(parent)?;
447    let opaque_ty = genv.fhir_node(def_id.local_id())?.expect_opaque_ty();
448    Ok(rty::EarlyBinder(
449        AfterSortck::new(genv, &wfckresults)
450            .into_conv_ctxt()
451            .conv_opaque_ty(opaque_ty)?,
452    ))
453}
454
455fn generics_of(genv: GlobalEnv, def_id: MaybeExternId) -> QueryResult<rty::Generics> {
456    let def_kind = genv.def_kind(def_id);
457    let generics = match def_kind {
458        DefKind::Impl { .. }
459        | DefKind::Struct
460        | DefKind::Enum
461        | DefKind::Union
462        | DefKind::TyAlias
463        | DefKind::AssocFn
464        | DefKind::AssocTy
465        | DefKind::Trait
466        | DefKind::Fn => {
467            let is_trait = def_kind == DefKind::Trait;
468            let generics = genv
469                .fhir_get_generics(def_id.local_id())?
470                .ok_or_else(|| query_bug!(def_id.local_id(), "no generics for {def_id:?}"))?;
471            conv::conv_generics(genv, generics, def_id, is_trait)
472        }
473        DefKind::OpaqueTy
474        | DefKind::Closure
475        | DefKind::TraitAlias
476        | DefKind::Ctor(..)
477        | DefKind::Static { .. } => refining::refine_generics(&genv.lower_generics_of(def_id)),
478        kind => {
479            Err(query_bug!(
480                def_id.local_id(),
481                "generics_of called on `{def_id:?}` with kind `{kind:?}`"
482            ))?
483        }
484    };
485    if config::dump_rty() {
486        dbg::dump_item_info(genv.tcx(), def_id.resolved_id(), "generics.rty", &generics).unwrap();
487    }
488    Ok(generics)
489}
490
491/// See [`GlobalEnv::late_bound_refinement_params`]
492fn late_bound_refinement_params<'genv>(
493    genv: GlobalEnv<'genv, '_>,
494    def_id: LocalDefId,
495) -> QueryResult<&'genv [fhir::ParamId]> {
496    let node = genv.fhir_expect_owner_node(def_id)?;
497    let Some(fn_sig) = node.fn_sig() else { return Ok(&[]) };
498    let generics = node.generics();
499
500    // Where-clauses and opaque types are converted separately from the signature (as clauses of the
501    // item or the opaque type), so params mentioned there must be early bound.
502    let mut appears_in_clauses = ParamCollector::default();
503    for pred in generics.predicates.unwrap_or_default() {
504        appears_in_clauses.visit_where_predicate(pred);
505    }
506    OpaqueTyParamCollector(&mut appears_in_clauses).visit_fn_sig(fn_sig);
507
508    let late_bound = generics
509        .refinement_params
510        .iter()
511        // Locations are always early bound
512        .filter(|param| !param.kind.is_loc() && !matches!(param.sort, fhir::Sort::Loc))
513        .filter(|param| !appears_in_clauses.params.contains(&param.id))
514        .map(|param| param.id)
515        .collect_vec();
516    Ok(genv.alloc_slice(&late_bound))
517}
518
519/// Collects all refinement params mentioned in the visited nodes.
520#[derive(Default)]
521struct ParamCollector {
522    params: UnordSet<fhir::ParamId>,
523}
524
525impl<'fhir> fhir::visit::Visitor<'fhir> for ParamCollector {
526    fn visit_path_expr(&mut self, path: &fhir::PathExpr<'fhir>) {
527        if let fhir::Res::Param(_, id) = path.res {
528            self.params.insert(id);
529        }
530    }
531}
532
533/// Collects the refinement params mentioned in the bounds of opaque types.
534struct OpaqueTyParamCollector<'a>(&'a mut ParamCollector);
535
536impl<'fhir> fhir::visit::Visitor<'fhir> for OpaqueTyParamCollector<'_> {
537    fn visit_opaque_ty(&mut self, opaque_ty: &fhir::OpaqueTy<'fhir>) {
538        self.0.visit_opaque_ty(opaque_ty);
539    }
540}
541
542fn refinement_generics_of(
543    genv: GlobalEnv,
544    def_id: MaybeExternId,
545) -> QueryResult<rty::EarlyBinder<rty::RefinementGenerics>> {
546    let parent = genv.tcx().generics_of(def_id).parent;
547    let parent_count =
548        if let Some(def_id) = parent { genv.refinement_generics_of(def_id)?.count() } else { 0 };
549    let generics = match genv.fhir_node(def_id.local_id())? {
550        fhir::Node::Item(fhir::Item {
551            kind: fhir::ItemKind::Fn(..) | fhir::ItemKind::TyAlias(..),
552            ..
553        })
554        | fhir::Node::TraitItem(fhir::TraitItem { kind: fhir::TraitItemKind::Fn(..), .. })
555        | fhir::Node::ImplItem(fhir::ImplItem { kind: fhir::ImplItemKind::Fn(..), .. })
556        | fhir::Node::ForeignItem(fhir::ForeignItem {
557            kind: fhir::ForeignItemKind::Fn(..), ..
558        }) => {
559            let wfckresults = genv.check_wf(def_id.local_id())?;
560            let (early, _) = genv.fhir_split_refinement_params(def_id.local_id())?;
561            let params = conv::conv_refinement_generics(&early, &wfckresults)?;
562            rty::RefinementGenerics { parent, parent_count, own_params: params }
563        }
564        _ => rty::RefinementGenerics { parent, parent_count, own_params: rty::List::empty() },
565    };
566    Ok(rty::EarlyBinder(generics))
567}
568
569fn type_of(genv: GlobalEnv, def_id: MaybeExternId) -> QueryResult<rty::EarlyBinder<rty::TyOrCtor>> {
570    let ty = match genv.def_kind(def_id) {
571        DefKind::TyAlias => {
572            let fhir_ty_alias = genv
573                .fhir_expect_item(def_id.local_id())?
574                .expect_type_alias();
575            let wfckresults = genv.check_wf(def_id.local_id())?;
576            let mut cx = AfterSortck::new(genv, &wfckresults).into_conv_ctxt();
577            let ty_alias = cx.conv_type_alias(def_id, fhir_ty_alias)?;
578            struct_compat::type_alias(genv, fhir_ty_alias, &ty_alias, def_id)?;
579            rty::TyOrCtor::Ctor(ty_alias)
580        }
581        DefKind::TyParam => {
582            match def_id {
583                MaybeExternId::Local(local_id) => {
584                    let owner = genv.tcx().hir_ty_param_owner(local_id);
585                    let param = genv.fhir_get_generics(owner)?.unwrap().get_param(local_id);
586                    match param.kind {
587                        fhir::GenericParamKind::Type { default: Some(ty) } => {
588                            let parent = genv.tcx().local_parent(local_id);
589                            let wfckresults = genv.check_wf(parent)?;
590                            conv::conv_default_type_parameter(genv, def_id, &ty, &wfckresults)?
591                                .into()
592                        }
593                        k => Err(query_bug!(local_id, "non-type def def {k:?} {def_id:?}"))?,
594                    }
595                }
596                MaybeExternId::Extern(_, extern_id) => {
597                    let ty = genv.lower_type_of(extern_id)?.skip_binder();
598                    Refiner::default_for_item(genv, ty_param_owner(genv, extern_id))?
599                        .refine_ty_or_base(&ty)?
600                        .into()
601                }
602            }
603        }
604        DefKind::Impl { .. } | DefKind::Struct | DefKind::Enum | DefKind::AssocTy => {
605            let ty = genv.lower_type_of(def_id)?.skip_binder();
606            Refiner::default_for_item(genv, def_id.resolved_id())?
607                .refine_ty_or_base(&ty)?
608                .into()
609        }
610        kind => {
611            Err(query_bug!(
612                def_id.local_id(),
613                "`{:?}` not supported",
614                kind.descr(def_id.resolved_id())
615            ))?
616        }
617    };
618    Ok(rty::EarlyBinder(ty))
619}
620
621fn ty_param_owner(genv: GlobalEnv, def_id: DefId) -> DefId {
622    let def_kind = genv.def_kind(def_id);
623    match def_kind {
624        DefKind::Trait | DefKind::TraitAlias => def_id,
625        DefKind::LifetimeParam | DefKind::TyParam | DefKind::ConstParam => {
626            genv.tcx().parent(def_id)
627        }
628        _ => bug!("ty_param_owner: {:?} is a {:?} not a type parameter", def_id, def_kind),
629    }
630}
631
632fn variants_of(
633    genv: GlobalEnv,
634    def_id: MaybeExternId,
635) -> QueryResult<rty::Opaqueness<rty::EarlyBinder<rty::PolyVariants>>> {
636    let local_id = def_id.local_id();
637
638    let item = &genv.fhir_expect_item(local_id)?;
639    let variants = match &item.kind {
640        fhir::ItemKind::Enum(enum_def) => {
641            let wfckresults = genv.check_wf(local_id)?;
642            let mut cx = AfterSortck::new(genv, &wfckresults).into_conv_ctxt();
643            let variants = cx.conv_enum_variants(def_id, enum_def)?;
644            let variants = rty::List::from_vec(struct_compat::variants(genv, &variants, def_id)?);
645            rty::Opaqueness::Transparent(rty::EarlyBinder(variants))
646        }
647        fhir::ItemKind::Struct(struct_def) => {
648            let wfckresults = genv.check_wf(local_id)?;
649            let mut cx = AfterSortck::new(genv, &wfckresults).into_conv_ctxt();
650            cx.conv_struct_variant(def_id, struct_def)?
651                .map(|variant| -> QueryResult<_> {
652                    let variants = struct_compat::variants(genv, &[variant], def_id)?;
653                    Ok(rty::List::from_vec(variants))
654                })
655                .transpose()?
656                .map(rty::EarlyBinder)
657        }
658        _ => Err(query_bug!(def_id.local_id(), "expected struct or enum"))?,
659    };
660    if config::dump_rty() {
661        dbg::dump_item_info(genv.tcx(), def_id.resolved_id(), "rty", &variants).unwrap();
662    }
663    Ok(variants)
664}
665
666fn fn_sig(genv: GlobalEnv, def_id: MaybeExternId) -> QueryResult<rty::EarlyBinder<rty::PolyFnSig>> {
667    let fhir_node = genv.fhir_node(def_id.local_id())?;
668    match &fhir_node {
669        fhir::Node::Item(Item { kind: ItemKind::Fn(fhir_fn_sig, ..), .. })
670        | fhir::Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(fhir_fn_sig), .. })
671        | fhir::Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(fhir_fn_sig), .. })
672        | fhir::Node::ForeignItem(ForeignItem {
673            kind: ForeignItemKind::Fn(fhir_fn_sig, ..), ..
674        }) => {
675            let wfckresults = genv.check_wf(def_id.local_id())?;
676            let fn_sig = AfterSortck::new(genv, &wfckresults)
677                .into_conv_ctxt()
678                .conv_fn_sig(def_id, fhir_fn_sig)?;
679            let fn_sig = struct_compat::fn_sig(genv, fhir_fn_sig.decl, &fn_sig, def_id)?;
680            #[cfg(feature = "suggestions")]
681            let mut fn_sig = fn_sig.hoist_input_binders();
682            #[cfg(feature = "suggestions")]
683            // We aren't sure how to handle suggestions for Traits themselves
684            // and ForeignItems.
685            //
686            // Things get a bit messy with making ImplItem suggestions match the
687            // subtype for their parent trait, but for now we *will* offer them
688            // as suggestions; the user can resolve issues.
689            if !genv.no_suggestions(def_id.local_id())
690                && !matches!(fhir_node, fhir::Node::TraitItem(..) | fhir::Node::ForeignItem(..))
691            {
692                fn_sig = fn_sig.add_weak_kvars(genv, def_id.local_id().into())?;
693            }
694
695            if config::dump_rty() {
696                let generics = genv.generics_of(def_id)?;
697                let refinement_generics = genv.refinement_generics_of(def_id)?;
698                dbg::dump_item_info(
699                    genv.tcx(),
700                    def_id.resolved_id(),
701                    "rty",
702                    (generics, refinement_generics, &fn_sig),
703                )
704                .unwrap();
705            }
706            Ok(rty::EarlyBinder(fn_sig))
707        }
708        fhir::Node::Ctor => {
709            let tcx = genv.tcx();
710            let (adt_id, variant_idx) = match tcx.def_kind(def_id) {
711                DefKind::Ctor(CtorOf::Struct, _) => {
712                    let struct_id = tcx.parent(def_id.resolved_id());
713                    (struct_id, FIRST_VARIANT)
714                }
715                DefKind::Ctor(CtorOf::Variant, _) => {
716                    let variant_id = tcx.parent(def_id.resolved_id());
717                    let enum_id = tcx.parent(variant_id);
718                    let variant_idx = tcx.adt_def(enum_id).variant_index_with_id(variant_id);
719                    (enum_id, variant_idx)
720                }
721                _ => return Err(query_bug!("invalid `DefKind` for ctor node")),
722            };
723            genv.variant_sig(adt_id, variant_idx)?
724                .map(|sig| sig.to_poly_fn_sig(None))
725                .ok_or_query_err(adt_id)
726        }
727        node => Err(query_bug!("fn_sig called on unsupported node {node:?}")),
728    }
729}
730
731fn check_wf(genv: GlobalEnv, def_id: LocalDefId) -> QueryResult<Rc<WfckResults>> {
732    let node = genv.fhir_expect_owner_node(def_id)?;
733    let wfckresults = wf::check_node(genv, &node)?;
734    Ok(Rc::new(wfckresults))
735}
736
737mod errors {
738    use flux_errors::E0999;
739    use flux_macros::Diagnostic;
740    use flux_middle::def_id::FluxLocalDefId;
741    use rustc_span::Span;
742
743    #[derive(Diagnostic)]
744    #[diag("cycle in definitions", code = E0999)]
745    pub struct DefinitionCycle {
746        #[primary_span]
747        #[label("{$msg}")]
748        span: Span,
749        msg: String,
750    }
751
752    impl DefinitionCycle {
753        pub(super) fn new(span: Span, cycle: Vec<FluxLocalDefId>) -> Self {
754            let root = format!("`{}`", cycle[0].name());
755            let names: Vec<String> = cycle.iter().map(|s| format!("`{}`", s.name())).collect();
756            let msg = format!("{} -> {}", names.join(" -> "), root);
757            Self { span, msg }
758        }
759    }
760}