1use std::{cell::OnceCell, mem};
3
4use hir_expand::{AstId, HirFileId, InFile, span_map::SpanMap};
5use span::{AstIdMap, AstIdNode, Edition, EditionedFileId, FileId, RealSpanMap};
6use syntax::ast;
7use thin_vec::ThinVec;
8use triomphe::Arc;
9
10use crate::{
11 db::DefDatabase,
12 path::Path,
13 type_ref::{PathId, TypeBound, TypePtr, TypeRef, TypeRefId, TypesMap, TypesSourceMap},
14};
15
16pub struct LowerCtx<'a> {
17 pub db: &'a dyn DefDatabase,
18 file_id: HirFileId,
19 span_map: OnceCell<SpanMap>,
20 ast_id_map: OnceCell<Arc<AstIdMap>>,
21 impl_trait_bounds: Vec<ThinVec<TypeBound>>,
22 outer_impl_trait: bool,
24 types_map: &'a mut TypesMap,
25 types_source_map: &'a mut TypesSourceMap,
26}
27
28impl<'a> LowerCtx<'a> {
29 pub fn new(
30 db: &'a dyn DefDatabase,
31 file_id: HirFileId,
32 types_map: &'a mut TypesMap,
33 types_source_map: &'a mut TypesSourceMap,
34 ) -> Self {
35 LowerCtx {
36 db,
37 file_id,
38 span_map: OnceCell::new(),
39 ast_id_map: OnceCell::new(),
40 impl_trait_bounds: Vec::new(),
41 outer_impl_trait: false,
42 types_map,
43 types_source_map,
44 }
45 }
46
47 pub fn with_span_map_cell(
48 db: &'a dyn DefDatabase,
49 file_id: HirFileId,
50 span_map: OnceCell<SpanMap>,
51 types_map: &'a mut TypesMap,
52 types_source_map: &'a mut TypesSourceMap,
53 ) -> Self {
54 LowerCtx {
55 db,
56 file_id,
57 span_map,
58 ast_id_map: OnceCell::new(),
59 impl_trait_bounds: Vec::new(),
60 outer_impl_trait: false,
61 types_map,
62 types_source_map,
63 }
64 }
65
66 pub fn for_synthetic_ast(
68 db: &'a dyn DefDatabase,
69 ast_id_map: Arc<AstIdMap>,
70 types_map: &'a mut TypesMap,
71 types_source_map: &'a mut TypesSourceMap,
72 ) -> Self {
73 let file_id = EditionedFileId::new(
74 FileId::from_raw(EditionedFileId::MAX_FILE_ID),
75 Edition::Edition2015,
76 );
77 LowerCtx {
78 db,
79 file_id: file_id.into(),
81 span_map: SpanMap::RealSpanMap(Arc::new(RealSpanMap::absolute(file_id))).into(),
82 ast_id_map: ast_id_map.into(),
83 impl_trait_bounds: Vec::new(),
84 outer_impl_trait: false,
85 types_map,
86 types_source_map,
87 }
88 }
89
90 pub(crate) fn span_map(&self) -> &SpanMap {
91 self.span_map.get_or_init(|| self.db.span_map(self.file_id))
92 }
93
94 pub(crate) fn lower_path(&mut self, ast: ast::Path) -> Option<Path> {
95 Path::from_src(self, ast)
96 }
97
98 pub(crate) fn ast_id<N: AstIdNode>(&self, item: &N) -> AstId<N> {
99 InFile::new(
100 self.file_id,
101 self.ast_id_map.get_or_init(|| self.db.ast_id_map(self.file_id)).ast_id(item),
102 )
103 }
104
105 pub fn update_impl_traits_bounds_from_type_ref(&mut self, type_ref: TypeRefId) {
106 TypeRef::walk(type_ref, self.types_map, &mut |tr| {
107 if let TypeRef::ImplTrait(bounds) = tr {
108 self.impl_trait_bounds.push(bounds.clone());
109 }
110 });
111 }
112
113 pub fn take_impl_traits_bounds(&mut self) -> Vec<ThinVec<TypeBound>> {
114 mem::take(&mut self.impl_trait_bounds)
115 }
116
117 pub(crate) fn outer_impl_trait(&self) -> bool {
118 self.outer_impl_trait
119 }
120
121 pub(crate) fn with_outer_impl_trait_scope<R>(
122 &mut self,
123 impl_trait: bool,
124 f: impl FnOnce(&mut Self) -> R,
125 ) -> R {
126 let old = mem::replace(&mut self.outer_impl_trait, impl_trait);
127 let result = f(self);
128 self.outer_impl_trait = old;
129 result
130 }
131
132 pub(crate) fn alloc_type_ref(&mut self, type_ref: TypeRef, node: TypePtr) -> TypeRefId {
133 let id = self.types_map.types.alloc(type_ref);
134 self.types_source_map.types_map_back.insert(id, InFile::new(self.file_id, node));
135 id
136 }
137
138 pub(crate) fn alloc_type_ref_desugared(&mut self, type_ref: TypeRef) -> TypeRefId {
139 self.types_map.types.alloc(type_ref)
140 }
141
142 pub(crate) fn alloc_error_type(&mut self) -> TypeRefId {
143 self.types_map.types.alloc(TypeRef::Error)
144 }
145
146 pub(crate) fn alloc_path(&mut self, path: Path, node: TypePtr) -> PathId {
147 PathId::from_type_ref_unchecked(self.alloc_type_ref(TypeRef::Path(path), node))
148 }
149}