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