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