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