Unnamed repository; edit this file 'description' to name the repository.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
//! Things related to generics in the next-trait-solver.

use hir_def::{
    ConstParamId, GenericDefId, GenericParamId, ItemContainerId, LifetimeParamId, Lookup,
    TypeOrConstParamId, TypeParamId,
    db::DefDatabase,
    expr_store::ExpressionStore,
    hir::generics::{
        GenericParamDataRef, GenericParams, LifetimeParamData, LocalLifetimeParamId,
        LocalTypeOrConstParamId, TypeOrConstParamData, TypeParamData, TypeParamProvenance,
        WherePredicate,
    },
};
use hir_expand::name::Name;
use intern::{Symbol, sym};
use la_arena::Arena;
use rustc_type_ir::inherent::Ty as _;
use triomphe::Arc;

use crate::{db::HirDatabase, generics::parent_generic_def, next_solver::Ty};

use super::{Const, EarlyParamRegion, ErrorGuaranteed, ParamConst, Region, SolverDefId};

use super::{DbInterner, GenericArg};

pub(crate) fn generics(db: &dyn HirDatabase, def: SolverDefId) -> Generics {
    let mk_lt = |parent, index, local_id, lt: &LifetimeParamData| {
        let name = lt.name.symbol().clone();
        let id = GenericParamId::LifetimeParamId(LifetimeParamId { parent, local_id });
        GenericParamDef { name, index, id }
    };
    let mk_ty = |parent, index, local_id, p: &TypeOrConstParamData| {
        let name = p.name().map(|n| n.symbol().clone()).unwrap_or_else(|| sym::MISSING_NAME);
        let id = TypeOrConstParamId { parent, local_id };
        let id = match p {
            TypeOrConstParamData::TypeParamData(_) => {
                GenericParamId::TypeParamId(TypeParamId::from_unchecked(id))
            }
            TypeOrConstParamData::ConstParamData(_) => {
                GenericParamId::ConstParamId(ConstParamId::from_unchecked(id))
            }
        };
        GenericParamDef { name, index, id }
    };
    let own_params_for_generic_params = |parent, params: &GenericParams| {
        let mut result = Vec::with_capacity(params.len());
        let mut type_and_consts = params.iter_type_or_consts();
        let mut index = 0;
        if let Some(self_param) = params.trait_self_param() {
            result.push(mk_ty(parent, 0, self_param, &params[self_param]));
            type_and_consts.next();
            index += 1;
        }
        result.extend(params.iter_lt().map(|(local_id, data)| {
            let lt = mk_lt(parent, index, local_id, data);
            index += 1;
            lt
        }));
        result.extend(type_and_consts.map(|(local_id, data)| {
            let ty = mk_ty(parent, index, local_id, data);
            index += 1;
            ty
        }));
        result
    };

    let (parent, own_params) = match (def.try_into(), def) {
        (Ok(def), _) => (
            parent_generic_def(db, def),
            own_params_for_generic_params(def, &db.generic_params(def)),
        ),
        (_, SolverDefId::InternedOpaqueTyId(id)) => {
            match db.lookup_intern_impl_trait_id(id) {
                crate::ImplTraitId::ReturnTypeImplTrait(function_id, _) => {
                    // The opaque type itself does not have generics - only the parent function
                    (Some(GenericDefId::FunctionId(function_id)), vec![])
                }
                crate::ImplTraitId::TypeAliasImplTrait(type_alias_id, _) => {
                    (Some(type_alias_id.into()), Vec::new())
                }
                crate::ImplTraitId::AsyncBlockTypeImplTrait(def, _) => {
                    let param = TypeOrConstParamData::TypeParamData(TypeParamData {
                        name: None,
                        default: None,
                        provenance: TypeParamProvenance::TypeParamList,
                    });
                    // Yes, there is a parent but we don't include it in the generics
                    // FIXME: It seems utterly sensitive to fake a generic param here.
                    // Also, what a horrible mess!
                    (
                        None,
                        vec![mk_ty(
                            GenericDefId::FunctionId(salsa::plumbing::FromId::from_id(unsafe {
                                salsa::Id::from_index(salsa::Id::MAX_U32 - 1)
                            })),
                            0,
                            LocalTypeOrConstParamId::from_raw(la_arena::RawIdx::from_u32(0)),
                            &param,
                        )],
                    )
                }
            }
        }
        _ => panic!("No generics for {def:?}"),
    };
    let parent_generics = parent.map(|def| Box::new(generics(db, def.into())));

    Generics {
        parent,
        parent_count: parent_generics.map_or(0, |g| g.parent_count + g.own_params.len()),
        own_params,
    }
}

#[derive(Debug)]
pub struct Generics {
    pub parent: Option<GenericDefId>,
    pub parent_count: usize,
    pub own_params: Vec<GenericParamDef>,
}

#[derive(Debug)]
pub struct GenericParamDef {
    pub(crate) name: Symbol,
    //def_id: GenericDefId,
    index: u32,
    pub(crate) id: GenericParamId,
}

impl GenericParamDef {
    /// Returns the index of the param on the self generics only
    /// (i.e. not including parent generics)
    pub fn index(&self) -> u32 {
        self.index
    }
}

impl<'db> rustc_type_ir::inherent::GenericsOf<DbInterner<'db>> for Generics {
    fn count(&self) -> usize {
        self.parent_count + self.own_params.len()
    }
}