1 //! AST -> `ItemTree` lowering code.
3 use std
::collections
::hash_map
::Entry
;
5 use hir_expand
::{ast_id_map::AstIdMap, hygiene::Hygiene, HirFileId}
;
6 use syntax
::ast
::{self, HasModuleItem, HasTypeBounds}
;
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::lower
::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::lower
::LowerCtx
::with_file_id(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
{
82 .insert(AttrOwner
::TopLevel
, RawAttrs
::new(self.db
.upcast(), block
, self.hygiene()));
83 self.tree
.top_level
= block
85 .filter_map(|stmt
| match stmt
{
86 ast
::Stmt
::Item(item
) => self.lower_mod_item(&item
),
87 // Macro calls can be both items and expressions. The syntax library always treats
88 // them as expressions here, so we undo that.
89 ast
::Stmt
::ExprStmt(es
) => match es
.expr()?
{
90 ast
::Expr
::MacroExpr(expr
) => self.lower_mod_item(&expr
.macro_call()?
.into()),
96 if let Some(ast
::Expr
::MacroExpr(expr
)) = block
.tail_expr() {
97 if let Some(call
) = expr
.macro_call() {
98 if let Some(mod_item
) = self.lower_mod_item(&call
.into()) {
99 self.tree
.top_level
.push(mod_item
);
107 fn data(&mut self) -> &mut ItemTreeData
{
111 fn lower_mod_item(&mut self, item
: &ast
::Item
) -> Option
<ModItem
> {
112 let attrs
= RawAttrs
::new(self.db
.upcast(), item
, self.hygiene());
113 let item
: ModItem
= match item
{
114 ast
::Item
::Struct(ast
) => self.lower_struct(ast
)?
.into(),
115 ast
::Item
::Union(ast
) => self.lower_union(ast
)?
.into(),
116 ast
::Item
::Enum(ast
) => self.lower_enum(ast
)?
.into(),
117 ast
::Item
::Fn(ast
) => self.lower_function(ast
)?
.into(),
118 ast
::Item
::TypeAlias(ast
) => self.lower_type_alias(ast
)?
.into(),
119 ast
::Item
::Static(ast
) => self.lower_static(ast
)?
.into(),
120 ast
::Item
::Const(ast
) => self.lower_const(ast
).into(),
121 ast
::Item
::Module(ast
) => self.lower_module(ast
)?
.into(),
122 ast
::Item
::Trait(ast
) => self.lower_trait(ast
)?
.into(),
123 ast
::Item
::TraitAlias(ast
) => self.lower_trait_alias(ast
)?
.into(),
124 ast
::Item
::Impl(ast
) => self.lower_impl(ast
)?
.into(),
125 ast
::Item
::Use(ast
) => self.lower_use(ast
)?
.into(),
126 ast
::Item
::ExternCrate(ast
) => self.lower_extern_crate(ast
)?
.into(),
127 ast
::Item
::MacroCall(ast
) => self.lower_macro_call(ast
)?
.into(),
128 ast
::Item
::MacroRules(ast
) => self.lower_macro_rules(ast
)?
.into(),
129 ast
::Item
::MacroDef(ast
) => self.lower_macro_def(ast
)?
.into(),
130 ast
::Item
::ExternBlock(ast
) => self.lower_extern_block(ast
).into(),
133 self.add_attrs(item
.into(), attrs
);
138 fn add_attrs(&mut self, item
: AttrOwner
, attrs
: RawAttrs
) {
139 match self.tree
.attrs
.entry(item
) {
140 Entry
::Occupied(mut entry
) => {
141 *entry
.get_mut() = entry
.get().merge(attrs
);
143 Entry
::Vacant(entry
) => {
149 fn lower_assoc_item(&mut self, item
: &ast
::AssocItem
) -> Option
<AssocItem
> {
151 ast
::AssocItem
::Fn(ast
) => self.lower_function(ast
).map(Into
::into
),
152 ast
::AssocItem
::TypeAlias(ast
) => self.lower_type_alias(ast
).map(Into
::into
),
153 ast
::AssocItem
::Const(ast
) => Some(self.lower_const(ast
).into()),
154 ast
::AssocItem
::MacroCall(ast
) => self.lower_macro_call(ast
).map(Into
::into
),
158 fn lower_struct(&mut self, strukt
: &ast
::Struct
) -> Option
<FileItemTreeId
<Struct
>> {
159 let visibility
= self.lower_visibility(strukt
);
160 let name
= strukt
.name()?
.as_name();
161 let generic_params
= self.lower_generic_params(HasImplicitSelf
::No
, strukt
);
162 let fields
= self.lower_fields(&strukt
.kind());
163 let ast_id
= self.source_ast_id_map
.ast_id(strukt
);
164 let res
= Struct { name, visibility, generic_params, fields, ast_id }
;
165 Some(id(self.data().structs
.alloc(res
)))
168 fn lower_fields(&mut self, strukt_kind
: &ast
::StructKind
) -> Fields
{
170 ast
::StructKind
::Record(it
) => {
171 let range
= self.lower_record_fields(it
);
172 Fields
::Record(range
)
174 ast
::StructKind
::Tuple(it
) => {
175 let range
= self.lower_tuple_fields(it
);
178 ast
::StructKind
::Unit
=> Fields
::Unit
,
182 fn lower_record_fields(&mut self, fields
: &ast
::RecordFieldList
) -> IdxRange
<Field
> {
183 let start
= self.next_field_idx();
184 for field
in fields
.fields() {
185 if let Some(data
) = self.lower_record_field(&field
) {
186 let idx
= self.data().fields
.alloc(data
);
187 self.add_attrs(idx
.into(), RawAttrs
::new(self.db
.upcast(), &field
, self.hygiene()));
190 let end
= self.next_field_idx();
191 IdxRange
::new(start
..end
)
194 fn lower_record_field(&mut self, field
: &ast
::RecordField
) -> Option
<Field
> {
195 let name
= field
.name()?
.as_name();
196 let visibility
= self.lower_visibility(field
);
197 let type_ref
= self.lower_type_ref_opt(field
.ty());
198 let ast_id
= FieldAstId
::Record(self.source_ast_id_map
.ast_id(field
));
199 let res
= Field { name, type_ref, visibility, ast_id }
;
203 fn lower_tuple_fields(&mut self, fields
: &ast
::TupleFieldList
) -> IdxRange
<Field
> {
204 let start
= self.next_field_idx();
205 for (i
, field
) in fields
.fields().enumerate() {
206 let data
= self.lower_tuple_field(i
, &field
);
207 let idx
= self.data().fields
.alloc(data
);
208 self.add_attrs(idx
.into(), RawAttrs
::new(self.db
.upcast(), &field
, self.hygiene()));
210 let end
= self.next_field_idx();
211 IdxRange
::new(start
..end
)
214 fn lower_tuple_field(&mut self, idx
: usize, field
: &ast
::TupleField
) -> Field
{
215 let name
= Name
::new_tuple_field(idx
);
216 let visibility
= self.lower_visibility(field
);
217 let type_ref
= self.lower_type_ref_opt(field
.ty());
218 let ast_id
= FieldAstId
::Tuple(self.source_ast_id_map
.ast_id(field
));
219 Field { name, type_ref, visibility, ast_id }
222 fn lower_union(&mut self, union: &ast
::Union
) -> Option
<FileItemTreeId
<Union
>> {
223 let visibility
= self.lower_visibility(union);
224 let name
= union.name()?
.as_name();
225 let generic_params
= self.lower_generic_params(HasImplicitSelf
::No
, union);
226 let fields
= match union.record_field_list() {
227 Some(record_field_list
) => self.lower_fields(&StructKind
::Record(record_field_list
)),
228 None
=> Fields
::Record(IdxRange
::new(self.next_field_idx()..self.next_field_idx())),
230 let ast_id
= self.source_ast_id_map
.ast_id(union);
231 let res
= Union { name, visibility, generic_params, fields, ast_id }
;
232 Some(id(self.data().unions
.alloc(res
)))
235 fn lower_enum(&mut self, enum_
: &ast
::Enum
) -> Option
<FileItemTreeId
<Enum
>> {
236 let visibility
= self.lower_visibility(enum_
);
237 let name
= enum_
.name()?
.as_name();
238 let generic_params
= self.lower_generic_params(HasImplicitSelf
::No
, enum_
);
239 let variants
= match &enum_
.variant_list() {
240 Some(variant_list
) => self.lower_variants(variant_list
),
241 None
=> IdxRange
::new(self.next_variant_idx()..self.next_variant_idx()),
243 let ast_id
= self.source_ast_id_map
.ast_id(enum_
);
244 let res
= Enum { name, visibility, generic_params, variants, ast_id }
;
245 Some(id(self.data().enums
.alloc(res
)))
248 fn lower_variants(&mut self, variants
: &ast
::VariantList
) -> IdxRange
<Variant
> {
249 let start
= self.next_variant_idx();
250 for variant
in variants
.variants() {
251 if let Some(data
) = self.lower_variant(&variant
) {
252 let idx
= self.data().variants
.alloc(data
);
255 RawAttrs
::new(self.db
.upcast(), &variant
, self.hygiene()),
259 let end
= self.next_variant_idx();
260 IdxRange
::new(start
..end
)
263 fn lower_variant(&mut self, variant
: &ast
::Variant
) -> Option
<Variant
> {
264 let name
= variant
.name()?
.as_name();
265 let fields
= self.lower_fields(&variant
.kind());
266 let ast_id
= self.source_ast_id_map
.ast_id(variant
);
267 let res
= Variant { name, fields, ast_id }
;
271 fn lower_function(&mut self, func
: &ast
::Fn
) -> Option
<FileItemTreeId
<Function
>> {
272 let visibility
= self.lower_visibility(func
);
273 let name
= func
.name()?
.as_name();
275 let mut has_self_param
= false;
276 let start_param
= self.next_param_idx();
277 if let Some(param_list
) = func
.param_list() {
278 if let Some(self_param
) = param_list
.self_param() {
279 let self_type
= match self_param
.ty() {
280 Some(type_ref
) => TypeRef
::from_ast(&self.body_ctx
, type_ref
),
282 let self_type
= TypeRef
::Path(name
![Self].into());
283 match self_param
.kind() {
284 ast
::SelfParamKind
::Owned
=> self_type
,
285 ast
::SelfParamKind
::Ref
=> TypeRef
::Reference(
287 self_param
.lifetime().as_ref().map(LifetimeRef
::new
),
290 ast
::SelfParamKind
::MutRef
=> TypeRef
::Reference(
292 self_param
.lifetime().as_ref().map(LifetimeRef
::new
),
298 let ty
= Interned
::new(self_type
);
299 let idx
= self.data().params
.alloc(Param
::Normal(ty
));
302 RawAttrs
::new(self.db
.upcast(), &self_param
, self.hygiene()),
304 has_self_param
= true;
306 for param
in param_list
.params() {
307 let idx
= match param
.dotdotdot_token() {
308 Some(_
) => self.data().params
.alloc(Param
::Varargs
),
310 let type_ref
= TypeRef
::from_ast_opt(&self.body_ctx
, param
.ty());
311 let ty
= Interned
::new(type_ref
);
312 self.data().params
.alloc(Param
::Normal(ty
))
315 self.add_attrs(idx
.into(), RawAttrs
::new(self.db
.upcast(), ¶m
, self.hygiene()));
318 let end_param
= self.next_param_idx();
319 let params
= IdxRange
::new(start_param
..end_param
);
321 let ret_type
= match func
.ret_type() {
322 Some(rt
) => match rt
.ty() {
323 Some(type_ref
) => TypeRef
::from_ast(&self.body_ctx
, type_ref
),
324 None
if rt
.thin_arrow_token().is_some() => TypeRef
::Error
,
325 None
=> TypeRef
::unit(),
327 None
=> TypeRef
::unit(),
330 let ret_type
= if func
.async_token().is_some() {
331 let future_impl
= desugar_future_path(ret_type
);
332 let ty_bound
= Interned
::new(TypeBound
::Path(future_impl
, TraitBoundModifier
::None
));
333 TypeRef
::ImplTrait(vec
![ty_bound
])
338 let abi
= func
.abi().map(lower_abi
);
340 let ast_id
= self.source_ast_id_map
.ast_id(func
);
342 let mut flags
= FnFlags
::default();
343 if func
.body().is_some() {
344 flags
|= FnFlags
::HAS_BODY
;
347 flags
|= FnFlags
::HAS_SELF_PARAM
;
349 if func
.default_token().is_some() {
350 flags
|= FnFlags
::HAS_DEFAULT_KW
;
352 if func
.const_token().is_some() {
353 flags
|= FnFlags
::HAS_CONST_KW
;
355 if func
.async_token().is_some() {
356 flags
|= FnFlags
::HAS_ASYNC_KW
;
358 if func
.unsafe_token().is_some() {
359 flags
|= FnFlags
::HAS_UNSAFE_KW
;
362 let mut res
= Function
{
365 explicit_generic_params
: Interned
::new(GenericParams
::default()),
368 ret_type
: Interned
::new(ret_type
),
372 res
.explicit_generic_params
= self.lower_generic_params(HasImplicitSelf
::No
, func
);
374 Some(id(self.data().functions
.alloc(res
)))
379 type_alias
: &ast
::TypeAlias
,
380 ) -> Option
<FileItemTreeId
<TypeAlias
>> {
381 let name
= type_alias
.name()?
.as_name();
382 let type_ref
= type_alias
.ty().map(|it
| self.lower_type_ref(&it
));
383 let visibility
= self.lower_visibility(type_alias
);
384 let bounds
= self.lower_type_bounds(type_alias
);
385 let generic_params
= self.lower_generic_params(HasImplicitSelf
::No
, type_alias
);
386 let ast_id
= self.source_ast_id_map
.ast_id(type_alias
);
387 let res
= TypeAlias
{
390 bounds
: bounds
.into_boxed_slice(),
395 Some(id(self.data().type_aliases
.alloc(res
)))
398 fn lower_static(&mut self, static_
: &ast
::Static
) -> Option
<FileItemTreeId
<Static
>> {
399 let name
= static_
.name()?
.as_name();
400 let type_ref
= self.lower_type_ref_opt(static_
.ty());
401 let visibility
= self.lower_visibility(static_
);
402 let mutable
= static_
.mut_token().is_some();
403 let ast_id
= self.source_ast_id_map
.ast_id(static_
);
404 let res
= Static { name, visibility, mutable, type_ref, ast_id }
;
405 Some(id(self.data().statics
.alloc(res
)))
408 fn lower_const(&mut self, konst
: &ast
::Const
) -> FileItemTreeId
<Const
> {
409 let name
= konst
.name().map(|it
| it
.as_name());
410 let type_ref
= self.lower_type_ref_opt(konst
.ty());
411 let visibility
= self.lower_visibility(konst
);
412 let ast_id
= self.source_ast_id_map
.ast_id(konst
);
413 let res
= Const { name, visibility, type_ref, ast_id }
;
414 id(self.data().consts
.alloc(res
))
417 fn lower_module(&mut self, module
: &ast
::Module
) -> Option
<FileItemTreeId
<Mod
>> {
418 let name
= module
.name()?
.as_name();
419 let visibility
= self.lower_visibility(module
);
420 let kind
= if module
.semicolon_token().is_some() {
426 .map(|list
| list
.items().flat_map(|item
| self.lower_mod_item(&item
)).collect())
428 cov_mark
::hit
!(name_res_works_for_broken_modules
);
429 Box
::new([]) as Box
<[_
]>
433 let ast_id
= self.source_ast_id_map
.ast_id(module
);
434 let res
= Mod { name, visibility, kind, ast_id }
;
435 Some(id(self.data().mods
.alloc(res
)))
438 fn lower_trait(&mut self, trait_def
: &ast
::Trait
) -> Option
<FileItemTreeId
<Trait
>> {
439 let name
= trait_def
.name()?
.as_name();
440 let visibility
= self.lower_visibility(trait_def
);
442 self.lower_generic_params(HasImplicitSelf
::Yes(trait_def
.type_bound_list()), trait_def
);
443 let is_auto
= trait_def
.auto_token().is_some();
444 let is_unsafe
= trait_def
.unsafe_token().is_some();
445 let ast_id
= self.source_ast_id_map
.ast_id(trait_def
);
447 let items
= trait_def
450 .flat_map(|list
| list
.assoc_items())
452 let attrs
= RawAttrs
::new(self.db
.upcast(), &item
, self.hygiene());
453 self.lower_assoc_item(&item
).map(|item
| {
454 self.add_attrs(ModItem
::from(item
).into(), attrs
);
460 let def
= Trait { name, visibility, generic_params, is_auto, is_unsafe, items, ast_id }
;
461 Some(id(self.data().traits
.alloc(def
)))
464 fn lower_trait_alias(
466 trait_alias_def
: &ast
::TraitAlias
,
467 ) -> Option
<FileItemTreeId
<TraitAlias
>> {
468 let name
= trait_alias_def
.name()?
.as_name();
469 let visibility
= self.lower_visibility(trait_alias_def
);
470 let generic_params
= self.lower_generic_params(
471 HasImplicitSelf
::Yes(trait_alias_def
.type_bound_list()),
474 let ast_id
= self.source_ast_id_map
.ast_id(trait_alias_def
);
476 let alias
= TraitAlias { name, visibility, generic_params, ast_id }
;
477 Some(id(self.data().trait_aliases
.alloc(alias
)))
480 fn lower_impl(&mut self, impl_def
: &ast
::Impl
) -> Option
<FileItemTreeId
<Impl
>> {
481 // Note that trait impls don't get implicit `Self` unlike traits, because here they are a
482 // type alias rather than a type parameter, so this is handled by the resolver.
483 let generic_params
= self.lower_generic_params(HasImplicitSelf
::No
, impl_def
);
484 // FIXME: If trait lowering fails, due to a non PathType for example, we treat this impl
485 // as if it was an non-trait impl. Ideally we want to create a unique missing ref that only
487 let target_trait
= impl_def
.trait_().and_then(|tr
| self.lower_trait_ref(&tr
));
488 let self_ty
= self.lower_type_ref(&impl_def
.self_ty()?
);
489 let is_negative
= impl_def
.excl_token().is_some();
491 // We cannot use `assoc_items()` here as that does not include macro calls.
495 .flat_map(|it
| it
.assoc_items())
497 let assoc
= self.lower_assoc_item(&item
)?
;
498 let attrs
= RawAttrs
::new(self.db
.upcast(), &item
, self.hygiene());
499 self.add_attrs(ModItem
::from(assoc
).into(), attrs
);
503 let ast_id
= self.source_ast_id_map
.ast_id(impl_def
);
504 let res
= Impl { generic_params, target_trait, self_ty, is_negative, items, ast_id }
;
505 Some(id(self.data().impls
.alloc(res
)))
508 fn lower_use(&mut self, use_item
: &ast
::Use
) -> Option
<FileItemTreeId
<Use
>> {
509 let visibility
= self.lower_visibility(use_item
);
510 let ast_id
= self.source_ast_id_map
.ast_id(use_item
);
511 let (use_tree
, _
) = lower_use_tree(self.db
, self.hygiene(), use_item
.use_tree()?
)?
;
513 let res
= Use { visibility, ast_id, use_tree }
;
514 Some(id(self.data().uses
.alloc(res
)))
517 fn lower_extern_crate(
519 extern_crate
: &ast
::ExternCrate
,
520 ) -> Option
<FileItemTreeId
<ExternCrate
>> {
521 let name
= extern_crate
.name_ref()?
.as_name();
522 let alias
= extern_crate
.rename().map(|a
| {
523 a
.name().map(|it
| it
.as_name()).map_or(ImportAlias
::Underscore
, ImportAlias
::Alias
)
525 let visibility
= self.lower_visibility(extern_crate
);
526 let ast_id
= self.source_ast_id_map
.ast_id(extern_crate
);
528 let res
= ExternCrate { name, alias, visibility, ast_id }
;
529 Some(id(self.data().extern_crates
.alloc(res
)))
532 fn lower_macro_call(&mut self, m
: &ast
::MacroCall
) -> Option
<FileItemTreeId
<MacroCall
>> {
533 let path
= Interned
::new(ModPath
::from_src(self.db
.upcast(), m
.path()?
, self.hygiene())?
);
534 let ast_id
= self.source_ast_id_map
.ast_id(m
);
535 let expand_to
= hir_expand
::ExpandTo
::from_call_site(m
);
536 let res
= MacroCall { path, ast_id, expand_to }
;
537 Some(id(self.data().macro_calls
.alloc(res
)))
540 fn lower_macro_rules(&mut self, m
: &ast
::MacroRules
) -> Option
<FileItemTreeId
<MacroRules
>> {
541 let name
= m
.name().map(|it
| it
.as_name())?
;
542 let ast_id
= self.source_ast_id_map
.ast_id(m
);
544 let res
= MacroRules { name, ast_id }
;
545 Some(id(self.data().macro_rules
.alloc(res
)))
548 fn lower_macro_def(&mut self, m
: &ast
::MacroDef
) -> Option
<FileItemTreeId
<MacroDef
>> {
549 let name
= m
.name().map(|it
| it
.as_name())?
;
551 let ast_id
= self.source_ast_id_map
.ast_id(m
);
552 let visibility
= self.lower_visibility(m
);
554 let res
= MacroDef { name, ast_id, visibility }
;
555 Some(id(self.data().macro_defs
.alloc(res
)))
558 fn lower_extern_block(&mut self, block
: &ast
::ExternBlock
) -> FileItemTreeId
<ExternBlock
> {
559 let ast_id
= self.source_ast_id_map
.ast_id(block
);
560 let abi
= block
.abi().map(lower_abi
);
561 let children
: Box
<[_
]> = block
.extern_item_list().map_or(Box
::new([]), |list
| {
564 // Note: All items in an `extern` block need to be lowered as if they're outside of one
565 // (in other words, the knowledge that they're in an extern block must not be used).
566 // This is because an extern block can contain macros whose ItemTree's top-level items
567 // should be considered to be in an extern block too.
568 let attrs
= RawAttrs
::new(self.db
.upcast(), &item
, self.hygiene());
569 let id
: ModItem
= match item
{
570 ast
::ExternItem
::Fn(ast
) => self.lower_function(&ast
)?
.into(),
571 ast
::ExternItem
::Static(ast
) => self.lower_static(&ast
)?
.into(),
572 ast
::ExternItem
::TypeAlias(ty
) => self.lower_type_alias(&ty
)?
.into(),
573 ast
::ExternItem
::MacroCall(call
) => self.lower_macro_call(&call
)?
.into(),
575 self.add_attrs(id
.into(), attrs
);
581 let res
= ExternBlock { abi, ast_id, children }
;
582 id(self.data().extern_blocks
.alloc(res
))
585 fn lower_generic_params(
587 has_implicit_self
: HasImplicitSelf
,
588 node
: &dyn ast
::HasGenericParams
,
589 ) -> Interned
<GenericParams
> {
590 let mut generics
= GenericParams
::default();
592 if let HasImplicitSelf
::Yes(bounds
) = has_implicit_self
{
593 // Traits and trait aliases get the Self type as an implicit first type parameter.
594 generics
.type_or_consts
.alloc(
596 name
: Some(name
![Self]),
598 provenance
: TypeParamProvenance
::TraitSelf
,
602 // add super traits as bounds on Self
603 // i.e., `trait Foo: Bar` is equivalent to `trait Foo where Self: Bar`
604 let self_param
= TypeRef
::Path(name
![Self].into());
605 generics
.fill_bounds(&self.body_ctx
, bounds
, Either
::Left(self_param
));
608 let add_param_attrs
= |item
, param
| {
609 let attrs
= RawAttrs
::new(self.db
.upcast(), ¶m
, self.body_ctx
.hygiene());
610 // This is identical to the body of `Ctx::add_attrs()` but we can't call that here
611 // because it requires `&mut self` and the call to `generics.fill()` below also
612 // references `self`.
613 match self.tree
.attrs
.entry(item
) {
614 Entry
::Occupied(mut entry
) => {
615 *entry
.get_mut() = entry
.get().merge(attrs
);
617 Entry
::Vacant(entry
) => {
622 generics
.fill(&self.body_ctx
, node
, add_param_attrs
);
624 generics
.shrink_to_fit();
625 Interned
::new(generics
)
628 fn lower_type_bounds(&mut self, node
: &dyn ast
::HasTypeBounds
) -> Vec
<Interned
<TypeBound
>> {
629 match node
.type_bound_list() {
630 Some(bound_list
) => bound_list
632 .map(|it
| Interned
::new(TypeBound
::from_ast(&self.body_ctx
, it
)))
638 fn lower_visibility(&mut self, item
: &dyn ast
::HasVisibility
) -> RawVisibilityId
{
639 let vis
= RawVisibility
::from_ast_with_hygiene(self.db
, item
.visibility(), self.hygiene());
640 self.data().vis
.alloc(vis
)
643 fn lower_trait_ref(&mut self, trait_ref
: &ast
::Type
) -> Option
<Interned
<TraitRef
>> {
644 let trait_ref
= TraitRef
::from_ast(&self.body_ctx
, trait_ref
.clone())?
;
645 Some(Interned
::new(trait_ref
))
648 fn lower_type_ref(&mut self, type_ref
: &ast
::Type
) -> Interned
<TypeRef
> {
649 let tyref
= TypeRef
::from_ast(&self.body_ctx
, type_ref
.clone());
653 fn lower_type_ref_opt(&mut self, type_ref
: Option
<ast
::Type
>) -> Interned
<TypeRef
> {
654 match type_ref
.map(|ty
| self.lower_type_ref(&ty
)) {
656 None
=> Interned
::new(TypeRef
::Error
),
660 fn next_field_idx(&self) -> Idx
<Field
> {
661 Idx
::from_raw(RawIdx
::from(
662 self.tree
.data
.as_ref().map_or(0, |data
| data
.fields
.len() as u32),
665 fn next_variant_idx(&self) -> Idx
<Variant
> {
666 Idx
::from_raw(RawIdx
::from(
667 self.tree
.data
.as_ref().map_or(0, |data
| data
.variants
.len() as u32),
670 fn next_param_idx(&self) -> Idx
<Param
> {
671 Idx
::from_raw(RawIdx
::from(
672 self.tree
.data
.as_ref().map_or(0, |data
| data
.params
.len() as u32),
677 fn desugar_future_path(orig
: TypeRef
) -> Path
{
678 let path
= path
![core
::future
::Future
];
679 let mut generic_args
: Vec
<_
> =
680 std
::iter
::repeat(None
).take(path
.segments().len() - 1).collect();
681 let binding
= AssociatedTypeBinding
{
684 type_ref
: Some(orig
),
685 bounds
: Box
::default(),
687 generic_args
.push(Some(Interned
::new(GenericArgs
{
688 bindings
: Box
::new([binding
]),
689 ..GenericArgs
::empty()
692 Path
::from_known_path(path
, generic_args
)
695 enum HasImplicitSelf
{
696 /// Inner list is a type bound list for the implicit `Self`.
697 Yes(Option
<ast
::TypeBoundList
>),
701 fn lower_abi(abi
: ast
::Abi
) -> Interned
<str> {
702 // FIXME: Abi::abi() -> Option<SyntaxToken>?
703 match abi
.syntax().last_token() {
704 Some(tok
) if tok
.kind() == SyntaxKind
::STRING
=> {
705 // FIXME: Better way to unescape?
706 Interned
::new_str(tok
.text().trim_matches('
"'))
709 // `extern` default to be `extern "C
"`.
710 Interned::new_str("C
")
715 struct UseTreeLowering<'a> {
716 db: &'a dyn DefDatabase,
717 hygiene: &'a Hygiene,
718 mapping: Arena<ast::UseTree>,
721 impl UseTreeLowering<'_> {
722 fn lower_use_tree(&mut self, tree: ast::UseTree) -> Option<UseTree> {
723 if let Some(use_tree_list) = tree.use_tree_list() {
724 let prefix = match tree.path() {
725 // E.g. use something::{{{inner}}};
727 // E.g. `use something::{inner}` (prefix is `None`, path is `something`)
728 // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`)
730 match ModPath::from_src(self.db.upcast(), path, self.hygiene) {
731 Some(it) => Some(it),
732 None => return None, // FIXME: report errors somewhere
738 use_tree_list.use_trees().filter_map(|tree| self.lower_use_tree(tree)).collect();
742 UseTreeKind::Prefixed { prefix: prefix.map(Interned::new), list },
747 let is_glob = tree.star_token().is_some();
748 let path = match tree.path() {
749 Some(path) => Some(ModPath::from_src(self.db.upcast(), path, self.hygiene)?),
752 let alias = tree.rename().map(|a| {
753 a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias)
755 if alias.is_some() && is_glob {
759 match (path, alias, is_glob) {
760 (path, None, true) => {
762 cov_mark::hit!(glob_enum_group);
764 Some(self.use_tree(UseTreeKind::Glob { path: path.map(Interned::new) }, tree))
766 // Globs can't be renamed
767 (_, Some(_), true) | (None, None, false) => None,
768 // `bla::{ as Name}` is invalid
769 (None, Some(_), false) => None,
770 (Some(path), alias, false) => Some(
771 self.use_tree(UseTreeKind::Single { path: Interned::new(path), alias }, tree),
777 fn use_tree(&mut self, kind: UseTreeKind, ast: ast::UseTree) -> UseTree {
778 let index = self.mapping.alloc(ast);
779 UseTree { index, kind }
783 pub(crate) fn lower_use_tree(
784 db: &dyn DefDatabase,
787 ) -> Option<(UseTree, Arena<ast::UseTree>)> {
788 let mut lowering = UseTreeLowering { db, hygiene, mapping: Arena::new() };
789 let tree = lowering.lower_use_tree(tree)?;
790 Some((tree, lowering.mapping))