]> git.lizzy.rs Git - rust.git/blobdiff - crates/hir_def/src/item_tree/lower.rs
Make some functions non-generic
[rust.git] / crates / hir_def / src / item_tree / lower.rs
index 91cf7537192f6614449c2bae43fa06801fa32a85..2926f32b63018fba53eadceb80725eb889e258d5 100644 (file)
@@ -3,15 +3,14 @@
 use std::{collections::hash_map::Entry, mem, sync::Arc};
 
 use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, name::known, HirFileId};
-use smallvec::SmallVec;
 use syntax::{
-    ast::{self, ModuleItemOwner},
+    ast::{self, HasModuleItem},
     SyntaxNode, WalkEvent,
 };
 
 use crate::{
     generics::{GenericParams, TypeParamData, TypeParamProvenance},
-    type_ref::{LifetimeRef, TraitRef},
+    type_ref::{LifetimeRef, TraitBoundModifier, TraitRef},
 };
 
 use super::*;
@@ -20,22 +19,10 @@ fn id<N: ItemTreeNode>(index: Idx<N>) -> FileItemTreeId<N> {
     FileItemTreeId { index, _p: PhantomData }
 }
 
-struct ModItems(SmallVec<[ModItem; 1]>);
-
-impl<T> From<T> for ModItems
-where
-    T: Into<ModItem>,
-{
-    fn from(t: T) -> Self {
-        ModItems(SmallVec::from_buf([t.into(); 1]))
-    }
-}
-
 pub(super) struct Ctx<'a> {
     db: &'a dyn DefDatabase,
     tree: ItemTree,
     hygiene: Hygiene,
-    file: HirFileId,
     source_ast_id_map: Arc<AstIdMap>,
     body_ctx: crate::body::LowerCtx<'a>,
     forced_visibility: Option<RawVisibilityId>,
@@ -47,19 +34,15 @@ pub(super) fn new(db: &'a dyn DefDatabase, hygiene: Hygiene, file: HirFileId) ->
             db,
             tree: ItemTree::default(),
             hygiene,
-            file,
             source_ast_id_map: db.ast_id_map(file),
             body_ctx: crate::body::LowerCtx::new(db, file),
             forced_visibility: None,
         }
     }
 
