flux_fhir_analysis/conv/
mod.rs

1//! Conversion from types in [`fhir`] to types in [`rty`]
2//!
3//! Conversion assumes well-formedness and will panic if type are not well-formed. Among other things,
4//! well-formedness implies:
5//! 1. Names are bound correctly.
6//! 2. Refinement parameters appear in allowed positions. This is particularly important for
7//!    refinement predicates, aka abstract refinements, since the syntax in [`rty`] has
8//!    syntactic restrictions on predicates.
9//! 3. Refinements are well-sorted.
10
11pub mod struct_compat;
12use std::{borrow::Borrow, iter};
13
14use flux_common::{
15    bug,
16    dbg::{self, SpanTrace},
17    iter::IterExt,
18    result::ResultExt as _,
19    span_bug,
20};
21use flux_middle::{
22    THEORY_FUNCS,
23    def_id::{FluxDefId, MaybeExternId},
24    fhir::{self, FhirId, FluxOwnerId, QPathExpr},
25    global_env::GlobalEnv,
26    queries::{QueryErr, QueryResult},
27    query_bug,
28    rty::{
29        self, AssocReft, BoundReftKind, ESpan, INNERMOST, InternalFuncKind, List, RefineArgsExt,
30        WfckResults,
31        fold::TypeFoldable,
32        refining::{self, Refine, Refiner},
33    },
34};
35use flux_rustc_bridge::{
36    ToRustc,
37    lowering::{Lower, UnsupportedErr},
38};
39use itertools::Itertools;
40use rustc_data_structures::{
41    fx::{FxHashMap, FxIndexMap},
42    unord::UnordMap,
43};
44use rustc_errors::Diagnostic;
45use rustc_hash::FxHashSet;
46use rustc_hir::{self as hir, BodyId, OwnerId, Safety, def::DefKind, def_id::DefId};
47use rustc_index::IndexVec;
48use rustc_middle::{
49    middle::resolve_bound_vars::ResolvedArg,
50    ty::{self, AssocItem, AssocTag, BoundVar, TyCtxt},
51};
52use rustc_span::{
53    DUMMY_SP, ErrorGuaranteed, Span, Symbol,
54    symbol::{Ident, kw},
55};
56use rustc_trait_selection::traits;
57use rustc_type_ir::DebruijnIndex;
58
59/// Wrapper over a type implementing [`ConvPhase`]. We have this to implement most functionality as
60/// inherent methods instead of defining them as default implementation in the trait definition.
61#[repr(transparent)]
62pub struct ConvCtxt<P>(P);
63
64pub(crate) struct AfterSortck<'a, 'genv, 'tcx> {
65    genv: GlobalEnv<'genv, 'tcx>,
66    wfckresults: &'a WfckResults,
67    next_sort_index: u32,
68    next_type_index: u32,
69    next_region_index: u32,
70    next_const_index: u32,
71}
72
73/// We do conversion twice: once before sort checking when we don't have elaborated information
74/// and then again after sort checking after all information has been elaborated. This is the
75/// interface to configure conversion for both *phases*.
76pub trait ConvPhase<'genv, 'tcx>: Sized {
77    /// Whether to expand type aliases or to generate a *weak* [`rty::AliasTy`].
78    const EXPAND_TYPE_ALIASES: bool;
79
80    /// Whether we have elaborated information or not (in the first phase we will not, but in the
81    /// second we will).
82    const HAS_ELABORATED_INFORMATION: bool;
83
84    type Results: WfckResultsProvider;
85
86    fn genv(&self) -> GlobalEnv<'genv, 'tcx>;
87
88    fn owner(&self) -> FluxOwnerId;
89
90    fn next_sort_vid(&mut self) -> rty::SortVid;
91
92    fn next_type_vid(&mut self) -> rty::TyVid;
93
94    fn next_region_vid(&mut self) -> rty::RegionVid;
95
96    fn next_const_vid(&mut self) -> rty::ConstVid;
97
98    fn results(&self) -> &Self::Results;
99
100    /// Called during the first phase to collect the sort associated to a node which
101    /// would be hard to recompute from `fhir` otherwise. Currently, this is being
102    /// called when converting:
103    /// * An indexed type `b[e]` with the `fhir_id` and sort of `b`.
104    /// * A [`fhir::PathExpr`] with the `fhir_id` and sort of the path.
105    fn insert_node_sort(&mut self, fhir_id: FhirId, sort: rty::Sort);
106
107    /// Called after converting a path with the generic arguments. Using during the first phase
108    /// to instantiate sort of generic refinements.
109    fn insert_path_args(&mut self, fhir_id: FhirId, args: rty::GenericArgs);
110
111    /// Called after converting an [`fhir::ExprKind::Alias`] with the sort of the resulting
112    /// [`rty::AliasReft`]. Used during the first phase to collect the sorts of refinement aliases.
113    fn insert_alias_reft_sort(&mut self, fhir_id: FhirId, fsort: rty::FuncSort);
114
115    fn into_conv_ctxt(self) -> ConvCtxt<Self> {
116        ConvCtxt(self)
117    }
118
119    fn as_conv_ctxt(&mut self) -> &mut ConvCtxt<Self> {
120        // SAFETY: `ConvCtxt` is `repr(transparent)` and it doesn't have any safety invariants.
121        unsafe { std::mem::transmute(self) }
122    }
123}
124
125/// An interface to the information elaborated during sort checking. We mock these results in
126/// the first conversion phase during sort checking.
127pub trait WfckResultsProvider: Sized {
128    fn bin_op_sort(&self, fhir_id: FhirId) -> rty::Sort;
129
130    fn coercions_for(&self, fhir_id: FhirId) -> &[rty::Coercion];
131
132    fn field_proj(&self, fhir_id: FhirId) -> rty::FieldProj;
133
134    fn record_ctor(&self, fhir_id: FhirId) -> DefId;
135
136    fn param_sort(&self, param_id: fhir::ParamId) -> rty::Sort;
137
138    fn node_sort(&self, fhir_id: FhirId) -> rty::Sort;
139
140    fn node_sort_args(&self, fhir_id: FhirId) -> List<rty::SortArg>;
141}
142
143impl<'genv, 'tcx> ConvPhase<'genv, 'tcx> for AfterSortck<'_, 'genv, 'tcx> {
144    const EXPAND_TYPE_ALIASES: bool = true;
145    const HAS_ELABORATED_INFORMATION: bool = true;
146
147    type Results = WfckResults;
148
149    fn genv(&self) -> GlobalEnv<'genv, 'tcx> {
150        self.genv
151    }
152
153    fn owner(&self) -> FluxOwnerId {
154        self.wfckresults.owner
155    }
156
157    fn next_sort_vid(&mut self) -> rty::SortVid {
158        self.next_sort_index = self.next_sort_index.checked_add(1).unwrap();
159        rty::SortVid::from_u32(self.next_sort_index - 1)
160    }
161
162    fn next_type_vid(&mut self) -> rty::TyVid {
163        self.next_type_index = self.next_type_index.checked_add(1).unwrap();
164        rty::TyVid::from_u32(self.next_type_index - 1)
165    }
166
167    fn next_region_vid(&mut self) -> rty::RegionVid {
168        self.next_region_index = self.next_region_index.checked_add(1).unwrap();
169        rty::RegionVid::from_u32(self.next_region_index - 1)
170    }
171
172    fn next_const_vid(&mut self) -> rty::ConstVid {
173        self.next_const_index = self.next_const_index.checked_add(1).unwrap();
174        rty::ConstVid::from_u32(self.next_const_index - 1)
175    }
176
177    fn results(&self) -> &Self::Results {
178        self.wfckresults
179    }
180
181    fn insert_node_sort(&mut self, _: FhirId, _: rty::Sort) {}
182
183    fn insert_path_args(&mut self, _: FhirId, _: rty::GenericArgs) {}
184
185    fn insert_alias_reft_sort(&mut self, _: FhirId, _: rty::FuncSort) {}
186}
187
188impl WfckResultsProvider for WfckResults {
189    fn bin_op_sort(&self, fhir_id: FhirId) -> rty::Sort {
190        self.bin_op_sorts()
191            .get(fhir_id)
192            .cloned()
193            .unwrap_or_else(|| bug!("binary operation without elaborated sort `{fhir_id:?}`"))
194    }
195
196    fn coercions_for(&self, fhir_id: FhirId) -> &[rty::Coercion] {
197        self.coercions().get(fhir_id).map_or(&[][..], Vec::as_slice)
198    }
199
200    fn field_proj(&self, fhir_id: FhirId) -> rty::FieldProj {
201        *self
202            .field_projs()
203            .get(fhir_id)
204            .unwrap_or_else(|| bug!("field projection without elaboration `{fhir_id:?}`"))
205    }
206
207    fn record_ctor(&self, fhir_id: FhirId) -> DefId {
208        *self
209            .record_ctors()
210            .get(fhir_id)
211            .unwrap_or_else(|| bug!("unelaborated record constructor `{fhir_id:?}`"))
212    }
213
214    fn param_sort(&self, param_id: fhir::ParamId) -> rty::Sort {
215        self.param_sorts()
216            .get(&param_id)
217            .unwrap_or_else(|| bug!("unresolved sort for param `{param_id:?}`"))
218            .clone()
219    }
220
221    fn node_sort(&self, fhir_id: FhirId) -> rty::Sort {
222        self.node_sorts()
223            .get(fhir_id)
224            .unwrap_or_else(|| bug!("node without elaborated sort for `{fhir_id:?}`"))
225            .clone()
226    }
227
228    fn node_sort_args(&self, fhir_id: FhirId) -> List<rty::SortArg> {
229        self.fn_app_sorts()
230            .get(fhir_id)
231            .unwrap_or_else(|| bug!("fn-app node without elaborated sort_args for `{fhir_id:?}`"))
232            .clone()
233    }
234}
235
236#[derive(Debug)]
237pub(crate) struct Env {
238    layers: Vec<Layer>,
239    early_params: FxIndexMap<fhir::ParamId, Symbol>,
240}
241
242#[derive(Debug, Clone)]
243struct Layer {
244    map: FxIndexMap<fhir::ParamId, ParamEntry>,
245    kind: LayerKind,
246}
247
248/// Whether the list of parameters in a layer is converted into a list of bound variables or
249/// coalesced into a single parameter of [adt] sort.
250///
251/// [adt]: rty::SortCtor::Adt
252#[derive(Debug, Clone, Copy)]
253enum LayerKind {
254    List {
255        /// The number of regions bound in this layer. Since regions and refinements are both
256        /// bound with a [`rty::Binder`] we need to keep track of the number of bound regions
257        /// to skip them when assigning an index to refinement parameters.
258        bound_regions: u32,
259    },
260    Coalesce(DefId),
261}
262
263#[derive(Debug, Clone)]
264struct ParamEntry {
265    name: Symbol,
266    sort: rty::Sort,
267    mode: rty::InferMode,
268}
269
270#[derive(Debug)]
271struct LookupResult<'a> {
272    kind: LookupResultKind<'a>,
273    /// The span of the variable that originated the lookup.
274    var_span: Span,
275}
276
277#[derive(Debug)]
278enum LookupResultKind<'a> {
279    Bound {
280        debruijn: DebruijnIndex,
281        entry: &'a ParamEntry,
282        kind: LayerKind,
283        /// The index of the parameter in the layer.
284        index: u32,
285    },
286    EarlyParam {
287        name: Symbol,
288        /// The index of the parameter.
289        index: u32,
290    },
291}
292
293pub(crate) fn conv_adt_sort_def(
294    genv: GlobalEnv,
295    def_id: MaybeExternId,
296    kind: &fhir::RefinementKind,
297) -> QueryResult<rty::AdtSortDef> {
298    let wfckresults = &WfckResults::new(OwnerId { def_id: def_id.local_id() });
299    let mut cx = AfterSortck::new(genv, wfckresults).into_conv_ctxt();
300    match kind {
301        fhir::RefinementKind::Refined(refined_by) => {
302            let params = refined_by
303                .sort_params
304                .iter()
305                .map(|def_id| def_id_to_param_ty(genv, *def_id))
306                .collect();
307            let fields = refined_by
308                .fields
309                .iter()
310                .map(|(name, sort)| -> QueryResult<_> { Ok((*name, cx.conv_sort(sort)?)) })
311                .try_collect_vec()?;
312            let variants = IndexVec::from([rty::AdtSortVariant::new(fields)]);
313            let def_id = def_id.resolved_id();
314            Ok(rty::AdtSortDef::new(def_id, params, variants, false, true))
315        }
316        fhir::RefinementKind::Reflected => {
317            let enum_def_id = def_id.resolved_id();
318            let mut variants = IndexVec::new();
319            for variant in genv.tcx().adt_def(enum_def_id).variants() {
320                if let Some(field) = variant.fields.iter().next() {
321                    let span = genv.tcx().def_span(field.did);
322                    let err = genv
323                        .sess()
324                        .emit_err(errors::FieldsOnReflectedEnumVariant::new(span));
325                    Err(err)?;
326                }
327                variants.push(rty::AdtSortVariant::new(vec![]));
328            }
329            Ok(rty::AdtSortDef::new(enum_def_id, vec![], variants, true, false))
330        }
331    }
332}
333
334pub(crate) fn conv_generics(
335    genv: GlobalEnv,
336    generics: &fhir::Generics,
337    def_id: MaybeExternId,
338    is_trait: bool,
339) -> rty::Generics {
340    let opt_self = is_trait.then(|| {
341        let kind = rty::GenericParamDefKind::Base { has_default: false };
342        rty::GenericParamDef { index: 0, name: kw::SelfUpper, def_id: def_id.resolved_id(), kind }
343    });
344    let rust_generics = genv.tcx().generics_of(def_id.resolved_id());
345    let params = {
346        opt_self
347            .into_iter()
348            .chain(rust_generics.own_params.iter().flat_map(|rust_param| {
349                // We have to filter out late bound parameters
350                let param = generics
351                    .params
352                    .iter()
353                    .find(|param| param.def_id.resolved_id() == rust_param.def_id)?;
354                Some(rty::GenericParamDef {
355                    kind: conv_generic_param_kind(&param.kind),
356                    def_id: param.def_id.resolved_id(),
357                    index: rust_param.index,
358                    name: rust_param.name,
359                })
360            }))
361            .collect_vec()
362    };
363
364    let rust_generics = genv.tcx().generics_of(def_id.resolved_id());
365    rty::Generics {
366        own_params: List::from_vec(params),
367        parent: rust_generics.parent,
368        parent_count: rust_generics.parent_count,
369        has_self: rust_generics.has_self,
370    }
371}
372
373pub(crate) fn conv_refinement_generics(
374    params: &[fhir::RefineParam],
375    wfckresults: &WfckResults,
376) -> QueryResult<List<rty::RefineParam>> {
377    params
378        .iter()
379        .map(|param| {
380            let sort = wfckresults.param_sort(param.id);
381            let mode = rty::InferMode::from_param_kind(param.kind);
382            Ok(rty::RefineParam { sort, name: param.name, mode })
383        })
384        .try_collect()
385}
386
387fn conv_generic_param_kind(kind: &fhir::GenericParamKind) -> rty::GenericParamDefKind {
388    match kind {
389        fhir::GenericParamKind::Type { default } => {
390            rty::GenericParamDefKind::Base { has_default: default.is_some() }
391        }
392        fhir::GenericParamKind::Lifetime => rty::GenericParamDefKind::Lifetime,
393        fhir::GenericParamKind::Const { .. } => {
394            rty::GenericParamDefKind::Const { has_default: false }
395        }
396    }
397}
398
399pub(crate) fn conv_default_type_parameter(
400    genv: GlobalEnv,
401    def_id: MaybeExternId,
402    ty: &fhir::Ty,
403    wfckresults: &WfckResults,
404) -> QueryResult<rty::TyOrBase> {
405    let mut env = Env::new(&[]);
406    let idx = genv.def_id_to_param_index(def_id.resolved_id());
407    let owner = ty_param_owner(genv, def_id.resolved_id());
408    let param = genv.generics_of(owner)?.param_at(idx as usize, genv)?;
409    let mut cx = AfterSortck::new(genv, wfckresults).into_conv_ctxt();
410    let rty_ty = cx.conv_ty(&mut env, ty)?;
411    cx.try_to_ty_or_base(param.kind, ty.span, &rty_ty)
412}
413
414impl<'a, 'genv, 'tcx> AfterSortck<'a, 'genv, 'tcx> {
415    pub(crate) fn new(genv: GlobalEnv<'genv, 'tcx>, wfckresults: &'a WfckResults) -> Self {
416        Self {
417            genv,
418            wfckresults,
419            // We start sorts and types from 1 to skip the trait object dummy self type.
420            // See [`rty::Ty::trait_object_dummy_self`]
421            next_sort_index: 1,
422            next_type_index: 1,
423            next_region_index: 0,
424            next_const_index: 0,
425        }
426    }
427}
428
429/// Delegate methods to P
430impl<'genv, 'tcx: 'genv, P: ConvPhase<'genv, 'tcx>> ConvCtxt<P> {
431    fn genv(&self) -> GlobalEnv<'genv, 'tcx> {
432        self.0.genv()
433    }
434
435    fn tcx(&self) -> TyCtxt<'tcx> {
436        self.0.genv().tcx()
437    }
438
439    fn owner(&self) -> FluxOwnerId {
440        self.0.owner()
441    }
442
443    fn results(&self) -> &P::Results {
444        self.0.results()
445    }
446
447    fn next_sort_vid(&mut self) -> rty::SortVid {
448        self.0.next_sort_vid()
449    }
450
451    fn next_type_vid(&mut self) -> rty::TyVid {
452        self.0.next_type_vid()
453    }
454
455    fn next_region_vid(&mut self) -> rty::RegionVid {
456        self.0.next_region_vid()
457    }
458
459    fn next_const_vid(&mut self) -> rty::ConstVid {
460        self.0.next_const_vid()
461    }
462}
463
464fn variant_idx(tcx: TyCtxt, variant_def_id: DefId) -> rty::VariantIdx {
465    let enum_def_id = tcx.parent(variant_def_id);
466    tcx.adt_def(enum_def_id)
467        .variant_index_with_id(variant_def_id)
468}
469
470/// Conversion of Flux items
471impl<'genv, 'tcx: 'genv, P: ConvPhase<'genv, 'tcx>> ConvCtxt<P> {
472    pub(crate) fn conv_qualifier(
473        &mut self,
474        qualifier: &fhir::Qualifier,
475    ) -> QueryResult<rty::Qualifier> {
476        let mut env = Env::new(&[]);
477        env.push_layer(Layer::list(self.results(), 0, qualifier.args));
478        let body = self.conv_expr(&mut env, &qualifier.expr)?;
479        let body = rty::Binder::bind_with_vars(body, env.pop_layer().into_bound_vars(self.genv())?);
480        Ok(rty::Qualifier { def_id: qualifier.def_id, body, kind: qualifier.kind })
481    }
482
483    pub(crate) fn conv_defn(
484        &mut self,
485        func: &fhir::SpecFunc,
486    ) -> QueryResult<Option<rty::Binder<rty::Expr>>> {
487        if let Some(body) = &func.body {
488            let mut env = Env::new(&[]);
489            env.push_layer(Layer::list(self.results(), 0, func.args));
490            let expr = self.conv_expr(&mut env, body)?;
491            let body =
492                rty::Binder::bind_with_vars(expr, env.pop_layer().into_bound_vars(self.genv())?);
493            Ok(Some(body))
494        } else {
495            Ok(None)
496        }
497    }
498
499    pub(crate) fn conv_primop_prop(
500        &mut self,
501        primop_prop: &fhir::PrimOpProp,
502    ) -> QueryResult<rty::PrimOpProp> {
503        let mut env = Env::new(&[]);
504        env.push_layer(Layer::list(self.results(), 0, primop_prop.args));
505        let body = self.conv_expr(&mut env, &primop_prop.body)?;
506        let body = rty::Binder::bind_with_vars(body, env.pop_layer().into_bound_vars(self.genv())?);
507        let op = match primop_prop.op {
508            fhir::BinOp::BitAnd => rty::BinOp::BitAnd(rty::Sort::Int),
509            fhir::BinOp::BitOr => rty::BinOp::BitOr(rty::Sort::Int),
510            fhir::BinOp::BitXor => rty::BinOp::BitXor(rty::Sort::Int),
511            fhir::BinOp::BitShl => rty::BinOp::BitShl(rty::Sort::Int),
512            fhir::BinOp::BitShr => rty::BinOp::BitShr(rty::Sort::Int),
513            _ => {
514                span_bug!(
515                    primop_prop.span,
516                    "unexpected binary operator in primitive property: {:?}",
517                    primop_prop.op
518                )
519            }
520        };
521        Ok(rty::PrimOpProp { def_id: primop_prop.def_id, op, body })
522    }
523}
524
525/// Conversion of definitions
526impl<'genv, 'tcx: 'genv, P: ConvPhase<'genv, 'tcx>> ConvCtxt<P> {
527    pub(crate) fn conv_constant_expr(&mut self, expr: &fhir::Expr) -> QueryResult<rty::Expr> {
528        let mut env = Env::new(&[]);
529        self.conv_expr(&mut env, expr)
530    }
531
532    pub(crate) fn conv_enum_variants(
533        &mut self,
534        enum_id: MaybeExternId,
535        enum_def: &fhir::EnumDef,
536    ) -> QueryResult<Vec<rty::PolyVariant>> {
537        let reflected = enum_def.refinement.is_reflected();
538        enum_def
539            .variants
540            .iter()
541            .map(|variant| self.conv_enum_variant(enum_id, variant, reflected))
542            .try_collect_vec()
543    }
544
545    fn conv_enum_variant(
546        &mut self,
547        enum_id: MaybeExternId,
548        variant: &fhir::VariantDef,
549        reflected: bool,
550    ) -> QueryResult<rty::PolyVariant> {
551        let mut env = Env::new(&[]);
552        env.push_layer(Layer::list(self.results(), 0, variant.params));
553
554        // TODO(RJ): just "lift" the fields, ignore any `variant` signatures if reflected?
555        let fields = variant
556            .fields
557            .iter()
558            .map(|field| self.conv_ty(&mut env, &field.ty))
559            .try_collect()?;
560
561        let adt_def = self.genv().adt_def(enum_id)?;
562        let idxs = if reflected {
563            let enum_def_id = enum_id.resolved_id();
564            let idx = variant_idx(self.tcx(), variant.def_id.to_def_id());
565            rty::Expr::ctor_enum(enum_def_id, idx)
566        } else {
567            self.conv_expr(&mut env, &variant.ret.idx)?
568        };
569        let variant = rty::VariantSig::new(
570            adt_def,
571            rty::GenericArg::identity_for_item(self.genv(), enum_id.resolved_id())?,
572            fields,
573            idxs,
574            List::empty(),
575        );
576
577        Ok(rty::Binder::bind_with_vars(variant, env.pop_layer().into_bound_vars(self.genv())?))
578    }
579
580    pub(crate) fn conv_struct_variant(
581        &mut self,
582        struct_id: MaybeExternId,
583        struct_def: &fhir::StructDef,
584    ) -> QueryResult<rty::Opaqueness<rty::PolyVariant>> {
585        let mut env = Env::new(&[]);
586        env.push_layer(Layer::list(self.results(), 0, struct_def.params));
587
588        if let fhir::StructKind::Transparent { fields } = &struct_def.kind {
589            let adt_def = self.genv().adt_def(struct_id)?;
590
591            let fields = fields
592                .iter()
593                .map(|field_def| self.conv_ty(&mut env, &field_def.ty))
594                .try_collect()?;
595
596            let vars = env.pop_layer().into_bound_vars(self.genv())?;
597            let idx = rty::Expr::ctor_struct(
598                struct_id.resolved_id(),
599                (0..vars.len())
600                    .map(|idx| {
601                        rty::Expr::bvar(
602                            INNERMOST,
603                            BoundVar::from_usize(idx),
604                            rty::BoundReftKind::Anon,
605                        )
606                    })
607                    .collect(),
608            );
609
610            let requires = adt_def
611                .invariants()
612                .iter_identity()
613                .map(|inv| inv.apply(&idx))
614                .collect();
615
616            let variant = rty::VariantSig::new(
617                adt_def,
618                rty::GenericArg::identity_for_item(self.genv(), struct_id.resolved_id())?,
619                fields,
620                idx,
621                requires,
622            );
623            let variant = rty::Binder::bind_with_vars(variant, vars);
624            Ok(rty::Opaqueness::Transparent(variant))
625        } else {
626            Ok(rty::Opaqueness::Opaque)
627        }
628    }
629
630    pub(crate) fn conv_type_alias(
631        &mut self,
632        ty_alias_id: MaybeExternId,
633        ty_alias: &fhir::TyAlias,
634    ) -> QueryResult<rty::TyCtor> {
635        let generics = self
636            .genv()
637            .fhir_get_generics(ty_alias_id.local_id())?
638            .unwrap();
639
640        let mut env = Env::new(generics.refinement_params);
641
642        if let Some(index) = &ty_alias.index {
643            env.push_layer(Layer::list(self.results(), 0, std::slice::from_ref(index)));
644            let ty = self.conv_ty(&mut env, &ty_alias.ty)?;
645
646            Ok(rty::Binder::bind_with_vars(ty, env.pop_layer().into_bound_vars(self.genv())?))
647        } else {
648            let ctor = self
649                .conv_ty(&mut env, &ty_alias.ty)?
650                .shallow_canonicalize()
651                .as_ty_or_base()
652                .as_base()
653                .ok_or_else(|| self.emit(errors::InvalidBaseInstance::new(ty_alias.span)))?;
654            Ok(ctor.to_ty_ctor())
655        }
656    }
657
658    pub(crate) fn conv_fn_sig(
659        &mut self,
660        fn_id: MaybeExternId,
661        fn_sig: &fhir::FnSig,
662    ) -> QueryResult<rty::PolyFnSig> {
663        let decl = &fn_sig.decl;
664        let header = fn_sig.header;
665
666        let late_bound_regions =
667            refining::refine_bound_variables(&self.genv().lower_late_bound_vars(fn_id.local_id())?);
668
669        let generics = self.genv().fhir_get_generics(fn_id.local_id())?.unwrap();
670        let mut env = Env::new(generics.refinement_params);
671        env.push_layer(Layer::list(self.results(), late_bound_regions.len() as u32, &[]));
672
673        let body_id = self.tcx().hir_node_by_def_id(fn_id.local_id()).body_id();
674        let fn_sig = self.conv_fn_decl(&mut env, header.safety(), header.abi, decl, body_id)?;
675
676        let vars = late_bound_regions
677            .iter()
678            .chain(env.pop_layer().into_bound_vars(self.genv())?.iter())
679            .cloned()
680            .collect();
681
682        Ok(rty::PolyFnSig::bind_with_vars(fn_sig, vars))
683    }
684
685    pub(crate) fn conv_generic_predicates(
686        &mut self,
687        def_id: MaybeExternId,
688        generics: &fhir::Generics,
689    ) -> QueryResult<rty::EarlyBinder<rty::GenericPredicates>> {
690        let env = &mut Env::new(generics.refinement_params);
691
692        let predicates = if let Some(fhir_predicates) = generics.predicates {
693            let mut clauses = vec![];
694            for pred in fhir_predicates {
695                let span = pred.bounded_ty.span;
696                let bounded_ty = self.conv_ty(env, &pred.bounded_ty)?;
697                for clause in self.conv_generic_bounds(env, span, bounded_ty, pred.bounds)? {
698                    clauses.push(clause);
699                }
700            }
701            self.match_clauses(def_id, &clauses)?
702        } else {
703            self.genv()
704                .lower_predicates_of(def_id)?
705                .refine(&Refiner::default_for_item(self.genv(), def_id.resolved_id())?)?
706        };
707        Ok(rty::EarlyBinder(predicates))
708    }
709
710    fn match_clauses(
711        &self,
712        def_id: MaybeExternId,
713        refined_clauses: &[rty::Clause],
714    ) -> QueryResult<rty::GenericPredicates> {
715        let tcx = self.genv().tcx();
716        let predicates = tcx.predicates_of(def_id);
717        let unrefined_clauses = predicates.predicates;
718
719        // For each *refined clause* at index `j` find a corresponding *unrefined clause* at index
720        // `i` and save a mapping `i -> j`.
721        let mut map = UnordMap::default();
722        for (j, clause) in refined_clauses.iter().enumerate() {
723            let clause = clause.to_rustc(tcx);
724            let Some((i, _)) = unrefined_clauses.iter().find_position(|it| it.0 == clause) else {
725                self.emit_fail_to_match_predicates(def_id)?;
726            };
727            if map.insert(i, j).is_some() {
728                self.emit_fail_to_match_predicates(def_id)?;
729            }
730        }
731
732        // For each unrefined clause, create a default refined clause or use corresponding refined
733        // clause if one was found.
734        let refiner = Refiner::default_for_item(self.genv(), def_id.resolved_id())?;
735        let mut clauses = vec![];
736        for (i, (clause, span)) in unrefined_clauses.iter().enumerate() {
737            let clause = if let Some(j) = map.get(&i) {
738                refined_clauses[*j].clone()
739            } else {
740                clause
741                    .lower(tcx)
742                    .map_err(|reason| {
743                        let err = UnsupportedErr::new(reason).with_span(*span);
744                        QueryErr::unsupported(def_id.resolved_id(), err)
745                    })?
746                    .refine(&refiner)?
747            };
748            clauses.push(clause);
749        }
750
751        Ok(rty::GenericPredicates {
752            parent: predicates.parent,
753            predicates: List::from_vec(clauses),
754        })
755    }
756
757    fn emit_fail_to_match_predicates(&self, def_id: MaybeExternId) -> Result<!, ErrorGuaranteed> {
758        let span = self.tcx().def_span(def_id.resolved_id());
759        Err(self.emit(errors::FailToMatchPredicates { span }))
760    }
761
762    pub(crate) fn conv_opaque_ty(
763        &mut self,
764        opaque_ty: &fhir::OpaqueTy,
765    ) -> QueryResult<rty::Clauses> {
766        let def_id = opaque_ty.def_id;
767        let parent = self.tcx().local_parent(def_id.local_id());
768        let refparams = &self
769            .genv()
770            .fhir_get_generics(parent)?
771            .unwrap()
772            .refinement_params;
773
774        let env = &mut Env::new(refparams);
775
776        let args = rty::GenericArg::identity_for_item(self.genv(), def_id.resolved_id())?;
777        let alias_ty = rty::AliasTy::new(def_id.resolved_id(), args, env.to_early_param_args());
778        let self_ty = rty::BaseTy::opaque(alias_ty).to_ty();
779        // FIXME(nilehmann) use a good span here
780        Ok(self
781            .conv_generic_bounds(env, DUMMY_SP, self_ty, opaque_ty.bounds)?
782            .into_iter()
783            .collect())
784    }
785
786    pub(crate) fn conv_assoc_reft_body(
787        &mut self,
788        params: &[fhir::RefineParam],
789        body: &fhir::Expr,
790        output: &fhir::Sort,
791    ) -> QueryResult<rty::Lambda> {
792        let mut env = Env::new(&[]);
793        env.push_layer(Layer::list(self.results(), 0, params));
794        let expr = self.conv_expr(&mut env, body)?;
795        let output = self.conv_sort(output)?;
796        let inputs = env.pop_layer().into_bound_vars(self.genv())?;
797        Ok(rty::Lambda::bind_with_vars(expr, inputs, output))
798    }
799}
800
801/// Conversion of sorts
802impl<'genv, 'tcx: 'genv, P: ConvPhase<'genv, 'tcx>> ConvCtxt<P> {
803    pub(crate) fn conv_sort(&mut self, sort: &fhir::Sort) -> QueryResult<rty::Sort> {
804        let sort = match sort {
805            fhir::Sort::Path(path) => self.conv_sort_path(path)?,
806            fhir::Sort::BitVec(size) => rty::Sort::BitVec(rty::BvSize::Fixed(*size)),
807            fhir::Sort::Loc => rty::Sort::Loc,
808            fhir::Sort::Func(fsort) => rty::Sort::Func(self.conv_poly_func_sort(fsort)?),
809            fhir::Sort::SortOf(bty) => {
810                let rty::TyOrCtor::Ctor(ty_ctor) = self.conv_bty(&mut Env::empty(), bty, None)?
811                else {
812                    // FIXME: maybe we should have a dedicated error for this
813                    return Err(self.emit(errors::RefinedUnrefinableType::new(bty.span)))?;
814                };
815                ty_ctor.sort()
816            }
817            fhir::Sort::Infer => rty::Sort::Infer(self.next_sort_vid()),
818            fhir::Sort::Err(_) => rty::Sort::Err,
819        };
820        Ok(sort)
821    }
822
823    fn conv_poly_func_sort(&mut self, sort: &fhir::PolyFuncSort) -> QueryResult<rty::PolyFuncSort> {
824        let params = iter::repeat_n(rty::SortParamKind::Sort, sort.params).collect();
825        Ok(rty::PolyFuncSort::new(params, self.conv_func_sort(&sort.fsort)?))
826    }
827
828    fn conv_func_sort(&mut self, fsort: &fhir::FuncSort) -> QueryResult<rty::FuncSort> {
829        let inputs = fsort
830            .inputs()
831            .iter()
832            .map(|sort| self.conv_sort(sort))
833            .try_collect()?;
834        Ok(rty::FuncSort::new(inputs, self.conv_sort(fsort.output())?))
835    }
836
837    fn conv_sort_path(&mut self, path: &fhir::SortPath) -> QueryResult<rty::Sort> {
838        let ctor = match path.res {
839            fhir::SortRes::PrimSort(fhir::PrimSort::Int) => {
840                self.check_prim_sort_generics(path, fhir::PrimSort::Int)?;
841                return Ok(rty::Sort::Int);
842            }
843            fhir::SortRes::PrimSort(fhir::PrimSort::Bool) => {
844                self.check_prim_sort_generics(path, fhir::PrimSort::Bool)?;
845                return Ok(rty::Sort::Bool);
846            }
847            fhir::SortRes::PrimSort(fhir::PrimSort::Real) => {
848                self.check_prim_sort_generics(path, fhir::PrimSort::Real)?;
849                return Ok(rty::Sort::Real);
850            }
851            fhir::SortRes::PrimSort(fhir::PrimSort::Char) => {
852                self.check_prim_sort_generics(path, fhir::PrimSort::Char)?;
853                return Ok(rty::Sort::Char);
854            }
855            fhir::SortRes::PrimSort(fhir::PrimSort::Str) => {
856                self.check_prim_sort_generics(path, fhir::PrimSort::Str)?;
857                return Ok(rty::Sort::Str);
858            }
859            fhir::SortRes::SortParam(n) => return Ok(rty::Sort::Var(rty::ParamSort::from(n))),
860            fhir::SortRes::TyParam(def_id) => {
861                if !path.args.is_empty() {
862                    let err = errors::GenericsOnSortTyParam::new(
863                        path.segments.last().unwrap().span,
864                        path.args.len(),
865                    );
866                    Err(self.emit(err))?;
867                }
868                return Ok(rty::Sort::Param(def_id_to_param_ty(self.genv(), def_id)));
869            }
870            fhir::SortRes::SelfParam { .. } => {
871                if !path.args.is_empty() {
872                    let err = errors::GenericsOnSelf::new(
873                        path.segments.last().unwrap().span,
874                        path.args.len(),
875                    );
876                    Err(self.emit(err))?;
877                }
878                return Ok(rty::Sort::Param(rty::SELF_PARAM_TY));
879            }
880            fhir::SortRes::SelfAlias { alias_to } => {
881                if !path.args.is_empty() {
882                    let err = errors::GenericsOnSelf::new(
883                        path.segments.last().unwrap().span,
884                        path.args.len(),
885                    );
886                    Err(self.emit(err))?;
887                }
888                return Ok(self
889                    .genv()
890                    .sort_of_self_ty_alias(alias_to)?
891                    .unwrap_or(rty::Sort::Err));
892            }
893            fhir::SortRes::SelfParamAssoc { trait_id, ident } => {
894                let res = fhir::Res::SelfTyParam { trait_: trait_id };
895                let assoc_segment =
896                    fhir::PathSegment { args: &[], constraints: &[], ident, res: fhir::Res::Err };
897                let mut env = Env::empty();
898                let alias_ty =
899                    self.conv_type_relative_type_path(&mut env, ident.span, res, &assoc_segment)?;
900                return Ok(rty::Sort::Alias(rty::AliasKind::Projection, alias_ty));
901            }
902            fhir::SortRes::PrimSort(fhir::PrimSort::Set) => {
903                self.check_prim_sort_generics(path, fhir::PrimSort::Set)?;
904                rty::SortCtor::Set
905            }
906            fhir::SortRes::PrimSort(fhir::PrimSort::Map) => {
907                self.check_prim_sort_generics(path, fhir::PrimSort::Map)?;
908                rty::SortCtor::Map
909            }
910            fhir::SortRes::User(def_id) => {
911                self.check_user_defined_sort_param_count(path, def_id)?;
912                rty::SortCtor::User(def_id)
913            }
914            fhir::SortRes::Adt(def_id) => {
915                let sort_def = self.genv().adt_sort_def_of(def_id)?;
916                if path.args.len() != sort_def.param_count() {
917                    let err = errors::IncorrectGenericsOnSort::new(
918                        self.genv(),
919                        def_id,
920                        path.segments.last().unwrap().span,
921                        path.args.len(),
922                        sort_def.param_count(),
923                    );
924                    Err(self.emit(err))?;
925                }
926                rty::SortCtor::Adt(sort_def)
927            }
928        };
929        let args = path.args.iter().map(|t| self.conv_sort(t)).try_collect()?;
930
931        Ok(rty::Sort::app(ctor, args))
932    }
933
934    fn check_user_defined_sort_param_count(
935        &mut self,
936        path: &fhir::SortPath<'_>,
937        def_id: FluxDefId,
938    ) -> QueryResult {
939        let expected_param_count = self.genv().sort_decl_param_count(def_id);
940        if path.args.len() != expected_param_count {
941            let err = errors::IncorrectGenericsOnUserDefinedOpaqueSort::new(
942                path.segments.last().unwrap().span,
943                def_id.name(),
944                expected_param_count,
945                path.args.len(),
946            );
947            Err(self.emit(err))?;
948        }
949        Ok(())
950    }
951
952    fn check_prim_sort_generics(
953        &mut self,
954        path: &fhir::SortPath<'_>,
955        prim_sort: fhir::PrimSort,
956    ) -> QueryResult {
957        if path.args.len() != prim_sort.generics() {
958            let err = errors::GenericsOnPrimitiveSort::new(
959                path.segments.last().unwrap().span,
960                prim_sort.name_str(),
961                path.args.len(),
962                prim_sort.generics(),
963            );
964            Err(self.emit(err))?;
965        }
966        Ok(())
967    }
968}
969
970/// Conversion of types
971impl<'genv, 'tcx: 'genv, P: ConvPhase<'genv, 'tcx>> ConvCtxt<P> {
972    fn conv_fn_decl(
973        &mut self,
974        env: &mut Env,
975        safety: Safety,
976        abi: rustc_abi::ExternAbi,
977        decl: &fhir::FnDecl,
978        body_id: Option<BodyId>,
979    ) -> QueryResult<rty::FnSig> {
980        let mut requires = vec![];
981        for req in decl.requires {
982            requires.push(self.conv_requires(env, req)?);
983        }
984
985        let mut inputs = vec![];
986        let params =
987            if let Some(body_id) = body_id { self.tcx().hir_body(body_id).params } else { &[] };
988        for (i, ty) in decl.inputs.iter().enumerate() {
989            let ty = if let Some(param) = params.get(i)
990                && let hir::PatKind::Binding(_, _, ident, _) = param.pat.kind
991            {
992                self.conv_ty_with_name(env, ty, ident.name)?
993            } else {
994                self.conv_ty(env, ty)?
995            };
996            inputs.push(ty);
997        }
998
999        let output = self.conv_fn_output(env, &decl.output)?;
1000
1001        Ok(rty::FnSig::new(safety, abi, requires.into(), inputs.into(), output))
1002    }
1003
1004    fn conv_requires(
1005        &mut self,
1006        env: &mut Env,
1007        requires: &fhir::Requires,
1008    ) -> QueryResult<rty::Expr> {
1009        if requires.params.is_empty() {
1010            self.conv_expr(env, &requires.pred)
1011        } else {
1012            env.push_layer(Layer::list(self.results(), 0, requires.params));
1013            let pred = self.conv_expr(env, &requires.pred)?;
1014            let sorts = env.pop_layer().into_bound_vars(self.genv())?;
1015            Ok(rty::Expr::forall(rty::Binder::bind_with_vars(pred, sorts)))
1016        }
1017    }
1018
1019    fn conv_ensures(
1020        &mut self,
1021        env: &mut Env,
1022        ensures: &fhir::Ensures,
1023    ) -> QueryResult<rty::Ensures> {
1024        match ensures {
1025            fhir::Ensures::Type(loc, ty) => {
1026                Ok(rty::Ensures::Type(self.conv_loc(env, *loc)?, self.conv_ty(env, ty)?))
1027            }
1028            fhir::Ensures::Pred(pred) => Ok(rty::Ensures::Pred(self.conv_expr(env, pred)?)),
1029        }
1030    }
1031
1032    fn conv_fn_output(
1033        &mut self,
1034        env: &mut Env,
1035        output: &fhir::FnOutput,
1036    ) -> QueryResult<rty::Binder<rty::FnOutput>> {
1037        env.push_layer(Layer::list(self.results(), 0, output.params));
1038
1039        let ret = self.conv_ty(env, &output.ret)?;
1040
1041        let ensures: List<rty::Ensures> = output
1042            .ensures
1043            .iter()
1044            .map(|ens| self.conv_ensures(env, ens))
1045            .try_collect()?;
1046        let output = rty::FnOutput::new(ret, ensures);
1047
1048        let vars = env.pop_layer().into_bound_vars(self.genv())?;
1049        Ok(rty::Binder::bind_with_vars(output, vars))
1050    }
1051
1052    fn conv_generic_bounds(
1053        &mut self,
1054        env: &mut Env,
1055        bounded_ty_span: Span,
1056        bounded_ty: rty::Ty,
1057        bounds: fhir::GenericBounds,
1058    ) -> QueryResult<Vec<rty::Clause>> {
1059        let mut clauses = vec![];
1060        for bound in bounds {
1061            match bound {
1062                fhir::GenericBound::Trait(poly_trait_ref) => {
1063                    match poly_trait_ref.modifiers {
1064                        fhir::TraitBoundModifier::None => {
1065                            self.conv_poly_trait_ref(
1066                                env,
1067                                bounded_ty_span,
1068                                &bounded_ty,
1069                                poly_trait_ref,
1070                                &mut clauses,
1071                            )?;
1072                        }
1073                        fhir::TraitBoundModifier::Maybe => {
1074                            // Maybe bounds are only supported for `?Sized`. The effect of the maybe
1075                            // bound is to relax the default which is `Sized` to not have the `Sized`
1076                            // bound, so we just skip it here.
1077                        }
1078                    }
1079                }
1080                fhir::GenericBound::Outlives(lft) => {
1081                    let re = self.conv_lifetime(env, *lft, bounded_ty_span);
1082                    clauses.push(rty::Clause::new(
1083                        List::empty(),
1084                        rty::ClauseKind::TypeOutlives(rty::OutlivesPredicate(
1085                            bounded_ty.clone(),
1086                            re,
1087                        )),
1088                    ));
1089                }
1090            }
1091        }
1092        Ok(clauses)
1093    }
1094
1095    /// Converts a `T: Trait<T0, ..., A0 = S0, ...>` bound
1096    fn conv_poly_trait_ref(
1097        &mut self,
1098        env: &mut Env,
1099        span: Span,
1100        bounded_ty: &rty::Ty,
1101        poly_trait_ref: &fhir::PolyTraitRef,
1102        clauses: &mut Vec<rty::Clause>,
1103    ) -> QueryResult {
1104        let generic_params = &poly_trait_ref.bound_generic_params;
1105        let layer =
1106            Layer::list(self.results(), generic_params.len() as u32, poly_trait_ref.refine_params);
1107        env.push_layer(layer);
1108
1109        let trait_id = poly_trait_ref.trait_def_id();
1110        let generics = self.genv().generics_of(trait_id)?;
1111        let trait_segment = poly_trait_ref.trait_ref.last_segment();
1112
1113        let self_param = generics.param_at(0, self.genv())?;
1114        let mut args = vec![
1115            self.try_to_ty_or_base(self_param.kind, span, bounded_ty)?
1116                .into(),
1117        ];
1118        self.conv_generic_args_into(env, trait_id, trait_segment, &mut args)?;
1119
1120        let vars = env.top_layer().to_bound_vars(self.genv())?;
1121        let poly_trait_ref = rty::Binder::bind_with_vars(
1122            rty::TraitRef { def_id: trait_id, args: args.into() },
1123            vars,
1124        );
1125
1126        clauses.push(
1127            poly_trait_ref
1128                .clone()
1129                .map(|trait_ref| {
1130                    rty::ClauseKind::Trait(rty::TraitPredicate { trait_ref: trait_ref.clone() })
1131                })
1132                .into(),
1133        );
1134
1135        for cstr in trait_segment.constraints {
1136            self.conv_assoc_item_constraint(env, &poly_trait_ref, cstr, clauses)?;
1137        }
1138
1139        env.pop_layer();
1140
1141        Ok(())
1142    }
1143
1144    fn conv_assoc_item_constraint(
1145        &mut self,
1146        env: &mut Env,
1147        poly_trait_ref: &rty::PolyTraitRef,
1148        constraint: &fhir::AssocItemConstraint,
1149        clauses: &mut Vec<rty::Clause>,
1150    ) -> QueryResult {
1151        let tcx = self.tcx();
1152
1153        let candidate = self.probe_single_bound_for_assoc_item(
1154            || traits::supertraits(tcx, poly_trait_ref.to_rustc(tcx)),
1155            constraint.ident,
1156            AssocTag::Type,
1157        )?;
1158        let assoc_item_id = AssocTag::Type
1159            .trait_defines_item_named(self.genv(), candidate.def_id(), constraint.ident)?
1160            .unwrap()
1161            .def_id;
1162
1163        let fhir::AssocItemConstraintKind::Equality { term } = &constraint.kind;
1164        let span = term.span;
1165        let term = self.conv_ty(env, term)?;
1166        let term = self.ty_to_subset_ty_ctor(span, &term)?;
1167
1168        let clause = poly_trait_ref
1169            .clone()
1170            .map(|trait_ref| {
1171                // TODO: when we support generic associated types, we need to also attach the associated generics here
1172                let args = trait_ref.args;
1173                let refine_args = List::empty();
1174                let projection_ty = rty::AliasTy { def_id: assoc_item_id, args, refine_args };
1175
1176                rty::ClauseKind::Projection(rty::ProjectionPredicate { projection_ty, term })
1177            })
1178            .into();
1179
1180        clauses.push(clause);
1181        Ok(())
1182    }
1183
1184    fn conv_ty_with_name(
1185        &mut self,
1186        env: &mut Env,
1187        ty: &fhir::Ty,
1188        name: Symbol,
1189    ) -> QueryResult<rty::Ty> {
1190        if let fhir::TyKind::BaseTy(bty) = &ty.kind {
1191            Ok(self.conv_bty(env, bty, Some(name))?.to_ty())
1192        } else {
1193            self.conv_ty(env, ty)
1194        }
1195    }
1196
1197    fn conv_ty(&mut self, env: &mut Env, ty: &fhir::Ty) -> QueryResult<rty::Ty> {
1198        match &ty.kind {
1199            fhir::TyKind::BaseTy(bty) => Ok(self.conv_bty(env, bty, None)?.to_ty()),
1200            fhir::TyKind::Indexed(bty, idx) => {
1201                let fhir_id = bty.fhir_id;
1202                let rty::TyOrCtor::Ctor(ty_ctor) = self.conv_bty(env, bty, None)? else {
1203                    return Err(self.emit(errors::RefinedUnrefinableType::new(bty.span)))?;
1204                };
1205                let idx = self.conv_expr(env, idx)?;
1206                self.0.insert_node_sort(fhir_id, ty_ctor.sort());
1207                Ok(ty_ctor.replace_bound_reft(&idx))
1208            }
1209            fhir::TyKind::Exists(params, ty) => {
1210                let layer = Layer::list(self.results(), 0, params);
1211                env.push_layer(layer);
1212                let ty = self.conv_ty(env, ty)?;
1213                let sorts = env.pop_layer().into_bound_vars(self.genv())?;
1214                if sorts.is_empty() {
1215                    Ok(ty.shift_out_escaping(1))
1216                } else {
1217                    Ok(rty::Ty::exists(rty::Binder::bind_with_vars(ty, sorts)))
1218                }
1219            }
1220            fhir::TyKind::StrgRef(lft, loc, ty) => {
1221                let re = self.conv_lifetime(env, *lft, ty.span);
1222                let loc = self.conv_loc(env, **loc)?;
1223                let ty = self.conv_ty(env, ty)?;
1224                Ok(rty::Ty::strg_ref(re, loc, ty))
1225            }
1226            fhir::TyKind::Ref(lft, fhir::MutTy { ty, mutbl }) => {
1227                let region = self.conv_lifetime(env, *lft, ty.span);
1228                Ok(rty::Ty::mk_ref(region, self.conv_ty(env, ty)?, *mutbl))
1229            }
1230            fhir::TyKind::BareFn(bare_fn) => {
1231                let mut env = Env::empty();
1232                env.push_layer(Layer::list(
1233                    self.results(),
1234                    bare_fn.generic_params.len() as u32,
1235                    &[],
1236                ));
1237                let fn_sig =
1238                    self.conv_fn_decl(&mut env, bare_fn.safety, bare_fn.abi, bare_fn.decl, None)?;
1239                let vars = bare_fn
1240                    .generic_params
1241                    .iter()
1242                    .map(|param| self.param_as_bound_var(param))
1243                    .try_collect()?;
1244                let poly_fn_sig = rty::Binder::bind_with_vars(fn_sig, vars);
1245                Ok(rty::BaseTy::FnPtr(poly_fn_sig).to_ty())
1246            }
1247            fhir::TyKind::Tuple(tys) => {
1248                let tys: List<rty::Ty> =
1249                    tys.iter().map(|ty| self.conv_ty(env, ty)).try_collect()?;
1250                Ok(rty::Ty::tuple(tys))
1251            }
1252            fhir::TyKind::Array(ty, len) => {
1253                Ok(rty::Ty::array(self.conv_ty(env, ty)?, self.conv_const_arg(*len)))
1254            }
1255            fhir::TyKind::Never => Ok(rty::Ty::never()),
1256            fhir::TyKind::Constr(pred, ty) => {
1257                let pred = self.conv_expr(env, pred)?;
1258                Ok(rty::Ty::constr(pred, self.conv_ty(env, ty)?))
1259            }
1260            fhir::TyKind::RawPtr(ty, mutability) => {
1261                Ok(rty::Ty::indexed(
1262                    rty::BaseTy::RawPtr(self.conv_ty(env, ty)?, *mutability),
1263                    rty::Expr::unit(),
1264                ))
1265            }
1266            fhir::TyKind::OpaqueDef(opaque_ty) => self.conv_opaque_def(env, opaque_ty, ty.span),
1267            fhir::TyKind::TraitObject(trait_bounds, lft, syn) => {
1268                if matches!(syn, rustc_ast::TraitObjectSyntax::Dyn) {
1269                    self.conv_trait_object(env, trait_bounds, *lft, ty.span)
1270                } else {
1271                    span_bug!(ty.span, "dyn* traits not supported yet")
1272                }
1273            }
1274            fhir::TyKind::Infer => Ok(rty::Ty::infer(self.next_type_vid())),
1275            fhir::TyKind::Err(err) => Err(QueryErr::Emitted(*err)),
1276        }
1277    }
1278
1279    /// Code adapted from <https://github.com/rust-lang/rust/blob/b5723af3457b9cd3795eeb97e9af2d34964854f2/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs#L2099>
1280    fn conv_opaque_def(
1281        &mut self,
1282        env: &mut Env,
1283        opaque_ty: &fhir::OpaqueTy,
1284        span: Span,
1285    ) -> QueryResult<rty::Ty> {
1286        let def_id = opaque_ty.def_id;
1287
1288        if P::HAS_ELABORATED_INFORMATION {
1289            let lifetimes = self.tcx().opaque_captured_lifetimes(def_id.local_id());
1290
1291            let generics = self.tcx().generics_of(opaque_ty.def_id);
1292
1293            let offset = generics.parent_count;
1294
1295            let args = rty::GenericArg::for_item(self.genv(), def_id.resolved_id(), |param, _| {
1296                if let Some(i) = (param.index as usize).checked_sub(offset) {
1297                    let (lifetime, _) = lifetimes[i];
1298                    rty::GenericArg::Lifetime(self.conv_resolved_lifetime(env, lifetime, span))
1299                } else {
1300                    rty::GenericArg::from_param_def(param)
1301                }
1302            })?;
1303            let reft_args = rty::RefineArgs::identity_for_item(self.genv(), def_id.resolved_id())?;
1304            let alias_ty = rty::AliasTy::new(def_id.resolved_id(), args, reft_args);
1305            Ok(rty::BaseTy::opaque(alias_ty).to_ty())
1306        } else {
1307            // During sortck we need to run conv on the opaque type to collect sorts for base types
1308            // in the opaque type's bounds. After sortck, we don't need to because opaque types are
1309            // converted as part of `genv.item_bounds`.
1310            self.conv_opaque_ty(opaque_ty)?;
1311
1312            // `RefineArgs::identity_for_item` uses `genv.refinement_generics_of` which in turn
1313            // requires `genv.check_wf`, so we simply return all empty here to avoid the circularity
1314            let alias_ty = rty::AliasTy::new(def_id.resolved_id(), List::empty(), List::empty());
1315            Ok(rty::BaseTy::opaque(alias_ty).to_ty())
1316        }
1317    }
1318
1319    fn conv_trait_object(
1320        &mut self,
1321        env: &mut Env,
1322        trait_bounds: &[fhir::PolyTraitRef],
1323        lifetime: fhir::Lifetime,
1324        span: Span,
1325    ) -> QueryResult<rty::Ty> {
1326        // We convert all the trait bounds into existential predicates. Some combinations won't yield
1327        // valid rust types (e.g., only one regular (non-auto) trait is allowed). We don't detect those
1328        // errors here, but that's fine because we should catch them when we check structural
1329        // compatibility with the unrefined rust type. We must be careful with producing predicates
1330        // in the same order that rustc does.
1331
1332        let mut bounds = vec![];
1333        let dummy_self = rty::Ty::trait_object_dummy_self();
1334        for trait_bound in trait_bounds.iter().rev() {
1335            self.conv_poly_trait_ref(env, trait_bound.span, &dummy_self, trait_bound, &mut bounds)?;
1336        }
1337
1338        // Separate trait bounds and projections bounds
1339        let mut trait_bounds = vec![];
1340        let mut projection_bounds = vec![];
1341        for pred in bounds {
1342            let bound_pred = pred.kind();
1343            let vars = bound_pred.vars().clone();
1344            match bound_pred.skip_binder() {
1345                rty::ClauseKind::Trait(trait_pred) => {
1346                    trait_bounds.push(rty::Binder::bind_with_vars(trait_pred.trait_ref, vars));
1347                }
1348                rty::ClauseKind::Projection(proj) => {
1349                    projection_bounds.push(rty::Binder::bind_with_vars(proj, vars));
1350                }
1351                rty::ClauseKind::RegionOutlives(_) => {}
1352                rty::ClauseKind::TypeOutlives(_) => {}
1353                rty::ClauseKind::ConstArgHasType(..) => {
1354                    bug!("did not expect {pred:?} clause in object bounds");
1355                }
1356            }
1357        }
1358
1359        // Separate between regular from auto traits
1360        let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) = trait_bounds
1361            .into_iter()
1362            .partition(|trait_ref| self.tcx().trait_is_auto(trait_ref.def_id()));
1363
1364        // De-duplicate auto traits preserving order
1365        {
1366            let mut duplicates = FxHashSet::default();
1367            auto_traits.retain(|trait_ref| duplicates.insert(trait_ref.def_id()));
1368        }
1369
1370        let regular_trait_predicates = regular_traits.into_iter().map(|poly_trait_ref| {
1371            poly_trait_ref.map(|trait_ref| {
1372                // Remove dummy self
1373                let args = trait_ref.args.iter().skip(1).cloned().collect();
1374                rty::ExistentialPredicate::Trait(rty::ExistentialTraitRef {
1375                    def_id: trait_ref.def_id,
1376                    args,
1377                })
1378            })
1379        });
1380
1381        let auto_trait_predicates = auto_traits.into_iter().map(|trait_def| {
1382            rty::Binder::dummy(rty::ExistentialPredicate::AutoTrait(trait_def.def_id()))
1383        });
1384
1385        let existential_projections = projection_bounds.into_iter().map(|bound| {
1386            bound.map(|proj| {
1387                // Remove dummy self
1388                let args = proj.projection_ty.args.iter().skip(1).cloned().collect();
1389                rty::ExistentialPredicate::Projection(rty::ExistentialProjection {
1390                    def_id: proj.projection_ty.def_id,
1391                    args,
1392                    term: proj.term.clone(),
1393                })
1394            })
1395        });
1396
1397        let existential_predicates = {
1398            let mut v = regular_trait_predicates
1399                .chain(existential_projections)
1400                .chain(auto_trait_predicates)
1401                .collect_vec();
1402            v.sort_by(|a, b| {
1403                a.as_ref()
1404                    .skip_binder()
1405                    .stable_cmp(self.tcx(), b.as_ref().skip_binder())
1406            });
1407            List::from_vec(v)
1408        };
1409
1410        let region = self.conv_lifetime(env, lifetime, span);
1411        Ok(rty::Ty::dynamic(existential_predicates, region))
1412    }
1413
1414    pub(crate) fn conv_bty(
1415        &mut self,
1416        env: &mut Env,
1417        bty: &fhir::BaseTy,
1418        name: Option<Symbol>,
1419    ) -> QueryResult<rty::TyOrCtor> {
1420        match &bty.kind {
1421            fhir::BaseTyKind::Path(fhir::QPath::Resolved(qself, path)) => {
1422                self.conv_qpath(env, *qself, path, name)
1423            }
1424            fhir::BaseTyKind::Path(fhir::QPath::TypeRelative(qself, segment)) => {
1425                let qself_res =
1426                    if let Some(path) = qself.as_path() { path.res } else { fhir::Res::Err };
1427                let alias_ty = self
1428                    .conv_type_relative_type_path(env, qself.span, qself_res, segment)?
1429                    .shift_in_escaping(1);
1430                let bty = rty::BaseTy::Alias(rty::AliasKind::Projection, alias_ty);
1431                let sort = bty.sort();
1432                let ty = rty::Ty::indexed(bty, rty::Expr::nu());
1433                Ok(rty::TyOrCtor::Ctor(rty::Binder::bind_with_sort(ty, sort)))
1434            }
1435            fhir::BaseTyKind::Slice(ty) => {
1436                let bty = rty::BaseTy::Slice(self.conv_ty(env, ty)?).shift_in_escaping(1);
1437                let sort = bty.sort();
1438                let ty = rty::Ty::indexed(bty, rty::Expr::nu());
1439                Ok(rty::TyOrCtor::Ctor(rty::Binder::bind_with_sort(ty, sort)))
1440            }
1441            fhir::BaseTyKind::Err(err) => Err(QueryErr::Emitted(*err)),
1442        }
1443    }
1444
1445    fn conv_type_relative_path<Tag: AssocItemTag>(
1446        &mut self,
1447        tag: Tag,
1448        qself_span: Span,
1449        qself_res: fhir::Res,
1450        assoc_ident: Ident,
1451    ) -> QueryResult<(Tag::AssocItem<'tcx>, rty::TraitRef)> {
1452        let tcx = self.tcx();
1453
1454        let bound = match qself_res {
1455            fhir::Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true } => {
1456                let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) else {
1457                    // A cycle error occurred most likely (comment copied from rustc)
1458                    span_bug!(qself_span, "expected cycle error");
1459                };
1460
1461                self.probe_single_bound_for_assoc_item(
1462                    || {
1463                        traits::supertraits(
1464                            tcx,
1465                            ty::Binder::dummy(trait_ref.instantiate_identity()),
1466                        )
1467                    },
1468                    assoc_ident,
1469                    tag,
1470                )?
1471            }
1472            fhir::Res::Def(DefKind::TyParam, param_id)
1473            | fhir::Res::SelfTyParam { trait_: param_id } => {
1474                let predicates = type_param_predicates(tcx, param_id);
1475                self.probe_single_bound_for_assoc_item(
1476                    || {
1477                        tag.transitive_bounds_that_define_assoc_item(
1478                            self.genv(),
1479                            predicates.map(|pred| pred.map_bound(|t| t.trait_ref)),
1480                            assoc_ident,
1481                        )
1482                    },
1483                    assoc_ident,
1484                    tag,
1485                )?
1486            }
1487            _ => self.report_assoc_item_not_found(assoc_ident.span, tag)?,
1488        };
1489
1490        let Some(trait_ref) = bound.no_bound_vars() else {
1491            // This is a programmer error and we should gracefully report it. It's triggered
1492            // by code like this
1493            // ```
1494            // trait Super<'a> { type Assoc; }
1495            // trait Child: for<'a> Super<'a> {}
1496            // fn foo<T: Child>(x: T::Assoc) {}
1497            // ```
1498            Err(self.emit(
1499                query_bug!("associated path with uninferred generic parameters")
1500                    .at(assoc_ident.span),
1501            ))?
1502        };
1503
1504        let trait_ref = trait_ref
1505            .lower(tcx)
1506            .map_err(|err| QueryErr::unsupported(trait_ref.def_id, err.into_err()))?
1507            .refine(&self.refiner()?)?;
1508
1509        let assoc_item = tag
1510            .trait_defines_item_named(self.genv(), trait_ref.def_id, assoc_ident)?
1511            .unwrap();
1512
1513        Ok((assoc_item, trait_ref))
1514    }
1515
1516    fn conv_type_relative_type_path(
1517        &mut self,
1518        env: &mut Env,
1519        qself_span: Span,
1520        qself_res: fhir::Res,
1521        assoc_segment: &fhir::PathSegment,
1522    ) -> QueryResult<rty::AliasTy> {
1523        let (assoc_item, trait_ref) = self.conv_type_relative_path(
1524            AssocTag::Type,
1525            qself_span,
1526            qself_res,
1527            assoc_segment.ident,
1528        )?;
1529
1530        let assoc_id = assoc_item.def_id;
1531        let mut args = trait_ref.args.to_vec();
1532        self.conv_generic_args_into(env, assoc_id, assoc_segment, &mut args)?;
1533
1534        let args = List::from_vec(args);
1535        let refine_args = List::empty();
1536        let alias_ty = rty::AliasTy { args, refine_args, def_id: assoc_id };
1537        Ok(alias_ty)
1538    }
1539
1540    fn conv_type_relative_const_path(
1541        &mut self,
1542        fhir_expr: &fhir::Expr,
1543        qself: &rty::Ty,
1544        assoc: Ident,
1545    ) -> QueryResult<rty::Expr> {
1546        let tcx = self.genv().tcx();
1547
1548        let mut candidates = vec![];
1549        if let Some(simplified_type) = qself.simplify_type() {
1550            candidates = tcx
1551                .incoherent_impls(simplified_type)
1552                .iter()
1553                .filter_map(|impl_id| {
1554                    tcx.associated_items(impl_id).find_by_ident_and_kind(
1555                        tcx,
1556                        assoc,
1557                        AssocTag::Const,
1558                        *impl_id,
1559                    )
1560                })
1561                .collect_vec();
1562        }
1563        let (expr, sort) = match &candidates[..] {
1564            [candidate] => self.conv_const(fhir_expr.span, candidate.def_id)?,
1565            [] => self.report_assoc_item_not_found(fhir_expr.span, AssocTag::Const)?,
1566            _ => self.report_ambiguous_assoc_item(fhir_expr.span, AssocTag::Const, assoc)?,
1567        };
1568        self.0.insert_node_sort(fhir_expr.fhir_id, sort);
1569        Ok(expr)
1570    }
1571
1572    /// Return the generics of the containing owner item
1573    fn refiner(&self) -> QueryResult<Refiner<'genv, 'tcx>> {
1574        match self.owner() {
1575            FluxOwnerId::Rust(owner_id) => {
1576                let def_id = self.genv().maybe_extern_id(owner_id.def_id);
1577                Refiner::default_for_item(self.genv(), def_id.resolved_id())
1578            }
1579            FluxOwnerId::Flux(_) => Err(query_bug!("cannot refine types insicde flux item")),
1580        }
1581    }
1582
1583    fn probe_single_bound_for_assoc_item<I, Tag: AssocItemTag>(
1584        &self,
1585        all_candidates: impl FnOnce() -> I,
1586        assoc_name: Ident,
1587        tag: Tag,
1588    ) -> QueryResult<ty::PolyTraitRef<'tcx>>
1589    where
1590        I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
1591    {
1592        let mut matching_candidates = vec![];
1593        for candidate in all_candidates() {
1594            if tag
1595                .trait_defines_item_named(self.genv(), candidate.def_id(), assoc_name)?
1596                .is_some()
1597            {
1598                matching_candidates.push(candidate);
1599            }
1600        }
1601
1602        let Some(bound) = matching_candidates.pop() else {
1603            self.report_assoc_item_not_found(assoc_name.span, tag)?;
1604        };
1605
1606        if !matching_candidates.is_empty() {
1607            self.report_ambiguous_assoc_item(assoc_name.span, tag, assoc_name)?;
1608        }
1609
1610        Ok(bound)
1611    }
1612
1613    fn conv_lifetime(&mut self, env: &Env, lft: fhir::Lifetime, span: Span) -> rty::Region {
1614        let res = match lft {
1615            fhir::Lifetime::Hole(_) => return rty::Region::ReVar(self.next_region_vid()),
1616            fhir::Lifetime::Resolved(res) => res,
1617        };
1618        self.conv_resolved_lifetime(env, res, span)
1619    }
1620
1621    fn conv_resolved_lifetime(&mut self, env: &Env, res: ResolvedArg, span: Span) -> rty::Region {
1622        let tcx = self.tcx();
1623        let lifetime_name = |def_id| tcx.item_name(def_id);
1624        match res {
1625            ResolvedArg::StaticLifetime => rty::ReStatic,
1626            ResolvedArg::EarlyBound(def_id) => {
1627                let index = self.genv().def_id_to_param_index(def_id.to_def_id());
1628                let name = lifetime_name(def_id.to_def_id());
1629                rty::ReEarlyParam(rty::EarlyParamRegion { index, name })
1630            }
1631            ResolvedArg::LateBound(_, index, def_id) => {
1632                let Some(depth) = env.depth().checked_sub(1) else {
1633                    span_bug!(span, "late-bound variable at depth 0")
1634                };
1635                let kind = rty::BoundRegionKind::Named(def_id.to_def_id());
1636                let var = BoundVar::from_u32(index);
1637                let bound_region = rty::BoundRegion { var, kind };
1638                rty::ReBound(rty::DebruijnIndex::from_usize(depth), bound_region)
1639            }
1640            ResolvedArg::Free(scope, id) => {
1641                let kind = rty::LateParamRegionKind::Named(id.to_def_id());
1642                rty::ReLateParam(rty::LateParamRegion { scope: scope.to_def_id(), kind })
1643            }
1644            ResolvedArg::Error(_) => bug!("lifetime resolved to an error"),
1645        }
1646    }
1647
1648    fn conv_const_arg(&mut self, cst: fhir::ConstArg) -> rty::Const {
1649        match cst.kind {
1650            fhir::ConstArgKind::Lit(lit) => rty::Const::from_usize(self.tcx(), lit),
1651            fhir::ConstArgKind::Param(def_id) => {
1652                rty::Const {
1653                    kind: rty::ConstKind::Param(def_id_to_param_const(self.genv(), def_id)),
1654                }
1655            }
1656            fhir::ConstArgKind::Infer => {
1657                rty::Const {
1658                    kind: rty::ConstKind::Infer(ty::InferConst::Var(self.next_const_vid())),
1659                }
1660            }
1661        }
1662    }
1663
1664    fn conv_qpath(
1665        &mut self,
1666        env: &mut Env,
1667        qself: Option<&fhir::Ty>,
1668        path: &fhir::Path,
1669        name: Option<Symbol>,
1670    ) -> QueryResult<rty::TyOrCtor> {
1671        let bty = match path.res {
1672            fhir::Res::PrimTy(prim_ty) => {
1673                self.check_prim_ty_generics(path, prim_ty)?;
1674                prim_ty_to_bty(prim_ty)
1675            }
1676            fhir::Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, did) => {
1677                let adt_def = self.genv().adt_def(did)?;
1678                let args = self.conv_generic_args(env, did, path.last_segment())?;
1679                rty::BaseTy::adt(adt_def, args)
1680            }
1681            fhir::Res::Def(DefKind::TyParam, def_id) => {
1682                let owner_id = ty_param_owner(self.genv(), def_id);
1683                let param_ty = def_id_to_param_ty(self.genv(), def_id);
1684                self.check_ty_param_generics(path, param_ty)?;
1685                let param = self
1686                    .genv()
1687                    .generics_of(owner_id)?
1688                    .param_at(param_ty.index as usize, self.genv())?;
1689                match param.kind {
1690                    rty::GenericParamDefKind::Type { .. } => {
1691                        return Ok(rty::TyOrCtor::Ty(rty::Ty::param(param_ty)));
1692                    }
1693                    rty::GenericParamDefKind::Base { .. } => rty::BaseTy::Param(param_ty),
1694                    _ => return Err(query_bug!("unexpected param kind")),
1695                }
1696            }
1697            fhir::Res::SelfTyParam { trait_ } => {
1698                self.check_self_ty_generics(path)?;
1699                let param = &self.genv().generics_of(trait_)?.own_params[0];
1700                match param.kind {
1701                    rty::GenericParamDefKind::Type { .. } => {
1702                        return Ok(rty::TyOrCtor::Ty(rty::Ty::param(rty::SELF_PARAM_TY)));
1703                    }
1704                    rty::GenericParamDefKind::Base { .. } => rty::BaseTy::Param(rty::SELF_PARAM_TY),
1705                    _ => return Err(query_bug!("unexpected param kind")),
1706                }
1707            }
1708            fhir::Res::SelfTyAlias { alias_to, .. } => {
1709                self.check_self_ty_generics(path)?;
1710                if P::EXPAND_TYPE_ALIASES {
1711                    return Ok(self.genv().type_of(alias_to)?.instantiate_identity());
1712                } else {
1713                    rty::BaseTy::Alias(
1714                        rty::AliasKind::Free,
1715                        rty::AliasTy {
1716                            def_id: alias_to,
1717                            args: List::empty(),
1718                            refine_args: List::empty(),
1719                        },
1720                    )
1721                }
1722            }
1723            fhir::Res::Def(DefKind::AssocTy, assoc_id) => {
1724                let trait_id = self.tcx().trait_of_assoc(assoc_id).unwrap();
1725
1726                let [.., trait_segment, assoc_segment] = path.segments else {
1727                    span_bug!(path.span, "expected at least two segments");
1728                };
1729
1730                let Some(qself) = qself else {
1731                    self.report_ambiguous_assoc_item(
1732                        path.span,
1733                        AssocTag::Type,
1734                        assoc_segment.ident,
1735                    )?
1736                };
1737
1738                let trait_generics = self.genv().generics_of(trait_id)?;
1739                let qself =
1740                    self.conv_ty_to_generic_arg(env, &trait_generics.own_params[0], qself)?;
1741                let mut args = vec![qself];
1742                self.conv_generic_args_into(env, trait_id, trait_segment, &mut args)?;
1743                self.conv_generic_args_into(env, assoc_id, assoc_segment, &mut args)?;
1744                let args = List::from_vec(args);
1745
1746                let refine_args = List::empty();
1747                let alias_ty = rty::AliasTy { args, refine_args, def_id: assoc_id };
1748                rty::BaseTy::Alias(rty::AliasKind::Projection, alias_ty)
1749            }
1750            fhir::Res::Def(DefKind::TyAlias, def_id) => {
1751                self.check_refinement_generics(path, def_id)?;
1752                let args = self.conv_generic_args(env, def_id, path.last_segment())?;
1753                self.0.insert_path_args(path.fhir_id, args.clone());
1754                let refine_args = path
1755                    .refine
1756                    .iter()
1757                    .map(|expr| self.conv_expr(env, expr))
1758                    .try_collect_vec()?;
1759
1760                if P::EXPAND_TYPE_ALIASES {
1761                    let tcx = self.tcx();
1762                    return Ok(self
1763                        .genv()
1764                        .type_of(def_id)?
1765                        .instantiate(tcx, &args, &refine_args));
1766                } else {
1767                    rty::BaseTy::Alias(
1768                        rty::AliasKind::Free,
1769                        rty::AliasTy { def_id, args, refine_args: List::from(refine_args) },
1770                    )
1771                }
1772            }
1773            fhir::Res::Def(DefKind::ForeignTy, def_id) => {
1774                self.check_foreign_ty_generics(path)?;
1775                rty::BaseTy::Foreign(def_id)
1776            }
1777            fhir::Res::Def(kind, def_id) => self.report_expected_type(path.span, kind, def_id)?,
1778            fhir::Res::Param(..) | fhir::Res::GlobalFunc(..) | fhir::Res::Err => {
1779                span_bug!(path.span, "unexpected resolution in conv_ty_ctor: {:?}", path.res)
1780            }
1781        };
1782        let sort = bty.sort();
1783        let bty = bty.shift_in_escaping(1);
1784        let kind = match name {
1785            Some(name) => BoundReftKind::Named(name),
1786            None => BoundReftKind::Anon,
1787        };
1788        let var = rty::BoundVariableKind::Refine(sort, rty::InferMode::EVar, kind);
1789        let ctor = rty::Binder::bind_with_vars(
1790            rty::Ty::indexed(bty, rty::Expr::nu()),
1791            List::singleton(var),
1792        );
1793        Ok(rty::TyOrCtor::Ctor(ctor))
1794    }
1795
1796    fn param_as_bound_var(
1797        &mut self,
1798        param: &fhir::GenericParam,
1799    ) -> QueryResult<rty::BoundVariableKind> {
1800        let def_id = param.def_id.resolved_id();
1801        match param.kind {
1802            fhir::GenericParamKind::Lifetime => {
1803                Ok(rty::BoundVariableKind::Region(rty::BoundRegionKind::Named(def_id)))
1804            }
1805            fhir::GenericParamKind::Const { .. } | fhir::GenericParamKind::Type { .. } => {
1806                Err(query_bug!(def_id, "unsupported param kind `{:?}`", param.kind))
1807            }
1808        }
1809    }
1810
1811    fn conv_generic_args(
1812        &mut self,
1813        env: &mut Env,
1814        def_id: DefId,
1815        segment: &fhir::PathSegment,
1816    ) -> QueryResult<List<rty::GenericArg>> {
1817        let mut into = vec![];
1818        self.conv_generic_args_into(env, def_id, segment, &mut into)?;
1819        Ok(List::from(into))
1820    }
1821
1822    fn conv_generic_args_into(
1823        &mut self,
1824        env: &mut Env,
1825        def_id: DefId,
1826        segment: &fhir::PathSegment,
1827        into: &mut Vec<rty::GenericArg>,
1828    ) -> QueryResult {
1829        let generics = self.genv().generics_of(def_id)?;
1830
1831        self.check_generic_arg_count(&generics, def_id, segment)?;
1832
1833        let len = into.len();
1834        for (idx, arg) in segment.args.iter().enumerate() {
1835            let param = generics.param_at(idx + len, self.genv())?;
1836            match arg {
1837                fhir::GenericArg::Lifetime(lft) => {
1838                    into.push(rty::GenericArg::Lifetime(self.conv_lifetime(
1839                        env,
1840                        *lft,
1841                        segment.ident.span,
1842                    )));
1843                }
1844                fhir::GenericArg::Type(ty) => {
1845                    into.push(self.conv_ty_to_generic_arg(env, &param, ty)?);
1846                }
1847                fhir::GenericArg::Const(cst) => {
1848                    into.push(rty::GenericArg::Const(self.conv_const_arg(*cst)));
1849                }
1850                fhir::GenericArg::Infer => {
1851                    into.push(self.conv_generic_arg_hole(env, param, segment.ident.span)?);
1852                }
1853            }
1854        }
1855        self.fill_generic_args_defaults(def_id, into)
1856    }
1857
1858    fn conv_generic_arg_hole(
1859        &mut self,
1860        env: &mut Env,
1861        param: rty::GenericParamDef,
1862        span: Span,
1863    ) -> QueryResult<rty::GenericArg> {
1864        match param.kind {
1865            rty::GenericParamDefKind::Type { .. } | rty::GenericParamDefKind::Base { .. } => {
1866                let ty = fhir::Ty { kind: fhir::TyKind::Infer, span };
1867                Ok(self.conv_ty_to_generic_arg(env, &param, &ty)?)
1868            }
1869            rty::GenericParamDefKind::Const { .. } => {
1870                let cst = fhir::ConstArg { kind: fhir::ConstArgKind::Infer, span };
1871                Ok(rty::GenericArg::Const(self.conv_const_arg(cst)))
1872            }
1873            rty::GenericParamDefKind::Lifetime => {
1874                let re = rty::Region::ReVar(self.next_region_vid());
1875                Ok(rty::GenericArg::Lifetime(re))
1876            }
1877        }
1878    }
1879
1880    fn check_generic_arg_count(
1881        &mut self,
1882        generics: &rty::Generics,
1883        def_id: DefId,
1884        segment: &fhir::PathSegment,
1885    ) -> QueryResult {
1886        let found = segment.args.len();
1887        let mut param_count = generics.own_params.len();
1888
1889        // The self parameter is not provided explicitly in the path so we skip it
1890        if let DefKind::Trait = self.genv().def_kind(def_id) {
1891            param_count -= 1;
1892        }
1893
1894        let min = param_count - generics.own_default_count();
1895        let max = param_count;
1896        if min == max && found != min {
1897            Err(self.emit(errors::GenericArgCountMismatch::new(
1898                self.genv(),
1899                def_id,
1900                segment,
1901                min,
1902            )))?;
1903        }
1904        if found < min {
1905            Err(self.emit(errors::TooFewGenericArgs::new(self.genv(), def_id, segment, min)))?;
1906        }
1907        if found > max {
1908            Err(self.emit(errors::TooManyGenericArgs::new(self.genv(), def_id, segment, min)))?;
1909        }
1910        Ok(())
1911    }
1912
1913    fn fill_generic_args_defaults(
1914        &mut self,
1915        def_id: DefId,
1916        into: &mut Vec<rty::GenericArg>,
1917    ) -> QueryResult {
1918        let generics = self.genv().generics_of(def_id)?;
1919        for param in generics.own_params.iter().skip(into.len()) {
1920            debug_assert!(matches!(
1921                param.kind,
1922                rty::GenericParamDefKind::Type { has_default: true }
1923                    | rty::GenericParamDefKind::Base { has_default: true }
1924            ));
1925            let span = self.tcx().def_span(param.def_id);
1926            // FIXME(nilehmann) we already know whether this is a type or a constructor so we could
1927            // directly check if the constructor returns a subset type.
1928            let ty = self
1929                .genv()
1930                .type_of(param.def_id)?
1931                .instantiate(self.tcx(), into, &[])
1932                .to_ty();
1933            into.push(self.try_to_ty_or_base(param.kind, span, &ty)?.into());
1934        }
1935        Ok(())
1936    }
1937
1938    fn conv_ty_to_generic_arg(
1939        &mut self,
1940        env: &mut Env,
1941        param: &rty::GenericParamDef,
1942        ty: &fhir::Ty,
1943    ) -> QueryResult<rty::GenericArg> {
1944        let rty_ty = self.conv_ty(env, ty)?;
1945        Ok(self.try_to_ty_or_base(param.kind, ty.span, &rty_ty)?.into())
1946    }
1947
1948    fn try_to_ty_or_base(
1949        &mut self,
1950        kind: rty::GenericParamDefKind,
1951        span: Span,
1952        ty: &rty::Ty,
1953    ) -> QueryResult<rty::TyOrBase> {
1954        match kind {
1955            rty::GenericParamDefKind::Type { .. } => Ok(rty::TyOrBase::Ty(ty.clone())),
1956            rty::GenericParamDefKind::Base { .. } => {
1957                Ok(rty::TyOrBase::Base(self.ty_to_subset_ty_ctor(span, ty)?))
1958            }
1959            _ => span_bug!(span, "unexpected param kind `{kind:?}`"),
1960        }
1961    }
1962
1963    fn ty_to_subset_ty_ctor(&mut self, span: Span, ty: &rty::Ty) -> QueryResult<rty::SubsetTyCtor> {
1964        let ctor = if let rty::TyKind::Infer(vid) = ty.kind() {
1965            // do not generate sort holes for dummy self types
1966            let sort_vid =
1967                if vid.as_u32() == 0 { rty::SortVid::from_u32(0) } else { self.next_sort_vid() };
1968            rty::SubsetTyCtor::bind_with_sort(
1969                rty::SubsetTy::trivial(rty::BaseTy::Infer(*vid), rty::Expr::nu()),
1970                rty::Sort::Infer(sort_vid),
1971            )
1972        } else {
1973            ty.shallow_canonicalize()
1974                .as_ty_or_base()
1975                .as_base()
1976                .ok_or_else(|| self.emit(errors::InvalidBaseInstance::new(span)))?
1977        };
1978        Ok(ctor)
1979    }
1980
1981    #[track_caller]
1982    fn emit(&self, err: impl Diagnostic<'genv>) -> ErrorGuaranteed {
1983        self.genv().sess().emit_err(err)
1984    }
1985
1986    fn report_assoc_item_not_found<Tag: AssocItemTag>(
1987        &self,
1988        span: Span,
1989        assoc_tag: Tag,
1990    ) -> Result<!, ErrorGuaranteed> {
1991        Err(self.emit(errors::AssocItemNotFound { span, tag: assoc_tag.descr() }))?
1992    }
1993
1994    fn report_ambiguous_assoc_item<Tag: AssocItemTag>(
1995        &self,
1996        span: Span,
1997        assoc_tag: Tag,
1998        assoc_name: Ident,
1999    ) -> Result<!, ErrorGuaranteed> {
2000        Err(self.emit(errors::AmbiguousAssocItem {
2001            span,
2002            name: assoc_name,
2003            tag: assoc_tag.descr(),
2004        }))?
2005    }
2006
2007    #[track_caller]
2008    fn report_expected_type(
2009        &self,
2010        span: Span,
2011        kind: DefKind,
2012        def_id: DefId,
2013    ) -> Result<!, ErrorGuaranteed> {
2014        Err(self.emit(errors::ExpectedType {
2015            span,
2016            def_descr: self.tcx().def_kind_descr(kind, def_id),
2017            name: self.tcx().def_path_str(def_id),
2018        }))?
2019    }
2020}
2021
2022/// Check generic params for types
2023impl<'genv, 'tcx: 'genv, P: ConvPhase<'genv, 'tcx>> ConvCtxt<P> {
2024    fn check_refinement_generics(&mut self, path: &fhir::Path, def_id: DefId) -> QueryResult {
2025        let generics = self.genv().refinement_generics_of(def_id)?;
2026        if generics.count() != path.refine.len() {
2027            let err = errors::RefineArgMismatch {
2028                span: path.span,
2029                expected: generics.count(),
2030                found: path.refine.len(),
2031                kind: self.tcx().def_descr(def_id),
2032            };
2033            Err(self.emit(err))?;
2034        }
2035        Ok(())
2036    }
2037
2038    fn check_prim_ty_generics(
2039        &mut self,
2040        path: &fhir::Path<'_>,
2041        prim_ty: rustc_hir::PrimTy,
2042    ) -> QueryResult {
2043        if !path.last_segment().args.is_empty() {
2044            let err = errors::GenericsOnPrimTy { span: path.span, name: prim_ty.name_str() };
2045            Err(self.emit(err))?;
2046        }
2047        Ok(())
2048    }
2049
2050    fn check_ty_param_generics(
2051        &mut self,
2052        path: &fhir::Path<'_>,
2053        param_ty: rty::ParamTy,
2054    ) -> QueryResult {
2055        if !path.last_segment().args.is_empty() {
2056            let err = errors::GenericsOnTyParam { span: path.span, name: param_ty.name };
2057            Err(self.emit(err))?;
2058        }
2059        Ok(())
2060    }
2061
2062    fn check_self_ty_generics(&mut self, path: &fhir::Path<'_>) -> QueryResult {
2063        if !path.last_segment().args.is_empty() {
2064            let err = errors::GenericsOnSelfTy { span: path.span };
2065            Err(self.emit(err))?;
2066        }
2067        Ok(())
2068    }
2069
2070    fn check_foreign_ty_generics(&mut self, path: &fhir::Path<'_>) -> QueryResult {
2071        if !path.last_segment().args.is_empty() {
2072            let err = errors::GenericsOnForeignTy { span: path.span };
2073            Err(self.emit(err))?;
2074        }
2075        Ok(())
2076    }
2077}
2078
2079fn prim_ty_to_bty(prim_ty: rustc_hir::PrimTy) -> rty::BaseTy {
2080    match prim_ty {
2081        rustc_hir::PrimTy::Int(int_ty) => rty::BaseTy::Int(int_ty),
2082        rustc_hir::PrimTy::Uint(uint_ty) => rty::BaseTy::Uint(uint_ty),
2083        rustc_hir::PrimTy::Float(float_ty) => rty::BaseTy::Float(float_ty),
2084        rustc_hir::PrimTy::Str => rty::BaseTy::Str,
2085        rustc_hir::PrimTy::Bool => rty::BaseTy::Bool,
2086        rustc_hir::PrimTy::Char => rty::BaseTy::Char,
2087    }
2088}
2089
2090/// Conversion of expressions
2091impl<'genv, 'tcx: 'genv, P: ConvPhase<'genv, 'tcx>> ConvCtxt<P> {
2092    fn conv_lit(&self, lit: fhir::Lit, fhir_id: FhirId, span: Span) -> QueryResult<rty::Constant> {
2093        match lit {
2094            fhir::Lit::Int(n, kind) => {
2095                match kind {
2096                    Some(fhir::NumLitKind::Int) => Ok(rty::Constant::from(n)),
2097                    Some(fhir::NumLitKind::Real) => Ok(rty::Constant::Real(rty::Real(n))),
2098                    None => {
2099                        let sort = self.results().node_sort(fhir_id);
2100                        if let rty::Sort::BitVec(bvsize) = sort {
2101                            if let rty::BvSize::Fixed(size) = bvsize
2102                                && (n == 0 || n.ilog2() < size)
2103                            {
2104                                Ok(rty::Constant::BitVec(n, size))
2105                            } else {
2106                                Err(self.emit(errors::InvalidBitVectorConstant::new(span, sort)))?
2107                            }
2108                        } else {
2109                            Ok(rty::Constant::from(n))
2110                        }
2111                    }
2112                }
2113            }
2114            fhir::Lit::Bool(b) => Ok(rty::Constant::from(b)),
2115            fhir::Lit::Str(s) => Ok(rty::Constant::from(s)),
2116            fhir::Lit::Char(c) => Ok(rty::Constant::from(c)),
2117        }
2118    }
2119
2120    fn conv_expr(&mut self, env: &mut Env, expr: &fhir::Expr) -> QueryResult<rty::Expr> {
2121        let fhir_id = expr.fhir_id;
2122        let espan = ESpan::new(expr.span);
2123        let expr = match expr.kind {
2124            fhir::ExprKind::Var(QPathExpr::Resolved(path, _)) => self.conv_path_expr(env, path)?,
2125            fhir::ExprKind::Var(QPathExpr::TypeRelative(qself, assoc)) => {
2126                let qself = self.conv_ty(env, qself)?;
2127                self.conv_type_relative_const_path(expr, &qself, assoc)?
2128            }
2129            fhir::ExprKind::Literal(lit) => {
2130                rty::Expr::constant(self.conv_lit(lit, fhir_id, expr.span)?).at(espan)
2131            }
2132            fhir::ExprKind::BinaryOp(op, e1, e2) => {
2133                rty::Expr::binary_op(
2134                    self.conv_bin_op(op, expr.fhir_id),
2135                    self.conv_expr(env, e1)?,
2136                    self.conv_expr(env, e2)?,
2137                )
2138                .at(espan)
2139            }
2140            fhir::ExprKind::UnaryOp(op, e) => {
2141                rty::Expr::unary_op(conv_un_op(op), self.conv_expr(env, e)?).at(espan)
2142            }
2143
2144            fhir::ExprKind::PrimApp(op, e1, e2) => {
2145                rty::Expr::prim_val(
2146                    self.conv_primop_val(op),
2147                    self.conv_expr(env, e1)?,
2148                    self.conv_expr(env, e2)?,
2149                )
2150                .at(espan)
2151            }
2152            fhir::ExprKind::App(func, args) => {
2153                let sort_args = self.results().node_sort_args(fhir_id);
2154                rty::Expr::app(self.conv_func(env, &func)?, sort_args, self.conv_exprs(env, args)?)
2155                    .at(espan)
2156            }
2157            fhir::ExprKind::Alias(alias, args) => {
2158                let args = args
2159                    .iter()
2160                    .map(|arg| self.conv_expr(env, arg))
2161                    .try_collect()?;
2162                let alias = self.conv_alias_reft(env, expr.fhir_id, &alias)?;
2163                rty::Expr::alias(alias, args).at(espan)
2164            }
2165            fhir::ExprKind::IfThenElse(p, e1, e2) => {
2166                rty::Expr::ite(
2167                    self.conv_expr(env, p)?,
2168                    self.conv_expr(env, e1)?,
2169                    self.conv_expr(env, e2)?,
2170                )
2171                .at(espan)
2172            }
2173            fhir::ExprKind::Dot(base, _) => {
2174                let proj = self.results().field_proj(fhir_id);
2175                rty::Expr::field_proj(self.conv_expr(env, base)?, proj)
2176            }
2177            fhir::ExprKind::Abs(params, body) => {
2178                env.push_layer(Layer::list(self.results(), 0, params));
2179                let pred = self.conv_expr(env, body)?;
2180                let vars = env.pop_layer().into_bound_vars(self.genv())?;
2181                let output = self.results().node_sort(body.fhir_id);
2182                let lam = rty::Lambda::bind_with_vars(pred, vars, output);
2183                rty::Expr::abs(lam)
2184            }
2185            fhir::ExprKind::Block(decls, body) => {
2186                for decl in decls {
2187                    env.push_layer(Layer::list(self.results(), 0, &[decl.param]));
2188                }
2189                let mut body = self.conv_expr(env, body)?;
2190                for decl in decls.iter().rev() {
2191                    let vars = env.pop_layer().into_bound_vars(self.genv())?;
2192                    let init = self.conv_expr(env, &decl.init)?;
2193                    body = rty::Expr::let_(init, rty::Binder::bind_with_vars(body, vars));
2194                }
2195                body
2196            }
2197            fhir::ExprKind::BoundedQuant(kind, param, rng, body) => {
2198                env.push_layer(Layer::list(self.results(), 0, &[param]));
2199                let pred = self.conv_expr(env, body)?;
2200                let vars = env.pop_layer().into_bound_vars(self.genv())?;
2201                let body = rty::Binder::bind_with_vars(pred, vars);
2202                rty::Expr::bounded_quant(kind, rng, body)
2203            }
2204            fhir::ExprKind::Record(flds) => {
2205                let def_id = self.results().record_ctor(expr.fhir_id);
2206                let flds = flds
2207                    .iter()
2208                    .map(|expr| self.conv_expr(env, expr))
2209                    .try_collect()?;
2210                rty::Expr::ctor_struct(def_id, flds)
2211            }
2212            fhir::ExprKind::SetLiteral(elems) => {
2213                let elems = elems
2214                    .iter()
2215                    .map(|expr| self.conv_expr(env, expr))
2216                    .try_collect()?;
2217                rty::Expr::set(elems)
2218            }
2219            fhir::ExprKind::Constructor(path, exprs, spread) => {
2220                let def_id = if let Some(path) = path {
2221                    match path.res {
2222                        fhir::Res::Def(DefKind::Enum | DefKind::Struct, def_id) => def_id,
2223                        _ => span_bug!(path.span, "unexpected path in constructor"),
2224                    }
2225                } else {
2226                    self.results().record_ctor(expr.fhir_id)
2227                };
2228                let assns = self.conv_constructor_exprs(def_id, env, exprs, &spread)?;
2229                rty::Expr::ctor_struct(def_id, assns)
2230            }
2231            fhir::ExprKind::Err(err) => Err(QueryErr::Emitted(err))?,
2232        };
2233        Ok(self.add_coercions(expr, fhir_id))
2234    }
2235
2236    fn conv_loc(&mut self, env: &mut Env, loc: fhir::PathExpr) -> QueryResult<rty::Path> {
2237        Ok(self
2238            .conv_path_expr(env, loc)?
2239            .to_path()
2240            .unwrap_or_else(|| span_bug!(loc.span, "expected path, found `{loc:?}`")))
2241    }
2242
2243    fn conv_path_expr(&mut self, env: &mut Env, path: fhir::PathExpr) -> QueryResult<rty::Expr> {
2244        let genv = self.genv();
2245        let tcx = self.genv().tcx();
2246        let espan = ESpan::new(path.span);
2247        let (expr, sort) = match path.res {
2248            fhir::Res::Param(_, id) => (env.lookup(&path).to_expr(), self.results().param_sort(id)),
2249            fhir::Res::Def(DefKind::Const, def_id) => {
2250                self.hyperlink(path.span, tcx.def_ident_span(def_id));
2251                let (expr, sort) = self.conv_const(path.span, def_id)?;
2252                (expr.at(espan), sort)
2253            }
2254            fhir::Res::Def(DefKind::Ctor(..), ctor_id) => {
2255                let Some(sort) = genv.sort_of_def_id(ctor_id).emit(&genv)? else {
2256                    span_bug!(path.span, "unexpected variant {ctor_id:?}")
2257                };
2258
2259                let variant_id = self.tcx().parent(ctor_id);
2260                let enum_id = self.tcx().parent(variant_id);
2261                self.hyperlink(path.span, tcx.def_ident_span(variant_id));
2262                let idx = variant_idx(self.tcx(), variant_id);
2263                (rty::Expr::ctor_enum(enum_id, idx), sort)
2264            }
2265            fhir::Res::Def(DefKind::ConstParam, def_id) => {
2266                self.hyperlink(path.span, tcx.def_ident_span(def_id));
2267                // FIXME(nilehmann) generalize this to other sorts
2268                let sort = rty::Sort::Int;
2269                (rty::Expr::const_generic(def_id_to_param_const(genv, def_id)).at(espan), sort)
2270            }
2271            _ => {
2272                Err(self.emit(errors::InvalidRes { span: path.span, res_descr: path.res.descr() }))?
2273            }
2274        };
2275        self.0.insert_node_sort(path.fhir_id, sort);
2276        Ok(expr)
2277    }
2278
2279    fn conv_const(&self, span: Span, def_id: DefId) -> QueryResult<(rty::Expr, rty::Sort)> {
2280        match self.genv().constant_info(def_id)? {
2281            rty::ConstantInfo::Uninterpreted => {
2282                Err(self.emit(errors::ConstantAnnotationNeeded::new(span)))?
2283            }
2284            rty::ConstantInfo::Interpreted(_, sort) => {
2285                Ok((rty::Expr::const_def_id(def_id).at(ESpan::new(span)), sort))
2286            }
2287        }
2288    }
2289
2290    fn conv_constructor_exprs(
2291        &mut self,
2292        struct_def_id: DefId,
2293        env: &mut Env,
2294        exprs: &[fhir::FieldExpr],
2295        spread: &Option<&fhir::Spread>,
2296    ) -> QueryResult<List<rty::Expr>> {
2297        let spread = spread
2298            .map(|spread| self.conv_expr(env, &spread.expr))
2299            .transpose()?;
2300        let mut field_exprs_by_name: FxHashMap<Symbol, rty::Expr> = exprs
2301            .iter()
2302            .map(|field_expr| -> QueryResult<_> {
2303                Ok((field_expr.ident.name, self.conv_expr(env, &field_expr.expr)?))
2304            })
2305            .try_collect()?;
2306
2307        if !P::HAS_ELABORATED_INFORMATION {
2308            return Ok(List::default());
2309        };
2310
2311        let adt_def = self.genv().adt_sort_def_of(struct_def_id)?;
2312        let struct_variant = adt_def.struct_variant();
2313        let mut assns = Vec::new();
2314        for (idx, field_name) in struct_variant.field_names().iter().enumerate() {
2315            if let Some(expr) = field_exprs_by_name.remove(field_name) {
2316                assns.push(expr);
2317            } else if let Some(spread) = &spread {
2318                let proj = rty::FieldProj::Adt { def_id: struct_def_id, field: idx as u32 };
2319                assns.push(rty::Expr::field_proj(spread, proj));
2320            }
2321        }
2322        Ok(List::from_vec(assns))
2323    }
2324
2325    fn conv_exprs(&mut self, env: &mut Env, exprs: &[fhir::Expr]) -> QueryResult<List<rty::Expr>> {
2326        exprs.iter().map(|e| self.conv_expr(env, e)).collect()
2327    }
2328
2329    fn conv_primop_val(&self, op: fhir::BinOp) -> rty::BinOp {
2330        match op {
2331            fhir::BinOp::BitAnd => rty::BinOp::BitAnd(rty::Sort::Int),
2332            fhir::BinOp::BitOr => rty::BinOp::BitOr(rty::Sort::Int),
2333            fhir::BinOp::BitXor => rty::BinOp::BitXor(rty::Sort::Int),
2334            fhir::BinOp::BitShl => rty::BinOp::BitShl(rty::Sort::Int),
2335            fhir::BinOp::BitShr => rty::BinOp::BitShr(rty::Sort::Int),
2336            _ => bug!("unsupported primop {op:?}"),
2337        }
2338    }
2339
2340    fn conv_bin_op(&self, op: fhir::BinOp, fhir_id: FhirId) -> rty::BinOp {
2341        match op {
2342            fhir::BinOp::Iff => rty::BinOp::Iff,
2343            fhir::BinOp::Imp => rty::BinOp::Imp,
2344            fhir::BinOp::Or => rty::BinOp::Or,
2345            fhir::BinOp::And => rty::BinOp::And,
2346            fhir::BinOp::Eq => rty::BinOp::Eq,
2347            fhir::BinOp::Ne => rty::BinOp::Ne,
2348            fhir::BinOp::Gt => rty::BinOp::Gt(self.results().bin_op_sort(fhir_id)),
2349            fhir::BinOp::Ge => rty::BinOp::Ge(self.results().bin_op_sort(fhir_id)),
2350            fhir::BinOp::Lt => rty::BinOp::Lt(self.results().bin_op_sort(fhir_id)),
2351            fhir::BinOp::Le => rty::BinOp::Le(self.results().bin_op_sort(fhir_id)),
2352            fhir::BinOp::Add => rty::BinOp::Add(self.results().bin_op_sort(fhir_id)),
2353            fhir::BinOp::Sub => rty::BinOp::Sub(self.results().bin_op_sort(fhir_id)),
2354            fhir::BinOp::Mul => rty::BinOp::Mul(self.results().bin_op_sort(fhir_id)),
2355            fhir::BinOp::Mod => rty::BinOp::Mod(self.results().bin_op_sort(fhir_id)),
2356            fhir::BinOp::Div => rty::BinOp::Div(self.results().bin_op_sort(fhir_id)),
2357            fhir::BinOp::BitAnd => rty::BinOp::BitAnd(self.results().bin_op_sort(fhir_id)),
2358            fhir::BinOp::BitOr => rty::BinOp::BitOr(self.results().bin_op_sort(fhir_id)),
2359            fhir::BinOp::BitXor => rty::BinOp::BitXor(self.results().bin_op_sort(fhir_id)),
2360            fhir::BinOp::BitShl => rty::BinOp::BitShl(self.results().bin_op_sort(fhir_id)),
2361            fhir::BinOp::BitShr => rty::BinOp::BitShr(self.results().bin_op_sort(fhir_id)),
2362        }
2363    }
2364
2365    fn add_coercions(&self, mut expr: rty::Expr, fhir_id: FhirId) -> rty::Expr {
2366        let span = expr.span();
2367        for coercion in self.results().coercions_for(fhir_id) {
2368            expr = match *coercion {
2369                rty::Coercion::Inject(def_id) => {
2370                    rty::Expr::ctor_struct(def_id, List::singleton(expr)).at_opt(span)
2371                }
2372                rty::Coercion::Project(def_id) => {
2373                    rty::Expr::field_proj(expr, rty::FieldProj::Adt { def_id, field: 0 })
2374                        .at_opt(span)
2375                }
2376            };
2377        }
2378        expr
2379    }
2380
2381    fn hyperlink(&self, span: Span, dst_span: Option<Span>) {
2382        if P::HAS_ELABORATED_INFORMATION
2383            && let Some(dst_span) = dst_span
2384        {
2385            dbg::hyperlink!(self.genv().tcx(), span, dst_span);
2386        }
2387    }
2388
2389    fn conv_func(&mut self, env: &Env, func: &fhir::PathExpr) -> QueryResult<rty::Expr> {
2390        let genv = self.genv();
2391        let span = func.span;
2392        let (expr, sort) = match func.res {
2393            fhir::Res::Param(_, id) => {
2394                let sort = self.results().param_sort(id);
2395                (env.lookup(func).to_expr(), sort)
2396            }
2397            fhir::Res::GlobalFunc(fhir::SpecFuncKind::Def(did)) => {
2398                self.hyperlink(span, Some(genv.func_span(did)));
2399                let sort = rty::Sort::Func(genv.func_sort(did));
2400                (rty::Expr::global_func(rty::SpecFuncKind::Def(did)), sort)
2401            }
2402            fhir::Res::GlobalFunc(fhir::SpecFuncKind::Uif(did)) => {
2403                self.hyperlink(span, Some(genv.func_span(did)));
2404                let sort = rty::Sort::Func(genv.func_sort(did));
2405                (rty::Expr::global_func(rty::SpecFuncKind::Uif(did)), sort)
2406            }
2407            fhir::Res::GlobalFunc(fhir::SpecFuncKind::Thy(itf)) => {
2408                let sort = THEORY_FUNCS.get(&itf).unwrap().sort.clone();
2409                (rty::Expr::global_func(rty::SpecFuncKind::Thy(itf)), rty::Sort::Func(sort))
2410            }
2411            fhir::Res::GlobalFunc(fhir::SpecFuncKind::Cast) => {
2412                let fsort = rty::PolyFuncSort::new(
2413                    List::from_arr([rty::SortParamKind::Sort, rty::SortParamKind::Sort]),
2414                    rty::FuncSort::new(
2415                        vec![rty::Sort::Var(rty::ParamSort::from(0_usize))],
2416                        rty::Sort::Var(rty::ParamSort::from(1_usize)),
2417                    ),
2418                );
2419                (rty::Expr::internal_func(InternalFuncKind::Cast), rty::Sort::Func(fsort))
2420            }
2421            _ => {
2422                return Err(
2423                    self.emit(errors::InvalidRes { span: func.span, res_descr: func.res.descr() })
2424                )?;
2425            }
2426        };
2427        self.0.insert_node_sort(func.fhir_id, sort);
2428        Ok(self.add_coercions(expr, func.fhir_id))
2429    }
2430
2431    fn conv_alias_reft(
2432        &mut self,
2433        env: &mut Env,
2434        fhir_id: FhirId,
2435        alias: &fhir::AliasReft,
2436    ) -> QueryResult<rty::AliasReft> {
2437        let alias_reft = match alias {
2438            fhir::AliasReft::Qualified { qself, trait_, name } => {
2439                let fhir::Res::Def(DefKind::Trait, trait_id) = trait_.res else {
2440                    span_bug!(trait_.span, "expected trait")
2441                };
2442                let trait_segment = trait_.last_segment();
2443
2444                let generics = self.genv().generics_of(trait_id)?;
2445                let self_ty =
2446                    self.conv_ty_to_generic_arg(env, &generics.param_at(0, self.genv())?, qself)?;
2447                let mut generic_args = vec![self_ty];
2448                self.conv_generic_args_into(env, trait_id, trait_segment, &mut generic_args)?;
2449
2450                let Some(assoc_reft) = self.genv().assoc_refinements_of(trait_id)?.find(name.name)
2451                else {
2452                    return Err(self.emit(errors::InvalidAssocReft::new(
2453                        trait_.span,
2454                        name.name,
2455                        format!("{:?}", trait_),
2456                    )))?;
2457                };
2458
2459                let assoc_id = assoc_reft.def_id;
2460
2461                dbg::hyperlink!(self.genv().tcx(), name.span, assoc_reft.span);
2462
2463                rty::AliasReft { assoc_id, args: List::from_vec(generic_args) }
2464            }
2465            fhir::AliasReft::TypeRelative { qself, name } => {
2466                let qself_res =
2467                    if let Some(path) = qself.as_path() { path.res } else { fhir::Res::Err };
2468                let (assoc_reft, trait_ref) =
2469                    self.conv_type_relative_path(AssocReftTag, qself.span, qself_res, *name)?;
2470                rty::AliasReft { assoc_id: assoc_reft.def_id, args: trait_ref.args }
2471            }
2472        };
2473        let fsort = alias_reft.fsort(self.genv())?;
2474        self.0.insert_alias_reft_sort(fhir_id, fsort);
2475        Ok(alias_reft)
2476    }
2477
2478    pub(crate) fn conv_invariants(
2479        &mut self,
2480        adt_id: MaybeExternId,
2481        params: &[fhir::RefineParam],
2482        invariants: &[fhir::Expr],
2483    ) -> QueryResult<Vec<rty::Invariant>> {
2484        let mut env = Env::new(&[]);
2485        env.push_layer(Layer::coalesce(self.results(), adt_id.resolved_id(), params));
2486        invariants
2487            .iter()
2488            .map(|invariant| self.conv_invariant(&mut env, invariant))
2489            .collect()
2490    }
2491
2492    fn conv_invariant(
2493        &mut self,
2494        env: &mut Env,
2495        invariant: &fhir::Expr,
2496    ) -> QueryResult<rty::Invariant> {
2497        Ok(rty::Invariant::new(rty::Binder::bind_with_vars(
2498            self.conv_expr(env, invariant)?,
2499            env.top_layer().to_bound_vars(self.genv())?,
2500        )))
2501    }
2502}
2503
2504impl Env {
2505    fn new(early_params: &[fhir::RefineParam]) -> Self {
2506        let early_params = early_params
2507            .iter()
2508            .map(|param| (param.id, param.name))
2509            .collect();
2510        Self { layers: vec![], early_params }
2511    }
2512
2513    pub(crate) fn empty() -> Self {
2514        Self { layers: vec![], early_params: Default::default() }
2515    }
2516
2517    fn depth(&self) -> usize {
2518        self.layers.len()
2519    }
2520
2521    fn push_layer(&mut self, layer: Layer) {
2522        self.layers.push(layer);
2523    }
2524
2525    fn pop_layer(&mut self) -> Layer {
2526        self.layers.pop().expect("bottom of layer stack")
2527    }
2528
2529    fn top_layer(&self) -> &Layer {
2530        self.layers.last().expect("bottom of layer stack")
2531    }
2532
2533    fn lookup(&self, var: &fhir::PathExpr) -> LookupResult<'_> {
2534        let (_, id) = var.res.expect_param();
2535        for (i, layer) in self.layers.iter().rev().enumerate() {
2536            if let Some((idx, entry)) = layer.get(id) {
2537                let debruijn = DebruijnIndex::from_usize(i);
2538                let kind = LookupResultKind::Bound {
2539                    debruijn,
2540                    entry,
2541                    index: idx as u32,
2542                    kind: layer.kind,
2543                };
2544                return LookupResult { var_span: var.span, kind };
2545            }
2546        }
2547        if let Some((idx, _, name)) = self.early_params.get_full(&id) {
2548            LookupResult {
2549                var_span: var.span,
2550                kind: LookupResultKind::EarlyParam { index: idx as u32, name: *name },
2551            }
2552        } else {
2553            span_bug!(var.span, "no entry found for key: `{:?}`", id);
2554        }
2555    }
2556
2557    fn to_early_param_args(&self) -> List<rty::Expr> {
2558        self.early_params
2559            .iter()
2560            .enumerate()
2561            .map(|(idx, (_, name))| rty::Expr::early_param(idx as u32, *name))
2562            .collect()
2563    }
2564}
2565
2566impl Layer {
2567    fn new<R: WfckResultsProvider>(
2568        results: &R,
2569        params: &[fhir::RefineParam],
2570        kind: LayerKind,
2571    ) -> Self {
2572        let map = params
2573            .iter()
2574            .map(|param| {
2575                let sort = results.param_sort(param.id);
2576                let infer_mode = rty::InferMode::from_param_kind(param.kind);
2577                let entry = ParamEntry::new(sort, infer_mode, param.name);
2578                (param.id, entry)
2579            })
2580            .collect();
2581        Self { map, kind }
2582    }
2583
2584    fn list<R: WfckResultsProvider>(
2585        results: &R,
2586        bound_regions: u32,
2587        params: &[fhir::RefineParam],
2588    ) -> Self {
2589        Self::new(results, params, LayerKind::List { bound_regions })
2590    }
2591
2592    fn coalesce<R: WfckResultsProvider>(
2593        results: &R,
2594        def_id: DefId,
2595        params: &[fhir::RefineParam],
2596    ) -> Self {
2597        Self::new(results, params, LayerKind::Coalesce(def_id))
2598    }
2599
2600    fn get(&self, name: impl Borrow<fhir::ParamId>) -> Option<(usize, &ParamEntry)> {
2601        let (idx, _, entry) = self.map.get_full(name.borrow())?;
2602        Some((idx, entry))
2603    }
2604
2605    fn into_bound_vars(self, genv: GlobalEnv) -> QueryResult<List<rty::BoundVariableKind>> {
2606        match self.kind {
2607            LayerKind::List { .. } => {
2608                Ok(self
2609                    .into_iter()
2610                    .map(|entry| {
2611                        let kind = rty::BoundReftKind::Named(entry.name);
2612                        rty::BoundVariableKind::Refine(entry.sort, entry.mode, kind)
2613                    })
2614                    .collect())
2615            }
2616            LayerKind::Coalesce(def_id) => {
2617                let sort_def = genv.adt_sort_def_of(def_id)?;
2618                let args = sort_def.identity_args();
2619                let ctor = rty::SortCtor::Adt(sort_def);
2620                Ok(List::singleton(rty::BoundVariableKind::Refine(
2621                    rty::Sort::App(ctor, args),
2622                    rty::InferMode::EVar,
2623                    rty::BoundReftKind::Anon,
2624                )))
2625            }
2626        }
2627    }
2628
2629    fn to_bound_vars(&self, genv: GlobalEnv) -> QueryResult<List<rty::BoundVariableKind>> {
2630        self.clone().into_bound_vars(genv)
2631    }
2632
2633    fn into_iter(self) -> impl Iterator<Item = ParamEntry> {
2634        self.map.into_values()
2635    }
2636}
2637
2638impl ParamEntry {
2639    fn new(sort: rty::Sort, mode: fhir::InferMode, name: Symbol) -> Self {
2640        ParamEntry { name, sort, mode }
2641    }
2642}
2643
2644impl LookupResult<'_> {
2645    fn to_expr(&self) -> rty::Expr {
2646        let espan = ESpan::new(self.var_span);
2647        match &self.kind {
2648            LookupResultKind::Bound { debruijn, entry: ParamEntry { name, .. }, kind, index } => {
2649                match *kind {
2650                    LayerKind::List { bound_regions } => {
2651                        rty::Expr::bvar(
2652                            *debruijn,
2653                            BoundVar::from_u32(bound_regions + *index),
2654                            rty::BoundReftKind::Named(*name),
2655                        )
2656                        .at(espan)
2657                    }
2658                    LayerKind::Coalesce(def_id) => {
2659                        let var =
2660                            rty::Expr::bvar(*debruijn, BoundVar::ZERO, rty::BoundReftKind::Anon)
2661                                .at(espan);
2662                        rty::Expr::field_proj(var, rty::FieldProj::Adt { def_id, field: *index })
2663                            .at(espan)
2664                    }
2665                }
2666            }
2667            &LookupResultKind::EarlyParam { index, name, .. } => {
2668                rty::Expr::early_param(index, name).at(espan)
2669            }
2670        }
2671    }
2672}
2673
2674pub fn conv_func_decl(genv: GlobalEnv, func: &fhir::SpecFunc) -> QueryResult<rty::PolyFuncSort> {
2675    let wfckresults = WfckResults::new(FluxOwnerId::Flux(func.def_id));
2676    let mut cx = AfterSortck::new(genv, &wfckresults).into_conv_ctxt();
2677    let inputs_and_output = func
2678        .args
2679        .iter()
2680        .map(|p| &p.sort)
2681        .chain(iter::once(&func.sort))
2682        .map(|sort| cx.conv_sort(sort))
2683        .try_collect()?;
2684    let params = iter::repeat_n(rty::SortParamKind::Sort, func.params).collect();
2685    Ok(rty::PolyFuncSort::new(params, rty::FuncSort { inputs_and_output }))
2686}
2687
2688fn conv_un_op(op: fhir::UnOp) -> rty::UnOp {
2689    match op {
2690        fhir::UnOp::Not => rty::UnOp::Not,
2691        fhir::UnOp::Neg => rty::UnOp::Neg,
2692    }
2693}
2694
2695fn def_id_to_param_ty(genv: GlobalEnv, def_id: DefId) -> rty::ParamTy {
2696    rty::ParamTy { index: genv.def_id_to_param_index(def_id), name: ty_param_name(genv, def_id) }
2697}
2698
2699fn def_id_to_param_const(genv: GlobalEnv, def_id: DefId) -> rty::ParamConst {
2700    rty::ParamConst { index: genv.def_id_to_param_index(def_id), name: ty_param_name(genv, def_id) }
2701}
2702
2703fn ty_param_owner(genv: GlobalEnv, def_id: DefId) -> DefId {
2704    let def_kind = genv.def_kind(def_id);
2705    match def_kind {
2706        DefKind::Trait | DefKind::TraitAlias => def_id,
2707        DefKind::LifetimeParam | DefKind::TyParam | DefKind::ConstParam => {
2708            genv.tcx().parent(def_id)
2709        }
2710        _ => bug!("ty_param_owner: {:?} is a {:?} not a type parameter", def_id, def_kind),
2711    }
2712}
2713
2714fn ty_param_name(genv: GlobalEnv, def_id: DefId) -> Symbol {
2715    let def_kind = genv.tcx().def_kind(def_id);
2716    match def_kind {
2717        DefKind::Trait | DefKind::TraitAlias => kw::SelfUpper,
2718        DefKind::LifetimeParam | DefKind::TyParam | DefKind::ConstParam => {
2719            genv.tcx().item_name(def_id)
2720        }
2721        _ => bug!("ty_param_name: {:?} is a {:?} not a type parameter", def_id, def_kind),
2722    }
2723}
2724
2725/// This trait is used to define functions generically over both _associated refinements_
2726/// and _associated items_ (types, consts, and functions).
2727trait AssocItemTag: Copy {
2728    type AssocItem<'tcx>;
2729
2730    fn descr(self) -> &'static str;
2731
2732    fn trait_defines_item_named<'tcx>(
2733        self,
2734        genv: GlobalEnv<'_, 'tcx>,
2735        trait_def_id: DefId,
2736        assoc_name: Ident,
2737    ) -> QueryResult<Option<Self::AssocItem<'tcx>>>;
2738
2739    fn transitive_bounds_that_define_assoc_item<'tcx>(
2740        self,
2741        genv: GlobalEnv<'_, 'tcx>,
2742        trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
2743        assoc_name: Ident,
2744    ) -> impl Iterator<Item = ty::PolyTraitRef<'tcx>>;
2745}
2746
2747impl AssocItemTag for AssocTag {
2748    type AssocItem<'tcx> = &'tcx AssocItem;
2749
2750    fn descr(self) -> &'static str {
2751        match self {
2752            AssocTag::Const => "constant",
2753            AssocTag::Fn => "function",
2754            AssocTag::Type => "type",
2755        }
2756    }
2757
2758    fn trait_defines_item_named<'tcx>(
2759        self,
2760        genv: GlobalEnv<'_, 'tcx>,
2761        trait_def_id: DefId,
2762        assoc_name: Ident,
2763    ) -> QueryResult<Option<Self::AssocItem<'tcx>>> {
2764        Ok(genv
2765            .tcx()
2766            .associated_items(trait_def_id)
2767            .find_by_ident_and_kind(genv.tcx(), assoc_name, self, trait_def_id))
2768    }
2769
2770    fn transitive_bounds_that_define_assoc_item<'tcx>(
2771        self,
2772        genv: GlobalEnv<'_, 'tcx>,
2773        trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
2774        assoc_name: Ident,
2775    ) -> impl Iterator<Item = ty::PolyTraitRef<'tcx>> {
2776        traits::transitive_bounds_that_define_assoc_item(genv.tcx(), trait_refs, assoc_name)
2777    }
2778}
2779
2780#[derive(Copy, Clone)]
2781struct AssocReftTag;
2782
2783impl AssocItemTag for AssocReftTag {
2784    type AssocItem<'tcx> = AssocReft;
2785
2786    fn descr(self) -> &'static str {
2787        "refinement"
2788    }
2789
2790    fn trait_defines_item_named<'tcx>(
2791        self,
2792        genv: GlobalEnv<'_, 'tcx>,
2793        trait_def_id: DefId,
2794        assoc_name: Ident,
2795    ) -> QueryResult<Option<Self::AssocItem<'tcx>>> {
2796        Ok(genv
2797            .assoc_refinements_of(trait_def_id)?
2798            .find(assoc_name.name))
2799    }
2800
2801    fn transitive_bounds_that_define_assoc_item<'tcx>(
2802        self,
2803        genv: GlobalEnv<'_, 'tcx>,
2804        trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
2805        _assoc_name: Ident,
2806    ) -> impl Iterator<Item = ty::PolyTraitRef<'tcx>> {
2807        transitive_bounds(genv.tcx(), trait_refs)
2808    }
2809}
2810
2811/// This is like [`TyCtxt::type_param_predicates`] but computes all bounds not just the ones defining
2812/// an associated item. We *must* compute this ourselves to resolve type-relative associated refinements,
2813/// but we also use it to resolve type-relative type paths.
2814///
2815/// NOTE: [`TyCtxt::type_param_predicates`] is defined specifically to avoid cycles which is not a
2816/// problem for us so we can use it instead of [`TyCtxt::type_param_predicates`].
2817fn type_param_predicates<'tcx>(
2818    tcx: TyCtxt<'tcx>,
2819    param_id: DefId,
2820) -> impl Iterator<Item = ty::PolyTraitPredicate<'tcx>> {
2821    let parent = if tcx.def_kind(param_id) == DefKind::Trait {
2822        // If the param_id is a trait then this is the `Self` parameter and the parent is the trait itself
2823        param_id
2824    } else {
2825        tcx.parent(param_id)
2826    };
2827    let param_index = tcx
2828        .generics_of(parent)
2829        .param_def_id_to_index(tcx, param_id)
2830        .unwrap();
2831    let predicates = tcx.predicates_of(parent).instantiate_identity(tcx);
2832    predicates.into_iter().filter_map(move |(clause, _)| {
2833        clause
2834            .as_trait_clause()
2835            .filter(|trait_pred| trait_pred.self_ty().skip_binder().is_param(param_index))
2836    })
2837}
2838
2839/// This is like [`traits::transitive_bounds_that_define_assoc_item`] but computes all bounds not just
2840/// the ones defining an associated item. We *must* compute this ourselves to resolve type-relative
2841/// associated refinements.
2842///
2843/// NOTE: [`traits::transitive_bounds_that_define_assoc_item`] is defined specifically to avoid cycles
2844/// which is not a problem for us. So instead of using `explicit_supertraits_containing_assoc_item` we
2845/// can simply use `explicit_super_predicates_of`.
2846fn transitive_bounds<'tcx>(
2847    tcx: TyCtxt<'tcx>,
2848    trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
2849) -> impl Iterator<Item = ty::PolyTraitRef<'tcx>> {
2850    let mut seen = FxHashSet::default();
2851    let mut stack: Vec<_> = trait_refs.collect();
2852
2853    std::iter::from_fn(move || {
2854        while let Some(trait_ref) = stack.pop() {
2855            if !seen.insert(tcx.anonymize_bound_vars(trait_ref)) {
2856                continue;
2857            }
2858
2859            stack.extend(
2860                tcx.explicit_super_predicates_of(trait_ref.def_id())
2861                    .iter_identity_copied()
2862                    .map(|(clause, _)| clause.instantiate_supertrait(tcx, trait_ref))
2863                    .filter_map(|clause| clause.as_trait_clause())
2864                    .filter(|clause| clause.polarity() == ty::PredicatePolarity::Positive)
2865                    .map(|clause| clause.map_bound(|clause| clause.trait_ref)),
2866            );
2867
2868            return Some(trait_ref);
2869        }
2870
2871        None
2872    })
2873}
2874
2875mod errors {
2876    use flux_errors::E0999;
2877    use flux_macros::Diagnostic;
2878    use flux_middle::{fhir, global_env::GlobalEnv, rty::Sort};
2879    use rustc_hir::def_id::DefId;
2880    use rustc_span::{Span, Symbol, symbol::Ident};
2881
2882    #[derive(Diagnostic)]
2883    #[diag(fhir_analysis_assoc_item_not_found, code = E0999)]
2884    #[note]
2885    pub(super) struct AssocItemNotFound {
2886        #[primary_span]
2887        #[label]
2888        pub span: Span,
2889        pub tag: &'static str,
2890    }
2891
2892    #[derive(Diagnostic)]
2893    #[diag(fhir_analysis_ambiguous_assoc_item, code = E0999)]
2894    pub(super) struct AmbiguousAssocItem {
2895        #[primary_span]
2896        pub span: Span,
2897        pub name: Ident,
2898        pub tag: &'static str,
2899    }
2900
2901    #[derive(Diagnostic)]
2902    #[diag(fhir_analysis_invalid_base_instance, code = E0999)]
2903    pub(super) struct InvalidBaseInstance {
2904        #[primary_span]
2905        span: Span,
2906    }
2907
2908    impl InvalidBaseInstance {
2909        pub(super) fn new(span: Span) -> Self {
2910            Self { span }
2911        }
2912    }
2913
2914    #[derive(Diagnostic)]
2915    #[diag(fhir_analysis_generic_argument_count_mismatch, code = E0999)]
2916    pub(super) struct GenericArgCountMismatch {
2917        #[primary_span]
2918        #[label]
2919        span: Span,
2920        found: usize,
2921        expected: usize,
2922        def_descr: &'static str,
2923    }
2924
2925    impl GenericArgCountMismatch {
2926        pub(super) fn new(
2927            genv: GlobalEnv,
2928            def_id: DefId,
2929            segment: &fhir::PathSegment,
2930            expected: usize,
2931        ) -> Self {
2932            GenericArgCountMismatch {
2933                span: segment.ident.span,
2934                found: segment.args.len(),
2935                expected,
2936                def_descr: genv.tcx().def_descr(def_id),
2937            }
2938        }
2939    }
2940
2941    #[derive(Diagnostic)]
2942    #[diag(fhir_analysis_too_few_generic_args, code = E0999)]
2943    pub(super) struct TooFewGenericArgs {
2944        #[primary_span]
2945        #[label]
2946        span: Span,
2947        found: usize,
2948        min: usize,
2949        def_descr: &'static str,
2950    }
2951
2952    impl TooFewGenericArgs {
2953        pub(super) fn new(
2954            genv: GlobalEnv,
2955            def_id: DefId,
2956            segment: &fhir::PathSegment,
2957            min: usize,
2958        ) -> Self {
2959            Self {
2960                span: segment.ident.span,
2961                found: segment.args.len(),
2962                min,
2963                def_descr: genv.tcx().def_descr(def_id),
2964            }
2965        }
2966    }
2967
2968    #[derive(Diagnostic)]
2969    #[diag(fhir_analysis_too_many_generic_args, code = E0999)]
2970    pub(super) struct TooManyGenericArgs {
2971        #[primary_span]
2972        #[label]
2973        span: Span,
2974        found: usize,
2975        max: usize,
2976        def_descr: &'static str,
2977    }
2978
2979    impl TooManyGenericArgs {
2980        pub(super) fn new(
2981            genv: GlobalEnv,
2982            def_id: DefId,
2983            segment: &fhir::PathSegment,
2984            max: usize,
2985        ) -> Self {
2986            Self {
2987                span: segment.ident.span,
2988                found: segment.args.len(),
2989                max,
2990                def_descr: genv.tcx().def_descr(def_id),
2991            }
2992        }
2993    }
2994
2995    #[derive(Diagnostic)]
2996    #[diag(fhir_analysis_refined_unrefinable_type, code = E0999)]
2997    pub(super) struct RefinedUnrefinableType {
2998        #[primary_span]
2999        span: Span,
3000    }
3001
3002    impl RefinedUnrefinableType {
3003        pub(super) fn new(span: Span) -> Self {
3004            Self { span }
3005        }
3006    }
3007
3008    #[derive(Diagnostic)]
3009    #[diag(fhir_analysis_generics_on_primitive_sort, code = E0999)]
3010    pub(super) struct GenericsOnPrimitiveSort {
3011        #[primary_span]
3012        #[label]
3013        span: Span,
3014        name: &'static str,
3015        found: usize,
3016        expected: usize,
3017    }
3018
3019    impl GenericsOnPrimitiveSort {
3020        pub(super) fn new(span: Span, name: &'static str, found: usize, expected: usize) -> Self {
3021            Self { span, found, expected, name }
3022        }
3023    }
3024
3025    #[derive(Diagnostic)]
3026    #[diag(fhir_analysis_incorrect_generics_on_sort, code = E0999)]
3027    pub(super) struct IncorrectGenericsOnSort {
3028        #[primary_span]
3029        #[label]
3030        span: Span,
3031        found: usize,
3032        expected: usize,
3033        def_descr: &'static str,
3034    }
3035
3036    impl IncorrectGenericsOnSort {
3037        pub(super) fn new(
3038            genv: GlobalEnv,
3039            def_id: DefId,
3040            span: Span,
3041            found: usize,
3042            expected: usize,
3043        ) -> Self {
3044            Self { span, found, expected, def_descr: genv.tcx().def_descr(def_id) }
3045        }
3046    }
3047
3048    #[derive(Diagnostic)]
3049    #[diag(fhir_analysis_generics_on_sort_ty_param, code = E0999)]
3050    pub(super) struct GenericsOnSortTyParam {
3051        #[primary_span]
3052        #[label]
3053        span: Span,
3054        found: usize,
3055    }
3056
3057    impl GenericsOnSortTyParam {
3058        pub(super) fn new(span: Span, found: usize) -> Self {
3059            Self { span, found }
3060        }
3061    }
3062
3063    #[derive(Diagnostic)]
3064    #[diag(fhir_analysis_generics_on_self_alias, code = E0999)]
3065    pub(super) struct GenericsOnSelf {
3066        #[primary_span]
3067        #[label]
3068        span: Span,
3069        found: usize,
3070    }
3071
3072    impl GenericsOnSelf {
3073        pub(super) fn new(span: Span, found: usize) -> Self {
3074            Self { span, found }
3075        }
3076    }
3077
3078    #[derive(Diagnostic)]
3079    #[diag(fhir_analysis_fields_on_reflected_enum_variant, code = E0999)]
3080    pub(super) struct FieldsOnReflectedEnumVariant {
3081        #[primary_span]
3082        #[label]
3083        span: Span,
3084    }
3085
3086    impl FieldsOnReflectedEnumVariant {
3087        pub(super) fn new(span: Span) -> Self {
3088            Self { span }
3089        }
3090    }
3091
3092    #[derive(Diagnostic)]
3093    #[diag(fhir_analysis_incorrect_generics_on_opaque_sort, code = E0999)]
3094    pub(super) struct IncorrectGenericsOnUserDefinedOpaqueSort {
3095        #[primary_span]
3096        #[label]
3097        span: Span,
3098        name: Symbol,
3099        expected: usize,
3100        found: usize,
3101    }
3102
3103    impl IncorrectGenericsOnUserDefinedOpaqueSort {
3104        pub(super) fn new(span: Span, name: Symbol, expected: usize, found: usize) -> Self {
3105            Self { span, name, expected, found }
3106        }
3107    }
3108
3109    #[derive(Diagnostic)]
3110    #[diag(fhir_analysis_generics_on_prim_ty, code = E0999)]
3111    pub(super) struct GenericsOnPrimTy {
3112        #[primary_span]
3113        pub span: Span,
3114        pub name: &'static str,
3115    }
3116
3117    #[derive(Diagnostic)]
3118    #[diag(fhir_analysis_generics_on_ty_param, code = E0999)]
3119    pub(super) struct GenericsOnTyParam {
3120        #[primary_span]
3121        pub span: Span,
3122        pub name: Symbol,
3123    }
3124
3125    #[derive(Diagnostic)]
3126    #[diag(fhir_analysis_generics_on_self_ty, code = E0999)]
3127    pub(super) struct GenericsOnSelfTy {
3128        #[primary_span]
3129        pub span: Span,
3130    }
3131
3132    #[derive(Diagnostic)]
3133    #[diag(fhir_analysis_generics_on_foreign_ty, code = E0999)]
3134    pub(super) struct GenericsOnForeignTy {
3135        #[primary_span]
3136        pub span: Span,
3137    }
3138
3139    #[derive(Diagnostic)]
3140    #[diag(fhir_analysis_invalid_bitvector_constant, code = E0999)]
3141    pub struct InvalidBitVectorConstant {
3142        #[primary_span]
3143        #[label]
3144        span: Span,
3145        sort: Sort,
3146    }
3147
3148    impl InvalidBitVectorConstant {
3149        pub(crate) fn new(span: Span, sort: Sort) -> Self {
3150            Self { span, sort }
3151        }
3152    }
3153
3154    #[derive(Diagnostic)]
3155    #[diag(fhir_analysis_invalid_assoc_reft, code = E0999)]
3156    pub struct InvalidAssocReft {
3157        #[primary_span]
3158        span: Span,
3159        trait_: String,
3160        name: Symbol,
3161    }
3162
3163    impl InvalidAssocReft {
3164        pub(crate) fn new(span: Span, name: Symbol, trait_: String) -> Self {
3165            Self { span, trait_, name }
3166        }
3167    }
3168
3169    #[derive(Diagnostic)]
3170    #[diag(fhir_analysis_refine_arg_mismatch, code = E0999)]
3171    pub(super) struct RefineArgMismatch {
3172        #[primary_span]
3173        #[label]
3174        pub span: Span,
3175        pub expected: usize,
3176        pub found: usize,
3177        pub kind: &'static str,
3178    }
3179
3180    #[derive(Diagnostic)]
3181    #[diag(fhir_analysis_expected_type, code = E0999)]
3182    pub(super) struct ExpectedType {
3183        #[primary_span]
3184        pub span: Span,
3185        pub def_descr: &'static str,
3186        pub name: String,
3187    }
3188
3189    #[derive(Diagnostic)]
3190    #[diag(fhir_analysis_fail_to_match_predicates, code = E0999)]
3191    pub(super) struct FailToMatchPredicates {
3192        #[primary_span]
3193        pub span: Span,
3194    }
3195
3196    #[derive(Diagnostic)]
3197    #[diag(fhir_analysis_invalid_res, code = E0999)]
3198    pub(super) struct InvalidRes {
3199        #[primary_span]
3200        pub span: Span,
3201        pub res_descr: &'static str,
3202    }
3203
3204    #[derive(Diagnostic)]
3205    #[diag(fhir_analysis_constant_annotation_needed, code = E0999)]
3206    pub(super) struct ConstantAnnotationNeeded {
3207        #[primary_span]
3208        #[label]
3209        span: Span,
3210    }
3211    impl ConstantAnnotationNeeded {
3212        pub(super) fn new(span: Span) -> Self {
3213            Self { span }
3214        }
3215    }
3216}