Skip to main content

flux_fhir_analysis/conv/
mod.rs

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