-    pub(super) fn lower_module_items(mut self, item_owner: &dyn ModuleItemOwner) -> ItemTree {
-        self.tree.top_level = item_owner
-            .items()
-            .flat_map(|item| self.lower_mod_item(&item, false))
-            .flat_map(|items| items.0)
-            .collect();
+    pub(super) fn lower_module_items(mut self, item_owner: &dyn HasModuleItem) -> ItemTree {
+        self.tree.top_level =
+            item_owner.items().flat_map(|item| self.lower_mod_item(&item, false)).collect();
         self.tree
     }
 
@@ -68,10 +51,18 @@ pub(super) fn lower_macro_stmts(mut self, stmts: ast::MacroStmts) -> ItemTree {
             .statements()
             .filter_map(|stmt| match stmt {
                 ast::Stmt::Item(item) => Some(item),
+                // Macro calls can be both items and expressions. The syntax library always treats
+                // them as expressions here, so we undo that.
+                ast::Stmt::ExprStmt(es) => match es.expr()? {
+                    ast::Expr::MacroCall(call) => {
+                        cov_mark::hit!(macro_call_in_macro_stmts_is_added_to_item_tree);
+                        Some(call.into())
+                    }
+                    _ => None,
+                },
                 _ => None,
             })
             .flat_map(|item| self.lower_mod_item(&item, false))
-            .flat_map(|items| items.0)
             .collect();
 
         // Non-items need to have their inner items collected.
@@ -98,7 +89,7 @@ fn data(&mut self) -> &mut ItemTreeData {
         self.tree.data_mut()
     }
 
-    fn lower_mod_item(&mut self, item: &ast::Item, inner: bool) -> Option<ModItems> {
+    fn lower_mod_item(&mut self, item: &ast::Item, inner: bool) -> Option<ModItem> {
         // Collect inner items for 1-to-1-lowered items.
         match item {
             ast::Item::Struct(_)
@@ -129,34 +120,28 @@ fn lower_mod_item(&mut self, item: &ast::Item, inner: bool) -> Option<ModItems>
         };
 
         let attrs = RawAttrs::new(self.db, item, &self.hygiene);
-        let items = match item {
-            ast::Item::Struct(ast) => self.lower_struct(ast).map(Into::into),
-            ast::Item::Union(ast) => self.lower_union(ast).map(Into::into),
-            ast::Item::Enum(ast) => self.lower_enum(ast).map(Into::into),
-            ast::Item::Fn(ast) => self.lower_function(ast).map(Into::into),
-            ast::Item::TypeAlias(ast) => self.lower_type_alias(ast).map(Into::into),
-            ast::Item::Static(ast) => self.lower_static(ast).map(Into::into),
-            ast::Item::Const(ast) => Some(self.lower_const(ast).into()),
-            ast::Item::Module(ast) => self.lower_module(ast).map(Into::into),
-            ast::Item::Trait(ast) => self.lower_trait(ast).map(Into::into),
-            ast::Item::Impl(ast) => self.lower_impl(ast).map(Into::into),
-            ast::Item::Use(ast) => Some(ModItems(
-                self.lower_use(ast).into_iter().map(Into::into).collect::<SmallVec<_>>(),
-            )),
-            ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast).map(Into::into),
-            ast::Item::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into),
-            ast::Item::MacroRules(ast) => self.lower_macro_rules(ast).map(Into::into),
-            ast::Item::MacroDef(ast) => self.lower_macro_def(ast).map(Into::into),
-            ast::Item::ExternBlock(ast) => Some(self.lower_extern_block(ast).into()),
+        let item: ModItem = match item {
+            ast::Item::Struct(ast) => self.lower_struct(ast)?.into(),
+            ast::Item::Union(ast) => self.lower_union(ast)?.into(),
+            ast::Item::Enum(ast) => self.lower_enum(ast)?.into(),
+            ast::Item::Fn(ast) => self.lower_function(ast)?.into(),
+            ast::Item::TypeAlias(ast) => self.lower_type_alias(ast)?.into(),
+            ast::Item::Static(ast) => self.lower_static(ast)?.into(),
+            ast::Item::Const(ast) => self.lower_const(ast).into(),
+            ast::Item::Module(ast) => self.lower_module(ast)?.into(),
+            ast::Item::Trait(ast) => self.lower_trait(ast)?.into(),
+            ast::Item::Impl(ast) => self.lower_impl(ast)?.into(),
+            ast::Item::Use(ast) => self.lower_use(ast)?.into(),
+            ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast)?.into(),
+            ast::Item::MacroCall(ast) => self.lower_macro_call(ast)?.into(),
+            ast::Item::MacroRules(ast) => self.lower_macro_rules(ast)?.into(),
+            ast::Item::MacroDef(ast) => self.lower_macro_def(ast)?.into(),
+            ast::Item::ExternBlock(ast) => self.lower_extern_block(ast).into(),
         };
 
-        if !attrs.is_empty() {
-            for item in items.iter().flat_map(|items| &items.0) {
-                self.add_attrs((*item).into(), attrs.clone());
-            }
-        }
+        self.add_attrs(item.into(), attrs);
 
-        items
+        Some(item)
     }
 
     fn add_attrs(&mut self, item: AttrOwner, attrs: RawAttrs) {
@@ -190,12 +175,10 @@ fn collect_inner_items(&mut self, container: &SyntaxNode) {
                             },
                             ast::Item(item) => {
                                 // FIXME: This triggers for macro calls in expression/pattern/type position
-                                let mod_items = self.lower_mod_item(&item, true);
+                                let mod_item = self.lower_mod_item(&item, true);
                                 let current_block = block_stack.last();
-                                if let (Some(mod_items), Some(block)) = (mod_items, current_block) {
-                                    if !mod_items.0.is_empty() {
-                                        self.data().inner_items.entry(*block).or_default().extend(mod_items.0.iter().copied());
-                                    }
+                                if let (Some(mod_item), Some(block)) = (mod_item, current_block) {
+                                        self.data().inner_items.entry(*block).or_default().push(mod_item);
                                 }
                             },
                             _ => {}
@@ -281,8 +264,7 @@ fn lower_tuple_field(&mut self, idx: usize, field: &ast::TupleField) -> Field {
         let name = Name::new_tuple_field(idx);
         let visibility = self.lower_visibility(field);
         let type_ref = self.lower_type_ref_opt(field.ty());
-        let res = Field { name, type_ref, visibility };
-        res
+        Field { name, type_ref, visibility }
     }
 
     fn lower_union(&mut self, union: &ast::Union) -> Option<FileItemTreeId<Union>> {
@@ -302,10 +284,11 @@ fn lower_enum(&mut self, enum_: &ast::Enum) -> Option<FileItemTreeId<Enum>> {
         let visibility = self.lower_visibility(enum_);
         let name = enum_.name()?.as_name();
         let generic_params = self.lower_generic_params(GenericsOwner::Enum, enum_);
-        let variants = match &enum_.variant_list() {
-            Some(variant_list) => self.lower_variants(variant_list),
-            None => IdRange::new(self.next_variant_idx()..self.next_variant_idx()),
-        };
+        let variants =
+            self.with_inherited_visibility(visibility, |this| match &enum_.variant_list() {
+                Some(variant_list) => this.lower_variants(variant_list),
+                None => IdRange::new(this.next_variant_idx()..this.next_variant_idx()),
+            });
         let ast_id = self.source_ast_id_map.ast_id(enum_);
         let res = Enum { name, visibility, generic_params, variants, ast_id };
         Some(id(self.data().enums.alloc(res)))
@@ -382,12 +365,13 @@ fn lower_function(&mut self, func: &ast::Fn) -> Option<FileItemTreeId<Function>>
             _ => TypeRef::unit(),
         };
 
-        let ret_type = if func.async_token().is_some() {
+        let (ret_type, async_ret_type) = if func.async_token().is_some() {
+            let async_ret_type = ret_type.clone();
             let future_impl = desugar_future_path(ret_type);
-            let ty_bound = TypeBound::Path(future_impl);
-            TypeRef::ImplTrait(vec![ty_bound])
+            let ty_bound = Interned::new(TypeBound::Path(future_impl, TraitBoundModifier::None));
+            (TypeRef::ImplTrait(vec![ty_bound]), Some(async_ret_type))
         } else {
-            ret_type
+            (ret_type, None)
         };
 
         let abi = func.abi().map(lower_abi);
@@ -417,14 +401,16 @@ fn lower_function(&mut self, func: &ast::Fn) -> Option<FileItemTreeId<Function>>
         let mut res = Function {
             name,
             visibility,
-            generic_params: Interned::new(GenericParams::default()),
+            explicit_generic_params: Interned::new(GenericParams::default()),
             abi,
             params,
             ret_type: Interned::new(ret_type),
+            async_ret_type: async_ret_type.map(Interned::new),
             ast_id,
             flags,
         };
-        res.generic_params = self.lower_generic_params(GenericsOwner::Function(&res), func);
+        res.explicit_generic_params =
+            self.lower_generic_params(GenericsOwner::Function(&res), func);
 
         Some(id(self.data().functions.alloc(res)))
     }
@@ -462,7 +448,12 @@ fn lower_static(&mut self, static_: &ast::Static) -> Option<FileItemTreeId<Stati
     }
 
     fn lower_const(&mut self, konst: &ast::Const) -> FileItemTreeId<Const> {
-        let name = konst.name().map(|it| it.as_name());
+        let mut name = konst.name().map(|it| it.as_name());
+        if name.as_ref().map_or(false, |n| n.to_string().starts_with("_DERIVE_")) {
+            // FIXME: this is a hack to treat consts generated by synstructure as unnamed
+            // remove this some time in the future
+            name = None;
+        }
         let type_ref = self.lower_type_ref_opt(konst.ty());
         let visibility = self.lower_visibility(konst);
         let ast_id = self.source_ast_id_map.ast_id(konst);
@@ -480,10 +471,7 @@ fn lower_module(&mut self, module: &ast::Module) -> Option<FileItemTreeId<Mod>>
                 items: module
                     .item_list()
                     .map(|list| {
-                        list.items()
-                            .flat_map(|item| self.lower_mod_item(&item, false))
-                            .flat_map(|items| items.0)
-                            .collect()
+                        list.items().flat_map(|item| self.lower_mod_item(&item, false)).collect()
                     })
                     .unwrap_or_else(|| {
                         cov_mark::hit!(name_res_works_for_broken_modules);
@@ -503,7 +491,6 @@ fn lower_trait(&mut self, trait_def: &ast::Trait) -> Option<FileItemTreeId<Trait
             self.lower_generic_params_and_inner_items(GenericsOwner::Trait(trait_def), trait_def);
         let is_auto = trait_def.auto_token().is_some();
         let is_unsafe = trait_def.unsafe_token().is_some();
-        let bounds = self.lower_type_bounds(trait_def);
         let items = trait_def.assoc_item_list().map(|list| {
             let db = self.db;
             self.with_inherited_visibility(visibility, |this| {
@@ -526,7 +513,6 @@ fn lower_trait(&mut self, trait_def: &ast::Trait) -> Option<FileItemTreeId<Trait
             generic_params,
             is_auto,
             is_unsafe,
-            bounds: bounds.into(),
             items: items.unwrap_or_default(),
             ast_id,
         };
@@ -561,30 +547,13 @@ fn lower_impl(&mut self, impl_def: &ast::Impl) -> Option<FileItemTreeId<Impl>> {
         Some(id(self.data().impls.alloc(res)))
     }
 
-    fn lower_use(&mut self, use_item: &ast::Use) -> Vec<FileItemTreeId<Import>> {
+    fn lower_use(&mut self, use_item: &ast::Use) -> Option<FileItemTreeId<Import>> {
         let visibility = self.lower_visibility(use_item);
         let ast_id = self.source_ast_id_map.ast_id(use_item);
+        let (use_tree, _) = lower_use_tree(self.db, &self.hygiene, use_item.use_tree()?)?;
 
-        // Every use item can expand to many `Import`s.
-        let mut imports = Vec::new();
-        let tree = self.tree.data_mut();
-        ModPath::expand_use_item(
-            self.db,
-            InFile::new(self.file, use_item.clone()),
-            &self.hygiene,
-            |path, _use_tree, is_glob, alias| {
-                imports.push(id(tree.imports.alloc(Import {
-                    path: Interned::new(path),
-                    alias,
-                    visibility,
-                    is_glob,
-                    ast_id,
-                    index: imports.len(),
-                })));
-            },
-        );
-
-        imports
+        let res = Import { visibility, ast_id, use_tree };
+        Some(id(self.data().imports.alloc(res)))
     }
 
     fn lower_extern_crate(
@@ -605,8 +574,8 @@ fn lower_extern_crate(
     fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<FileItemTreeId<MacroCall>> {
         let path = Interned::new(ModPath::from_src(self.db, m.path()?, &self.hygiene)?);
         let ast_id = self.source_ast_id_map.ast_id(m);
-        let fragment = hir_expand::to_fragment_kind(m);
-        let res = MacroCall { path, ast_id, fragment };
+        let expand_to = hir_expand::ExpandTo::from_call_site(m);
+        let res = MacroCall { path, ast_id, expand_to };
         Some(id(self.data().macro_calls.alloc(res)))
     }
 
@@ -676,7 +645,7 @@ fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> FileItemTreeId<Ext
     fn lower_generic_params_and_inner_items(
         &mut self,
         owner: GenericsOwner<'_>,
-        node: &impl ast::GenericParamsOwner,
+        node: &dyn ast::HasGenericParams,
     ) -> Interned<GenericParams> {
         // Generics are part of item headers and may contain inner items we need to collect.
         if let Some(params) = node.generic_param_list() {
@@ -692,45 +661,35 @@ fn lower_generic_params_and_inner_items(
     fn lower_generic_params(
         &mut self,
         owner: GenericsOwner<'_>,
-        node: &impl ast::GenericParamsOwner,
+        node: &dyn ast::HasGenericParams,
     ) -> Interned<GenericParams> {
-        let mut sm = &mut Default::default();
         let mut generics = GenericParams::default();
         match owner {
-            GenericsOwner::Function(func) => {
-                generics.fill(&self.body_ctx, sm, node);
-                // lower `impl Trait` in arguments
-                for id in func.params.clone() {
-                    if let Param::Normal(ty) = &self.data().params[id] {
-                        generics.fill_implicit_impl_trait_args(ty);
-                    }
-                }
-            }
-            GenericsOwner::Struct
+            GenericsOwner::Function(_)
+            | GenericsOwner::Struct
             | GenericsOwner::Enum
             | GenericsOwner::Union
             | GenericsOwner::TypeAlias => {
-                generics.fill(&self.body_ctx, sm, node);
+                generics.fill(&self.body_ctx, node);
             }
             GenericsOwner::Trait(trait_def) => {
                 // traits get the Self type as an implicit first type parameter
-                let self_param_id = generics.types.alloc(TypeParamData {
+                generics.types.alloc(TypeParamData {
                     name: Some(name![Self]),
                     default: None,
                     provenance: TypeParamProvenance::TraitSelf,
                 });
-                sm.type_params.insert(self_param_id, Either::Left(trait_def.clone()));
                 // add super traits as bounds on Self
                 // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar
                 let self_param = TypeRef::Path(name![Self].into());
                 generics.fill_bounds(&self.body_ctx, trait_def, Either::Left(self_param));
-                generics.fill(&self.body_ctx, &mut sm, node);
+                generics.fill(&self.body_ctx, node);
             }
             GenericsOwner::Impl => {
                 // Note that we don't add `Self` here: in `impl`s, `Self` is not a
                 // type-parameter, but rather is a type-alias for impl's target
                 // type, so this is handled by the resolver.
-                generics.fill(&self.body_ctx, &mut sm, node);
+                generics.fill(&self.body_ctx, node);
             }
         }
 
@@ -738,16 +697,17 @@ fn lower_generic_params(
         Interned::new(generics)
     }
 
-    fn lower_type_bounds(&mut self, node: &impl ast::TypeBoundsOwner) -> Vec<TypeBound> {
+    fn lower_type_bounds(&mut self, node: &dyn ast::HasTypeBounds) -> Vec<Interned<TypeBound>> {
         match node.type_bound_list() {
-            Some(bound_list) => {
-                bound_list.bounds().map(|it| TypeBound::from_ast(&self.body_ctx, it)).collect()
-            }
+            Some(bound_list) => bound_list
+                .bounds()
+                .map(|it| Interned::new(TypeBound::from_ast(&self.body_ctx, it)))
+                .collect(),
             None => Vec::new(),
         }
     }
 
-    fn lower_visibility(&mut self, item: &impl ast::VisibilityOwner) -> RawVisibilityId {
+    fn lower_visibility(&mut self, item: &dyn ast::HasVisibility) -> RawVisibilityId {
         let vis = match self.forced_visibility {
             Some(vis) => return vis,
             None => RawVisibility::from_ast_with_hygiene(self.db, item.visibility(), &self.hygiene),
@@ -810,7 +770,7 @@ fn desugar_future_path(orig: TypeRef) -> Path {
     let binding =
         AssociatedTypeBinding { name: name![Output], type_ref: Some(orig), bounds: Vec::new() };
     last.bindings.push(binding);
-    generic_args.push(Some(Arc::new(last)));
+    generic_args.push(Some(Interned::new(last)));
 
     Path::from_known_path(path, generic_args)
 }
@@ -830,44 +790,44 @@ enum GenericsOwner<'a> {
 
 /// Returns `true` if the given intrinsic is unsafe to call, or false otherwise.
 fn is_intrinsic_fn_unsafe(name: &Name) -> bool {
-    // Should be kept in sync with https://github.com/rust-lang/rust/blob/c6e4db620a7d2f569f11dcab627430921ea8aacf/compiler/rustc_typeck/src/check/intrinsic.rs#L68
+    // Should be kept in sync with https://github.com/rust-lang/rust/blob/0cd0709f19d316c4796fa71c5f52c8612a5f3771/compiler/rustc_typeck/src/check/intrinsic.rs#L72-L105
     ![
         known::abort,
-        known::min_align_of,
-        known::needs_drop,
-        known::caller_location,
-        known::size_of_val,
-        known::min_align_of_val,
         known::add_with_overflow,
-        known::sub_with_overflow,
-        known::mul_with_overflow,
-        known::wrapping_add,
-        known::wrapping_sub,
-        known::wrapping_mul,
-        known::saturating_add,
-        known::saturating_sub,
-        known::rotate_left,
-        known::rotate_right,
-        known::ctpop,
+        known::bitreverse,
+        known::bswap,
+        known::caller_location,
         known::ctlz,
+        known::ctpop,
         known::cttz,
-        known::bswap,
-        known::bitreverse,
         known::discriminant_value,
-        known::type_id,
+        known::forget,
         known::likely,
-        known::unlikely,
-        known::ptr_guaranteed_eq,
-        known::ptr_guaranteed_ne,
+        known::maxnumf32,
+        known::maxnumf64,
+        known::min_align_of,
         known::minnumf32,
         known::minnumf64,
-        known::maxnumf32,
+        known::mul_with_overflow,
+        known::needs_drop,
+        known::ptr_guaranteed_eq,
+        known::ptr_guaranteed_ne,
+        known::rotate_left,
+        known::rotate_right,
         known::rustc_peek,
-        known::maxnumf64,
+        known::saturating_add,
+        known::saturating_sub,
+        known::size_of,
+        known::sub_with_overflow,
+        known::type_id,
         known::type_name,
+        known::unlikely,
         known::variant_count,
+        known::wrapping_add,
+        known::wrapping_mul,
+        known::wrapping_sub,
     ]
-    .contains(&name)
+    .contains(name)
 }
 
 fn lower_abi(abi: ast::Abi) -> Interned<str> {
@@ -883,3 +843,81 @@ fn lower_abi(abi: ast::Abi) -> Interned<str> {
         }
     }
 }
+
+struct UseTreeLowering<'a> {
+    db: &'a dyn DefDatabase,
+    hygiene: &'a Hygiene,
+    mapping: Arena<ast::UseTree>,
+}
+
+impl UseTreeLowering<'_> {
+    fn lower_use_tree(&mut self, tree: ast::UseTree) -> Option<UseTree> {
+        if let Some(use_tree_list) = tree.use_tree_list() {
+            let prefix = match tree.path() {
+                // E.g. use something::{{{inner}}};
+                None => None,
+                // E.g. `use something::{inner}` (prefix is `None`, path is `something`)
+                // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`)
+                Some(path) => {
+                    match ModPath::from_src(self.db, path, self.hygiene) {
+                        Some(it) => Some(it),
+                        None => return None, // FIXME: report errors somewhere
+                    }
+                }
+            };
+
+            let list =
+                use_tree_list.use_trees().filter_map(|tree| self.lower_use_tree(tree)).collect();
+
+            Some(
+                self.use_tree(
+                    UseTreeKind::Prefixed { prefix: prefix.map(Interned::new), list },
+                    tree,
+                ),
+            )
+        } else {
+            let is_glob = tree.star_token().is_some();
+            let path = match tree.path() {
+                Some(path) => Some(ModPath::from_src(self.db, path, self.hygiene)?),
+                None => None,
+            };
+            let alias = tree.rename().map(|a| {
+                a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias)
+            });
+            if alias.is_some() && is_glob {
+                return None;
+            }
+
+            match (path, alias, is_glob) {
+                (path, None, true) => {
+                    if path.is_none() {
+                        cov_mark::hit!(glob_enum_group);
+                    }
+                    Some(self.use_tree(UseTreeKind::Glob { path: path.map(Interned::new) }, tree))
+                }
+                // Globs can't be renamed
+                (_, Some(_), true) | (None, None, false) => None,
+                // `bla::{ as Name}` is invalid
+                (None, Some(_), false) => None,
+                (Some(path), alias, false) => Some(
+                    self.use_tree(UseTreeKind::Single { path: Interned::new(path), alias }, tree),
+                ),
+            }
+        }
+    }
+
+    fn use_tree(&mut self, kind: UseTreeKind, ast: ast::UseTree) -> UseTree {
+        let index = self.mapping.alloc(ast);
+        UseTree { index, kind }
+    }
+}
+
+pub(super) fn lower_use_tree(
+    db: &dyn DefDatabase,
+    hygiene: &Hygiene,
+    tree: ast::UseTree,
+) -> Option<(UseTree, Arena<ast::UseTree>)> {
+    let mut lowering = UseTreeLowering { db, hygiene, mapping: Arena::new() };
+    let tree = lowering.lower_use_tree(tree)?;
+    Some((tree, lowering.mapping))
+}