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