aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/generics.rs
blob: 5625c2459f56f11b41f07bb5325333aaa3f3d2dd (plain)
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
//! Many kinds of items or constructs can have generic parameters: functions,
//! structs, impls, traits, etc. This module provides a common HIR for these
//! generic parameters. See also the `Generics` type and the `generics_of` query
//! in rustc.

use std::sync::Arc;

use ra_syntax::ast::{self, NameOwner, TypeParamsOwner};

use crate::{
    db::DefDatabase,
    Name, AsName, Function, Struct, Enum, Trait, TypeAlias, ImplBlock, Container
};

/// Data about a generic parameter (to a function, struct, impl, ...).
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct GenericParam {
    // FIXME: give generic params proper IDs
    pub(crate) idx: u32,
    pub(crate) name: Name,
}

/// Data about the generic parameters of a function, struct, impl, etc.
#[derive(Clone, PartialEq, Eq, Debug, Default)]
pub struct GenericParams {
    pub(crate) parent_params: Option<Arc<GenericParams>>,
    pub(crate) params: Vec<GenericParam>,
}

// FIXME: consts can have type parameters from their parents (i.e. associated consts of traits)
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub enum GenericDef {
    Function(Function),
    Struct(Struct),
    Enum(Enum),
    Trait(Trait),
    TypeAlias(TypeAlias),
    ImplBlock(ImplBlock),
}
impl_froms!(GenericDef: Function, Struct, Enum, Trait, TypeAlias, ImplBlock);

impl GenericParams {
    pub(crate) fn generic_params_query(
        db: &impl DefDatabase,
        def: GenericDef,
    ) -> Arc<GenericParams> {
        let mut generics = GenericParams::default();
        let parent = match def {
            GenericDef::Function(it) => it.container(db).map(GenericDef::from),
            GenericDef::TypeAlias(it) => it.container(db).map(GenericDef::from),
            GenericDef::Struct(_) | GenericDef::Enum(_) | GenericDef::Trait(_) => None,
            GenericDef::ImplBlock(_) => None,
        };
        generics.parent_params = parent.map(|p| db.generic_params(p));
        let start = generics.parent_params.as_ref().map(|p| p.params.len()).unwrap_or(0) as u32;
        match def {
            GenericDef::Function(it) => generics.fill(&*it.source(db).1, start),
            GenericDef::Struct(it) => generics.fill(&*it.source(db).1, start),
            GenericDef::Enum(it) => generics.fill(&*it.source(db).1, start),
            GenericDef::Trait(it) => {
                // traits get the Self type as an implicit first type parameter
                generics.params.push(GenericParam { idx: start, name: Name::self_type() });
                generics.fill(&*it.source(db).1, start + 1);
            }
            GenericDef::TypeAlias(it) => generics.fill(&*it.source(db).1, start),
            GenericDef::ImplBlock(it) => generics.fill(&*it.source(db).1, start),
        }

        Arc::new(generics)
    }

    fn fill(&mut self, node: &impl TypeParamsOwner, start: u32) {
        if let Some(params) = node.type_param_list() {
            self.fill_params(params, start)
        }
    }

    fn fill_params(&mut self, params: &ast::TypeParamList, start: u32) {
        for (idx, type_param) in params.type_params().enumerate() {
            let name = type_param.name().map(AsName::as_name).unwrap_or_else(Name::missing);
            let param = GenericParam { idx: idx as u32 + start, name };
            self.params.push(param);
        }
    }

    pub(crate) fn find_by_name(&self, name: &Name) -> Option<&GenericParam> {
        self.params.iter().find(|p| &p.name == name)
    }

    pub fn count_parent_params(&self) -> usize {
        self.parent_params.as_ref().map(|p| p.count_params_including_parent()).unwrap_or(0)
    }

    pub fn count_params_including_parent(&self) -> usize {
        let parent_count = self.count_parent_params();
        parent_count + self.params.len()
    }

    fn for_each_param<'a>(&'a self, f: &mut impl FnMut(&'a GenericParam)) {
        if let Some(parent) = &self.parent_params {
            parent.for_each_param(f);
        }
        self.params.iter().for_each(f);
    }

    pub fn params_including_parent(&self) -> Vec<&GenericParam> {
        let mut vec = Vec::with_capacity(self.count_params_including_parent());
        self.for_each_param(&mut |p| vec.push(p));
        vec
    }
}

impl From<Container> for GenericDef {
    fn from(c: Container) -> Self {
        match c {
            Container::Trait(trait_) => trait_.into(),
            Container::ImplBlock(impl_block) => impl_block.into(),
        }
    }
}

pub trait HasGenericParams {
    fn generic_params(self, db: &impl DefDatabase) -> Arc<GenericParams>;
}

impl<T> HasGenericParams for T
where
    T: Into<GenericDef>,
{
    fn generic_params(self, db: &impl DefDatabase) -> Arc<GenericParams> {
        db.generic_params(self.into())
    }
}