Skip to main content

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