1 //! AST -> `ItemTree` lowering code.
3 use std
::{collections::hash_map::Entry, sync::Arc}
;
5 use hir_expand
::{ast_id_map::AstIdMap, hygiene::Hygiene, HirFileId}
;
6 use syntax
::ast
::{self, HasModuleItem}
;
9 generics
::{GenericParams, TypeParamData, TypeParamProvenance}
,
10 type_ref
::{LifetimeRef, TraitBoundModifier, TraitRef}
,
15 fn id
<N
: ItemTreeNode
>(index
: Idx
<N
>) -> FileItemTreeId
<N
> {
16 FileItemTreeId { index, _p: PhantomData }
19 pub(super) struct Ctx
<'a
> {
20 db
: &'a
dyn DefDatabase
,
22 source_ast_id_map
: Arc
<AstIdMap
>,
23 body_ctx
: crate::body
::LowerCtx
<'a
>,
27 pub(super) fn new(db
: &'a
dyn DefDatabase
, file
: HirFileId
) -> Self {
30 tree
: ItemTree
::default(),
31 source_ast_id_map
: db
.ast_id_map(file
),
32 body_ctx
: crate::body
::LowerCtx
::new(db
, file
),
36 pub(super) fn hygiene(&self) -> &Hygiene
{
37 self.body_ctx
.hygiene()
40 pub(super) fn lower_module_items(mut self, item_owner
: &dyn HasModuleItem
) -> ItemTree
{
42 item_owner
.items().flat_map(|item
| self.lower_mod_item(&item
)).collect();
46 pub(super) fn lower_macro_stmts(mut self, stmts
: ast
::MacroStmts
) -> ItemTree
{
47 self.tree
.top_level
= stmts
51 ast
::Stmt
::Item(item
) => Some(item
),
52 // Macro calls can be both items and expressions. The syntax library always treats
53 // them as expressions here, so we undo that.
54 ast
::Stmt
::ExprStmt(es
) => match es
.expr()?
{
55 ast
::Expr
::MacroExpr(expr
) => {
56 cov_mark
::hit
!(macro_call_in_macro_stmts_is_added_to_item_tree
);
57 Some(expr
.macro_call()?
.into())
64 .flat_map(|item
| self.lower_mod_item(&item
))
67 if let Some(ast
::Expr
::MacroExpr(tail_macro
)) = stmts
.expr() {
68 if let Some(call
) = tail_macro
.macro_call() {
69 cov_mark
::hit
!(macro_stmt_with_trailing_macro_expr
);
70 if let Some(mod_item
) = self.lower_mod_item(&call
.into()) {
71 self.tree
.top_level
.push(mod_item
);
79 pub(super) fn lower_block(mut self, block
: &ast
::BlockExpr
) -> ItemTree
{
80 self.tree
.top_level
= block
82 .filter_map(|stmt
| match stmt
{
83 ast
::Stmt
::Item(item
) => self.lower_mod_item(&item
),
84 // Macro calls can be both items and expressions. The syntax library always treats
85 // them as expressions here, so we undo that.
86 ast
::Stmt
::ExprStmt(es
) => match es
.expr()?
{
87 ast
::Expr
::MacroExpr(expr
) => self.lower_mod_item(&expr
.macro_call()?
.into()),
97 fn data(&mut self) -> &mut ItemTreeData
{
101 fn lower_mod_item(&mut self, item
: &ast
::Item
) -> Option
<ModItem
> {
102 let attrs
= RawAttrs
::new(self.db
, item
, self.hygiene());
103 let item
: ModItem
= match item
{
104 ast
::Item
::Struct(ast
) => self.lower_struct(ast
)?
.into(),
105 ast
::Item
::Union(ast
) => self.lower_union(ast
)?
.into(),
106 ast
::Item
::Enum(ast
) => self.lower_enum(ast
)?
.into(),
107 ast
::Item
::Fn(ast
) => self.lower_function(ast
)?
.into(),
108 ast
::Item
::TypeAlias(ast
) => self.lower_type_alias(ast
)?
.into(),
109 ast
::Item
::Static(ast
) => self.lower_static(ast
)?
.into(),
110 ast
::Item
::Const(ast
) => self.lower_const(ast
).into(),
111 ast
::Item
::Module(ast
) => self.lower_module(ast
)?
.into(),
112 ast
::Item
::Trait(ast
) => self.lower_trait(ast
)?
.into(),
113 ast
::Item
::Impl(ast
) => self.lower_impl(ast
)?
.into(),
114 ast
::Item
::Use(ast
) => self.lower_use(ast
)?
.into(),
115 ast
::Item
::ExternCrate(ast
) => self.lower_extern_crate(ast
)?
.into(),
116 ast
::Item
::MacroCall(ast
) => self.lower_macro_call(ast
)?
.into(),
117 ast
::Item
::MacroRules(ast
) => self.lower_macro_rules(ast
)?
.into(),
118 ast
::Item
::MacroDef(ast
) => self.lower_macro_def(ast
)?
.into(),
119 ast
::Item
::ExternBlock(ast
) => self.lower_extern_block(ast
).into(),
122 self.add_attrs(item
.into(), attrs
);
127 fn add_attrs(&mut self, item
: AttrOwner
, attrs
: RawAttrs
) {
128 match self.tree
.attrs
.entry(item
) {
129 Entry
::Occupied(mut entry
) => {
130 *entry
.get_mut() = entry
.get().merge(attrs
);
132 Entry
::Vacant(entry
) => {
138 fn lower_assoc_item(&mut self, item
: &ast
::AssocItem
) -> Option
<AssocItem
> {
140 ast
::AssocItem
::Fn(ast
) => self.lower_function(ast
).map(Into
::into
),
141 ast
::AssocItem
::TypeAlias(ast
) => self.lower_type_alias(ast
).map(Into
::into
),
142 ast
::AssocItem
::Const(ast
) => Some(self.lower_const(ast
).into()),
143 ast
::AssocItem
::MacroCall(ast
) => self.lower_macro_call(ast
).map(Into
::into
),
147 fn lower_struct(&mut self, strukt
: &ast
::Struct
) -> Option
<FileItemTreeId
<Struct
>> {
148 let visibility
= self.lower_visibility(strukt
);
149 let name
= strukt
.name()?
.as_name();
150 let generic_params
= self.lower_generic_params(GenericsOwner
::Struct
, strukt
);
151 let fields
= self.lower_fields(&strukt
.kind());
152 let ast_id
= self.source_ast_id_map
.ast_id(strukt
);
153 let res
= Struct { name, visibility, generic_params, fields, ast_id }
;
154 Some(id(self.data().structs
.alloc(res
)))
157 fn lower_fields(&mut self, strukt_kind
: &ast
::StructKind
) -> Fields
{
159 ast
::StructKind
::Record(it
) => {
160 let range
= self.lower_record_fields(it
);
161 Fields
::Record(range
)
163 ast
::StructKind
::Tuple(it
) => {
164 let range
= self.lower_tuple_fields(it
);
167 ast
::StructKind
::Unit
=> Fields
::Unit
,
171 fn lower_record_fields(&mut self, fields
: &ast
::RecordFieldList
) -> IdxRange
<Field
> {
172 let start
= self.next_field_idx();
173 for field
in fields
.fields() {
174 if let Some(data
) = self.lower_record_field(&field
) {
175 let idx
= self.data().fields
.alloc(data
);
176 self.add_attrs(idx
.into(), RawAttrs
::new(self.db
, &field
, self.hygiene()));
179 let end
= self.next_field_idx();
180 IdxRange
::new(start
..end
)
183 fn lower_record_field(&mut self, field
: &ast
::RecordField
) -> Option
<Field
> {
184 let name
= field
.name()?
.as_name();
185 let visibility
= self.lower_visibility(field
);
186 let type_ref
= self.lower_type_ref_opt(field
.ty());
187 let ast_id
= FieldAstId
::Record(self.source_ast_id_map
.ast_id(field
));
188 let res
= Field { name, type_ref, visibility, ast_id }
;
192 fn lower_tuple_fields(&mut self, fields
: &ast
::TupleFieldList
) -> IdxRange
<Field
> {
193 let start
= self.next_field_idx();
194 for (i
, field
) in fields
.fields().enumerate() {
195 let data
= self.lower_tuple_field(i
, &field
);
196 let idx
= self.data().fields
.alloc(data
);
197 self.add_attrs(idx
.into(), RawAttrs
::new(self.db
, &field
, self.hygiene()));
199 let end
= self.next_field_idx();
200 IdxRange
::new(start
..end
)
203 fn lower_tuple_field(&mut self, idx
: usize, field
: &ast
::TupleField
) -> Field
{
204 let name
= Name
::new_tuple_field(idx
);
205 let visibility
= self.lower_visibility(field
);
206 let type_ref
= self.lower_type_ref_opt(field
.ty());
207 let ast_id
= FieldAstId
::Tuple(self.source_ast_id_map
.ast_id(field
));
208 Field { name, type_ref, visibility, ast_id }
211 fn lower_union(&mut self, union: &ast
::Union
) -> Option
<FileItemTreeId
<Union
>> {
212 let visibility
= self.lower_visibility(union);
213 let name
= union.name()?
.as_name();
214 let generic_params
= self.lower_generic_params(GenericsOwner
::Union
, union);
215 let fields
= match union.record_field_list() {
216 Some(record_field_list
) => self.lower_fields(&StructKind
::Record(record_field_list
)),
217 None
=> Fields
::Record(IdxRange
::new(self.next_field_idx()..self.next_field_idx())),
219 let ast_id
= self.source_ast_id_map
.ast_id(union);
220 let res
= Union { name, visibility, generic_params, fields, ast_id }
;
221 Some(id(self.data().unions
.alloc(res
)))
224 fn lower_enum(&mut self, enum_
: &ast
::Enum
) -> Option
<FileItemTreeId
<Enum
>> {
225 let visibility
= self.lower_visibility(enum_
);
226 let name
= enum_
.name()?
.as_name();
227 let generic_params
= self.lower_generic_params(GenericsOwner
::Enum
, enum_
);
228 let variants
= match &enum_
.variant_list() {
229 Some(variant_list
) => self.lower_variants(variant_list
),
230 None
=> IdxRange
::new(self.next_variant_idx()..self.next_variant_idx()),
232 let ast_id
= self.source_ast_id_map
.ast_id(enum_
);
233 let res
= Enum { name, visibility, generic_params, variants, ast_id }
;
234 Some(id(self.data().enums
.alloc(res
)))
237 fn lower_variants(&mut self, variants
: &ast
::VariantList
) -> IdxRange
<Variant
> {
238 let start
= self.next_variant_idx();
239 for variant
in variants
.variants() {
240 if let Some(data
) = self.lower_variant(&variant
) {
241 let idx
= self.data().variants
.alloc(data
);
242 self.add_attrs(idx
.into(), RawAttrs
::new(self.db
, &variant
, self.hygiene()));
245 let end
= self.next_variant_idx();
246 IdxRange
::new(start
..end
)
249 fn lower_variant(&mut self, variant
: &ast
::Variant
) -> Option
<Variant
> {
250 let name
= variant
.name()?
.as_name();
251 let fields
= self.lower_fields(&variant
.kind());
252 let ast_id
= self.source_ast_id_map
.ast_id(variant
);
253 let res
= Variant { name, fields, ast_id }
;
257 fn lower_function(&mut self, func
: &ast
::Fn
) -> Option
<FileItemTreeId
<Function
>> {
258 let visibility
= self.lower_visibility(func
);
259 let name
= func
.name()?
.as_name();
261 let mut has_self_param
= false;
262 let start_param
= self.next_param_idx();
263 if let Some(param_list
) = func
.param_list() {
264 if let Some(self_param
) = param_list
.self_param() {
265 let self_type
= match self_param
.ty() {
266 Some(type_ref
) => TypeRef
::from_ast(&self.body_ctx
, type_ref
),
268 let self_type
= TypeRef
::Path(name
![Self].into());
269 match self_param
.kind() {
270 ast
::SelfParamKind
::Owned
=> self_type
,
271 ast
::SelfParamKind
::Ref
=> TypeRef
::Reference(
273 self_param
.lifetime().as_ref().map(LifetimeRef
::new
),
276 ast
::SelfParamKind
::MutRef
=> TypeRef
::Reference(
278 self_param
.lifetime().as_ref().map(LifetimeRef
::new
),
284 let ty
= Interned
::new(self_type
);
285 let idx
= self.data().params
.alloc(Param
::Normal(None
, ty
));
286 self.add_attrs(idx
.into(), RawAttrs
::new(self.db
, &self_param
, self.hygiene()));
287 has_self_param
= true;
289 for param
in param_list
.params() {
290 let idx
= match param
.dotdotdot_token() {
291 Some(_
) => self.data().params
.alloc(Param
::Varargs
),
293 let type_ref
= TypeRef
::from_ast_opt(&self.body_ctx
, param
.ty());
294 let ty
= Interned
::new(type_ref
);
295 let mut pat
= param
.pat();
296 // FIXME: This really shouldn't be here, in fact FunctionData/ItemTree's function shouldn't know about
297 // pattern names at all
298 let name
= 'name
: loop {
300 Some(ast
::Pat
::RefPat(ref_pat
)) => pat
= ref_pat
.pat(),
301 Some(ast
::Pat
::IdentPat(ident
)) => {
302 break 'name ident
.name().map(|it
| it
.as_name())
304 _
=> break 'name None
,
307 self.data().params
.alloc(Param
::Normal(name
, ty
))
310 self.add_attrs(idx
.into(), RawAttrs
::new(self.db
, ¶m
, self.hygiene()));
313 let end_param
= self.next_param_idx();
314 let params
= IdxRange
::new(start_param
..end_param
);
316 let ret_type
= match func
.ret_type() {
317 Some(rt
) => match rt
.ty() {
318 Some(type_ref
) => TypeRef
::from_ast(&self.body_ctx
, type_ref
),
319 None
if rt
.thin_arrow_token().is_some() => TypeRef
::Error
,
320 None
=> TypeRef
::unit(),
322 None
=> TypeRef
::unit(),
325 let (ret_type
, async_ret_type
) = if func
.async_token().is_some() {
326 let async_ret_type
= ret_type
.clone();
327 let future_impl
= desugar_future_path(ret_type
);
328 let ty_bound
= Interned
::new(TypeBound
::Path(future_impl
, TraitBoundModifier
::None
));
329 (TypeRef
::ImplTrait(vec
![ty_bound
]), Some(async_ret_type
))
334 let abi
= func
.abi().map(lower_abi
);
336 let ast_id
= self.source_ast_id_map
.ast_id(func
);
338 let mut flags
= FnFlags
::default();
339 if func
.body().is_some() {
340 flags
|= FnFlags
::HAS_BODY
;
343 flags
|= FnFlags
::HAS_SELF_PARAM
;
345 if func
.default_token().is_some() {
346 flags
|= FnFlags
::HAS_DEFAULT_KW
;
348 if func
.const_token().is_some() {
349 flags
|= FnFlags
::HAS_CONST_KW
;
351 if func
.async_token().is_some() {
352 flags
|= FnFlags
::HAS_ASYNC_KW
;
354 if func
.unsafe_token().is_some() {
355 flags
|= FnFlags
::HAS_UNSAFE_KW
;
358 let mut res
= Function
{
361 explicit_generic_params
: Interned
::new(GenericParams
::default()),
364 ret_type
: Interned
::new(ret_type
),
365 async_ret_type
: async_ret_type
.map(Interned
::new
),
369 res
.explicit_generic_params
=
370 self.lower_generic_params(GenericsOwner
::Function(&res
), func
);
372 Some(id(self.data().functions
.alloc(res
)))
377 type_alias
: &ast
::TypeAlias
,
378 ) -> Option
<FileItemTreeId
<TypeAlias
>> {
379 let name
= type_alias
.name()?
.as_name();
380 let type_ref
= type_alias
.ty().map(|it
| self.lower_type_ref(&it
));
381 let visibility
= self.lower_visibility(type_alias
);
382 let bounds
= self.lower_type_bounds(type_alias
);
383 let generic_params
= self.lower_generic_params(GenericsOwner
::TypeAlias
, type_alias
);
384 let ast_id
= self.source_ast_id_map
.ast_id(type_alias
);
385 let res
= TypeAlias
{
388 bounds
: bounds
.into_boxed_slice(),
393 Some(id(self.data().type_aliases
.alloc(res
)))
396 fn lower_static(&mut self, static_
: &ast
::Static
) -> Option
<FileItemTreeId
<Static
>> {
397 let name
= static_
.name()?
.as_name();
398 let type_ref
= self.lower_type_ref_opt(static_
.ty());
399 let visibility
= self.lower_visibility(static_
);
400 let mutable
= static_
.mut_token().is_some();
401 let ast_id
= self.source_ast_id_map
.ast_id(static_
);
402 let res
= Static { name, visibility, mutable, type_ref, ast_id }
;
403 Some(id(self.data().statics
.alloc(res
)))
406 fn lower_const(&mut self, konst
: &ast
::Const
) -> FileItemTreeId
<Const
> {
407 let name
= konst
.name().map(|it
| it
.as_name());
408 let type_ref
= self.lower_type_ref_opt(konst
.ty());
409 let visibility
= self.lower_visibility(konst
);
410 let ast_id
= self.source_ast_id_map
.ast_id(konst
);
411 let res
= Const { name, visibility, type_ref, ast_id }
;
412 id(self.data().consts
.alloc(res
))
415 fn lower_module(&mut self, module
: &ast
::Module
) -> Option
<FileItemTreeId
<Mod
>> {
416 let name
= module
.name()?
.as_name();
417 let visibility
= self.lower_visibility(module
);
418 let kind
= if module
.semicolon_token().is_some() {
424 .map(|list
| list
.items().flat_map(|item
| self.lower_mod_item(&item
)).collect())
426 cov_mark
::hit
!(name_res_works_for_broken_modules
);
427 Box
::new([]) as Box
<[_
]>
431 let ast_id
= self.source_ast_id_map
.ast_id(module
);
432 let res
= Mod { name, visibility, kind, ast_id }
;
433 Some(id(self.data().mods
.alloc(res
)))
436 fn lower_trait(&mut self, trait_def
: &ast
::Trait
) -> Option
<FileItemTreeId
<Trait
>> {
437 let name
= trait_def
.name()?
.as_name();
438 let visibility
= self.lower_visibility(trait_def
);
439 let generic_params
= self.lower_generic_params(GenericsOwner
::Trait(trait_def
), trait_def
);
440 let is_auto
= trait_def
.auto_token().is_some();
441 let is_unsafe
= trait_def
.unsafe_token().is_some();
442 let items
= trait_def
.assoc_item_list().map(|list
| {
445 let attrs
= RawAttrs
::new(self.db
, &item
, self.hygiene());
446 self.lower_assoc_item(&item
).map(|item
| {
447 self.add_attrs(ModItem
::from(item
).into(), attrs
);
453 let ast_id
= self.source_ast_id_map
.ast_id(trait_def
);
460 items
: items
.unwrap_or_default(),
463 Some(id(self.data().traits
.alloc(res
)))
466 fn lower_impl(&mut self, impl_def
: &ast
::Impl
) -> Option
<FileItemTreeId
<Impl
>> {
467 let generic_params
= self.lower_generic_params(GenericsOwner
::Impl
, impl_def
);
468 // FIXME: If trait lowering fails, due to a non PathType for example, we treat this impl
469 // as if it was an non-trait impl. Ideally we want to create a unique missing ref that only
471 let target_trait
= impl_def
.trait_().and_then(|tr
| self.lower_trait_ref(&tr
));
472 let self_ty
= self.lower_type_ref(&impl_def
.self_ty()?
);
473 let is_negative
= impl_def
.excl_token().is_some();
475 // We cannot use `assoc_items()` here as that does not include macro calls.
479 .flat_map(|it
| it
.assoc_items())
481 let assoc
= self.lower_assoc_item(&item
)?
;
482 let attrs
= RawAttrs
::new(self.db
, &item
, self.hygiene());
483 self.add_attrs(ModItem
::from(assoc
).into(), attrs
);
487 let ast_id
= self.source_ast_id_map
.ast_id(impl_def
);
488 let res
= Impl { generic_params, target_trait, self_ty, is_negative, items, ast_id }
;
489 Some(id(self.data().impls
.alloc(res
)))
492 fn lower_use(&mut self, use_item
: &ast
::Use
) -> Option
<FileItemTreeId
<Import
>> {
493 let visibility
= self.lower_visibility(use_item
);
494 let ast_id
= self.source_ast_id_map
.ast_id(use_item
);
495 let (use_tree
, _
) = lower_use_tree(self.db
, self.hygiene(), use_item
.use_tree()?
)?
;
497 let res
= Import { visibility, ast_id, use_tree }
;
498 Some(id(self.data().imports
.alloc(res
)))
501 fn lower_extern_crate(
503 extern_crate
: &ast
::ExternCrate
,
504 ) -> Option
<FileItemTreeId
<ExternCrate
>> {
505 let name
= extern_crate
.name_ref()?
.as_name();
506 let alias
= extern_crate
.rename().map(|a
| {
507 a
.name().map(|it
| it
.as_name()).map_or(ImportAlias
::Underscore
, ImportAlias
::Alias
)
509 let visibility
= self.lower_visibility(extern_crate
);
510 let ast_id
= self.source_ast_id_map
.ast_id(extern_crate
);
512 let res
= ExternCrate { name, alias, visibility, ast_id }
;
513 Some(id(self.data().extern_crates
.alloc(res
)))
516 fn lower_macro_call(&mut self, m
: &ast
::MacroCall
) -> Option
<FileItemTreeId
<MacroCall
>> {
517 let path
= Interned
::new(ModPath
::from_src(self.db
.upcast(), m
.path()?
, self.hygiene())?
);
518 let ast_id
= self.source_ast_id_map
.ast_id(m
);
519 let expand_to
= hir_expand
::ExpandTo
::from_call_site(m
);
520 let res
= MacroCall { path, ast_id, expand_to }
;
521 Some(id(self.data().macro_calls
.alloc(res
)))
524 fn lower_macro_rules(&mut self, m
: &ast
::MacroRules
) -> Option
<FileItemTreeId
<MacroRules
>> {
525 let name
= m
.name().map(|it
| it
.as_name())?
;
526 let ast_id
= self.source_ast_id_map
.ast_id(m
);
528 let res
= MacroRules { name, ast_id }
;
529 Some(id(self.data().macro_rules
.alloc(res
)))
532 fn lower_macro_def(&mut self, m
: &ast
::MacroDef
) -> Option
<FileItemTreeId
<MacroDef
>> {
533 let name
= m
.name().map(|it
| it
.as_name())?
;
535 let ast_id
= self.source_ast_id_map
.ast_id(m
);
536 let visibility
= self.lower_visibility(m
);
538 let res
= MacroDef { name, ast_id, visibility }
;
539 Some(id(self.data().macro_defs
.alloc(res
)))
542 fn lower_extern_block(&mut self, block
: &ast
::ExternBlock
) -> FileItemTreeId
<ExternBlock
> {
543 let ast_id
= self.source_ast_id_map
.ast_id(block
);
544 let abi
= block
.abi().map(lower_abi
);
545 let children
: Box
<[_
]> = block
.extern_item_list().map_or(Box
::new([]), |list
| {
548 // Note: All items in an `extern` block need to be lowered as if they're outside of one
549 // (in other words, the knowledge that they're in an extern block must not be used).
550 // This is because an extern block can contain macros whose ItemTree's top-level items
551 // should be considered to be in an extern block too.
552 let attrs
= RawAttrs
::new(self.db
, &item
, self.hygiene());
553 let id
: ModItem
= match item
{
554 ast
::ExternItem
::Fn(ast
) => self.lower_function(&ast
)?
.into(),
555 ast
::ExternItem
::Static(ast
) => self.lower_static(&ast
)?
.into(),
556 ast
::ExternItem
::TypeAlias(ty
) => self.lower_type_alias(&ty
)?
.into(),
557 ast
::ExternItem
::MacroCall(call
) => self.lower_macro_call(&call
)?
.into(),
559 self.add_attrs(id
.into(), attrs
);
565 let res
= ExternBlock { abi, ast_id, children }
;
566 id(self.data().extern_blocks
.alloc(res
))
569 fn lower_generic_params(
571 owner
: GenericsOwner
<'_
>,
572 node
: &dyn ast
::HasGenericParams
,
573 ) -> Interned
<GenericParams
> {
574 let mut generics
= GenericParams
::default();
576 GenericsOwner
::Function(_
)
577 | GenericsOwner
::Struct
578 | GenericsOwner
::Enum
579 | GenericsOwner
::Union
580 | GenericsOwner
::TypeAlias
=> {
581 generics
.fill(&self.body_ctx
, node
);
583 GenericsOwner
::Trait(trait_def
) => {
584 // traits get the Self type as an implicit first type parameter
585 generics
.type_or_consts
.alloc(
587 name
: Some(name
![Self]),
589 provenance
: TypeParamProvenance
::TraitSelf
,
593 // add super traits as bounds on Self
594 // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar
595 let self_param
= TypeRef
::Path(name
![Self].into());
596 generics
.fill_bounds(&self.body_ctx
, trait_def
, Either
::Left(self_param
));
597 generics
.fill(&self.body_ctx
, node
);
599 GenericsOwner
::Impl
=> {
600 // Note that we don't add `Self` here: in `impl`s, `Self` is not a
601 // type-parameter, but rather is a type-alias for impl's target
602 // type, so this is handled by the resolver.
603 generics
.fill(&self.body_ctx
, node
);
607 generics
.shrink_to_fit();
608 Interned
::new(generics
)
611 fn lower_type_bounds(&mut self, node
: &dyn ast
::HasTypeBounds
) -> Vec
<Interned
<TypeBound
>> {
612 match node
.type_bound_list() {
613 Some(bound_list
) => bound_list
615 .map(|it
| Interned
::new(TypeBound
::from_ast(&self.body_ctx
, it
)))
621 fn lower_visibility(&mut self, item
: &dyn ast
::HasVisibility
) -> RawVisibilityId
{
622 let vis
= RawVisibility
::from_ast_with_hygiene(self.db
, item
.visibility(), self.hygiene());
623 self.data().vis
.alloc(vis
)
626 fn lower_trait_ref(&mut self, trait_ref
: &ast
::Type
) -> Option
<Interned
<TraitRef
>> {
627 let trait_ref
= TraitRef
::from_ast(&self.body_ctx
, trait_ref
.clone())?
;
628 Some(Interned
::new(trait_ref
))
631 fn lower_type_ref(&mut self, type_ref
: &ast
::Type
) -> Interned
<TypeRef
> {
632 let tyref
= TypeRef
::from_ast(&self.body_ctx
, type_ref
.clone());
636 fn lower_type_ref_opt(&mut self, type_ref
: Option
<ast
::Type
>) -> Interned
<TypeRef
> {
637 match type_ref
.map(|ty
| self.lower_type_ref(&ty
)) {
639 None
=> Interned
::new(TypeRef
::Error
),
643 fn next_field_idx(&self) -> Idx
<Field
> {
644 Idx
::from_raw(RawIdx
::from(
645 self.tree
.data
.as_ref().map_or(0, |data
| data
.fields
.len() as u32),
648 fn next_variant_idx(&self) -> Idx
<Variant
> {
649 Idx
::from_raw(RawIdx
::from(
650 self.tree
.data
.as_ref().map_or(0, |data
| data
.variants
.len() as u32),
653 fn next_param_idx(&self) -> Idx
<Param
> {
654 Idx
::from_raw(RawIdx
::from(
655 self.tree
.data
.as_ref().map_or(0, |data
| data
.params
.len() as u32),
660 fn desugar_future_path(orig
: TypeRef
) -> Path
{
661 let path
= path
![core
::future
::Future
];
662 let mut generic_args
: Vec
<_
> =
663 std
::iter
::repeat(None
).take(path
.segments().len() - 1).collect();
664 let mut last
= GenericArgs
::empty();
666 AssociatedTypeBinding { name: name![Output], type_ref: Some(orig), bounds: Vec::new() }
;
667 last
.bindings
.push(binding
);
668 generic_args
.push(Some(Interned
::new(last
)));
670 Path
::from_known_path(path
, generic_args
)
673 enum GenericsOwner
<'a
> {
674 /// We need access to the partially-lowered `Function` for lowering `impl Trait` in argument
676 Function(&'a Function
),
680 /// The `TraitDef` is needed to fill the source map for the implicit `Self` parameter.
681 Trait(&'a ast
::Trait
),
686 fn lower_abi(abi
: ast
::Abi
) -> Interned
<str> {
687 // FIXME: Abi::abi() -> Option<SyntaxToken>?
688 match abi
.syntax().last_token() {
689 Some(tok
) if tok
.kind() == SyntaxKind
::STRING
=> {
690 // FIXME: Better way to unescape?
691 Interned
::new_str(tok
.text().trim_matches('
"'))
694 // `extern` default to be `extern "C
"`.
695 Interned::new_str("C
")
700 struct UseTreeLowering<'a> {
701 db: &'a dyn DefDatabase,
702 hygiene: &'a Hygiene,
703 mapping: Arena<ast::UseTree>,
706 impl UseTreeLowering<'_> {
707 fn lower_use_tree(&mut self, tree: ast::UseTree) -> Option<UseTree> {
708 if let Some(use_tree_list) = tree.use_tree_list() {
709 let prefix = match tree.path() {
710 // E.g. use something::{{{inner}}};
712 // E.g. `use something::{inner}` (prefix is `None`, path is `something`)
713 // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`)
715 match ModPath::from_src(self.db.upcast(), path, self.hygiene) {
716 Some(it) => Some(it),
717 None => return None, // FIXME: report errors somewhere
723 use_tree_list.use_trees().filter_map(|tree| self.lower_use_tree(tree)).collect();
727 UseTreeKind::Prefixed { prefix: prefix.map(Interned::new), list },
732 let is_glob = tree.star_token().is_some();
733 let path = match tree.path() {
734 Some(path) => Some(ModPath::from_src(self.db.upcast(), path, self.hygiene)?),
737 let alias = tree.rename().map(|a| {
738 a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias)
740 if alias.is_some() && is_glob {
744 match (path, alias, is_glob) {
745 (path, None, true) => {
747 cov_mark::hit!(glob_enum_group);
749 Some(self.use_tree(UseTreeKind::Glob { path: path.map(Interned::new) }, tree))
751 // Globs can't be renamed
752 (_, Some(_), true) | (None, None, false) => None,
753 // `bla::{ as Name}` is invalid
754 (None, Some(_), false) => None,
755 (Some(path), alias, false) => Some(
756 self.use_tree(UseTreeKind::Single { path: Interned::new(path), alias }, tree),
762 fn use_tree(&mut self, kind: UseTreeKind, ast: ast::UseTree) -> UseTree {
763 let index = self.mapping.alloc(ast);
764 UseTree { index, kind }
768 pub(super) fn lower_use_tree(
769 db: &dyn DefDatabase,
772 ) -> Option<(UseTree, Arena<ast::UseTree>)> {
773 let mut lowering = UseTreeLowering { db, hygiene, mapping: Arena::new() };
774 let tree = lowering.lower_use_tree(tree)?;
775 Some((tree, lowering.mapping))