mun_hir/
type_ref.rs

1//! HIR for references to types. These paths are not yet resolved. They can be directly created
2//! from an `ast::TypeRef`, without further queries.
3
4use crate::{
5    arena::{map::ArenaMap, Arena, Idx},
6    Path,
7};
8use mun_syntax::{ast, AstPtr};
9use rustc_hash::FxHashMap;
10use std::ops::Index;
11
12/// The ID of a `TypeRef` in a `TypeRefMap`
13pub type LocalTypeRefId = Idx<TypeRef>;
14
15/// Compare ty::Ty
16#[derive(Clone, PartialEq, Eq, Hash, Debug)]
17pub enum TypeRef {
18    Path(Path),
19    Array(LocalTypeRefId),
20    Never,
21    Tuple(Vec<LocalTypeRefId>),
22    Error,
23}
24
25#[derive(Default, Debug, Eq, PartialEq)]
26pub struct TypeRefSourceMap {
27    type_ref_map: FxHashMap<AstPtr<ast::TypeRef>, LocalTypeRefId>,
28    type_ref_map_back: ArenaMap<LocalTypeRefId, AstPtr<ast::TypeRef>>,
29}
30
31impl TypeRefSourceMap {
32    /// Returns the syntax node of the specified `LocalTypeRefId` or `None` if it doesnt exist in
33    /// this instance.
34    pub(crate) fn type_ref_syntax(&self, expr: LocalTypeRefId) -> Option<AstPtr<ast::TypeRef>> {
35        self.type_ref_map_back.get(expr).cloned()
36    }
37
38    /// Returns the `LocalTypeRefId` references at the given location or `None` if no such Id
39    /// exists.
40    pub(crate) fn syntax_type_ref(&self, ptr: AstPtr<ast::TypeRef>) -> Option<LocalTypeRefId> {
41        self.type_ref_map.get(&ptr).cloned()
42    }
43}
44
45/// Holds all type references from a specific region in the source code (depending on the use of
46/// this struct). This struct is often used in conjunction with a `TypeRefSourceMap` which maps
47/// `LocalTypeRefId`s to location in the syntax tree and back.
48#[derive(Default, Debug, Eq, PartialEq, Clone)]
49pub struct TypeRefMap {
50    type_refs: Arena<TypeRef>,
51}
52
53impl TypeRefMap {
54    pub(crate) fn builder() -> TypeRefMapBuilder {
55        TypeRefMapBuilder {
56            map: Default::default(),
57            source_map: Default::default(),
58        }
59    }
60
61    /// Returns an iterator over all types in this instance
62    pub fn iter(&self) -> impl Iterator<Item = (LocalTypeRefId, &TypeRef)> {
63        self.type_refs.iter()
64    }
65}
66
67impl Index<LocalTypeRefId> for TypeRefMap {
68    type Output = TypeRef;
69
70    fn index(&self, pat: LocalTypeRefId) -> &Self::Output {
71        &self.type_refs[pat]
72    }
73}
74
75/// A builder object to lower type references from syntax to a more abstract representation.
76#[derive(Debug, Eq, PartialEq)]
77pub(crate) struct TypeRefMapBuilder {
78    map: TypeRefMap,
79    source_map: TypeRefSourceMap,
80}
81
82impl TypeRefMapBuilder {
83    /// Allocates a new `LocalTypeRefId` for the specified `TypeRef`. The passed `ptr` marks where
84    /// the `TypeRef` is located in the AST.
85    fn alloc_type_ref(&mut self, type_ref: TypeRef, ptr: AstPtr<ast::TypeRef>) -> LocalTypeRefId {
86        let id = self.map.type_refs.alloc(type_ref);
87        self.source_map.type_ref_map.insert(ptr.clone(), id);
88        self.source_map.type_ref_map_back.insert(id, ptr);
89        id
90    }
91
92    /// Lowers the given optional AST type references and returns the Id of the resulting `TypeRef`.
93    /// If the node is None an error is created indicating a missing `TypeRef` in the AST.
94    pub fn alloc_from_node_opt(&mut self, node: Option<&ast::TypeRef>) -> LocalTypeRefId {
95        if let Some(node) = node {
96            self.alloc_from_node(node)
97        } else {
98            self.error()
99        }
100    }
101
102    /// Lowers the given AST type references and returns the Id of the resulting `TypeRef`.
103    pub fn alloc_from_node(&mut self, node: &ast::TypeRef) -> LocalTypeRefId {
104        use mun_syntax::ast::TypeRefKind::*;
105        let ptr = AstPtr::new(node);
106        let type_ref = match node.kind() {
107            PathType(path) => path
108                .path()
109                .and_then(Path::from_ast)
110                .map(TypeRef::Path)
111                .unwrap_or(TypeRef::Error),
112            NeverType(_) => TypeRef::Never,
113            ArrayType(inner) => TypeRef::Array(self.alloc_from_node_opt(inner.type_ref().as_ref())),
114        };
115        self.alloc_type_ref(type_ref, ptr)
116    }
117
118    /// Constructs a new `TypeRef` for the empty tuple type. Returns the Id of the newly create
119    /// `TypeRef`.
120    pub fn unit(&mut self) -> LocalTypeRefId {
121        self.map.type_refs.alloc(TypeRef::Tuple(vec![]))
122    }
123
124    /// Constructs a new error `TypeRef` which marks an error in the AST.
125    pub fn error(&mut self) -> LocalTypeRefId {
126        self.map.type_refs.alloc(TypeRef::Error)
127    }
128
129    /// Finish building type references, returning the `TypeRefMap` which contains all the
130    /// `TypeRef`s and a `TypeRefSourceMap` which converts LocalTypeRefIds back to source location.
131    pub fn finish(self) -> (TypeRefMap, TypeRefSourceMap) {
132        (self.map, self.source_map)
133    }
134}