aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def/src/body
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def/src/body')
-rw-r--r--crates/hir_def/src/body/lower.rs61
-rw-r--r--crates/hir_def/src/body/scope.rs22
-rw-r--r--crates/hir_def/src/body/tests.rs56
-rw-r--r--crates/hir_def/src/body/tests/block.rs290
4 files changed, 399 insertions, 30 deletions
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index 4ce5e5b72..40beb2f7a 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -1,7 +1,7 @@
1//! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr` 1//! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr`
2//! representation. 2//! representation.
3 3
4use std::{any::type_name, sync::Arc}; 4use std::{any::type_name, mem, sync::Arc};
5 5
6use either::Either; 6use either::Either;
7use hir_expand::{ 7use hir_expand::{
@@ -10,6 +10,7 @@ use hir_expand::{
10 ExpandError, HirFileId, MacroDefId, MacroDefKind, 10 ExpandError, HirFileId, MacroDefId, MacroDefKind,
11}; 11};
12use la_arena::Arena; 12use la_arena::Arena;
13use profile::Count;
13use rustc_hash::FxHashMap; 14use rustc_hash::FxHashMap;
14use syntax::{ 15use syntax::{
15 ast::{ 16 ast::{
@@ -23,7 +24,7 @@ use test_utils::mark;
23use crate::{ 24use crate::{
24 adt::StructKind, 25 adt::StructKind,
25 body::{Body, BodySourceMap, Expander, LabelSource, PatPtr, SyntheticSyntax}, 26 body::{Body, BodySourceMap, Expander, LabelSource, PatPtr, SyntheticSyntax},
26 builtin_type::{BuiltinFloat, BuiltinInt}, 27 builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
27 db::DefDatabase, 28 db::DefDatabase,
28 diagnostics::{InactiveCode, MacroError, UnresolvedProcMacro}, 29 diagnostics::{InactiveCode, MacroError, UnresolvedProcMacro},
29 expr::{ 30 expr::{
@@ -35,8 +36,8 @@ use crate::{
35 item_tree::{ItemTree, ItemTreeId, ItemTreeNode}, 36 item_tree::{ItemTree, ItemTreeId, ItemTreeNode},
36 path::{GenericArgs, Path}, 37 path::{GenericArgs, Path},
37 type_ref::{Mutability, Rawness, TypeRef}, 38 type_ref::{Mutability, Rawness, TypeRef},
38 AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId, 39 AdtId, BlockLoc, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern,
39 StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, 40 ModuleDefId, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc,
40}; 41};
41 42
42use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource}; 43use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource};
@@ -77,6 +78,7 @@ pub(super) fn lower(
77 params: Vec::new(), 78 params: Vec::new(),
78 body_expr: dummy_expr_id(), 79 body_expr: dummy_expr_id(),
79 item_scope: Default::default(), 80 item_scope: Default::default(),
81 _c: Count::new(),
80 }, 82 },
81 item_trees: { 83 item_trees: {
82 let mut map = FxHashMap::default(); 84 let mut map = FxHashMap::default();
@@ -150,8 +152,8 @@ impl ExprCollector<'_> {
150 fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId { 152 fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId {
151 self.make_expr(expr, Err(SyntheticSyntax)) 153 self.make_expr(expr, Err(SyntheticSyntax))
152 } 154 }
153 fn empty_block(&mut self) -> ExprId { 155 fn unit(&mut self) -> ExprId {
154 self.alloc_expr_desugared(Expr::Block { statements: Vec::new(), tail: None, label: None }) 156 self.alloc_expr_desugared(Expr::Tuple { exprs: Vec::new() })
155 } 157 }
156 fn missing_expr(&mut self) -> ExprId { 158 fn missing_expr(&mut self) -> ExprId {
157 self.alloc_expr_desugared(Expr::Missing) 159 self.alloc_expr_desugared(Expr::Missing)
@@ -220,7 +222,7 @@ impl ExprCollector<'_> {
220 MatchArm { pat, expr: then_branch, guard: None }, 222 MatchArm { pat, expr: then_branch, guard: None },
221 MatchArm { 223 MatchArm {
222 pat: placeholder_pat, 224 pat: placeholder_pat,
223 expr: else_branch.unwrap_or_else(|| self.empty_block()), 225 expr: else_branch.unwrap_or_else(|| self.unit()),
224 guard: None, 226 guard: None,
225 }, 227 },
226 ]; 228 ];
@@ -559,7 +561,7 @@ impl ExprCollector<'_> {
559 let outer_file = self.expander.current_file_id; 561 let outer_file = self.expander.current_file_id;
560 562
561 let macro_call = self.expander.to_source(AstPtr::new(&e)); 563 let macro_call = self.expander.to_source(AstPtr::new(&e));
562 let res = self.expander.enter_expand(self.db, Some(&self.body.item_scope), e); 564 let res = self.expander.enter_expand(self.db, e);
563 565
564 match &res.err { 566 match &res.err {
565 Some(ExpandError::UnresolvedProcMacro) => { 567 Some(ExpandError::UnresolvedProcMacro) => {
@@ -695,12 +697,30 @@ impl ExprCollector<'_> {
695 } 697 }
696 698
697 fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId { 699 fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId {
698 let syntax_node_ptr = AstPtr::new(&block.clone().into()); 700 let ast_id = self.expander.ast_id(&block);
701 let block_loc =
702 BlockLoc { ast_id, module: self.expander.def_map.module_id(self.expander.module) };
703 let block_id = self.db.intern_block(block_loc);
704 let opt_def_map = self.db.block_def_map(block_id);
705 let has_def_map = opt_def_map.is_some();
706 let def_map = opt_def_map.unwrap_or_else(|| self.expander.def_map.clone());
707 let module = if has_def_map { def_map.root() } else { self.expander.module };
708 let prev_def_map = mem::replace(&mut self.expander.def_map, def_map);
709 let prev_local_module = mem::replace(&mut self.expander.module, module);
710
699 self.collect_stmts_items(block.statements()); 711 self.collect_stmts_items(block.statements());
700 let statements = 712 let statements =
701 block.statements().filter_map(|s| self.collect_stmt(s)).flatten().collect(); 713 block.statements().filter_map(|s| self.collect_stmt(s)).flatten().collect();
702 let tail = block.tail_expr().map(|e| self.collect_expr(e)); 714 let tail = block.tail_expr().map(|e| self.collect_expr(e));
703 self.alloc_expr(Expr::Block { statements, tail, label: None }, syntax_node_ptr) 715 let syntax_node_ptr = AstPtr::new(&block.into());
716 let expr_id = self.alloc_expr(
717 Expr::Block { id: block_id, statements, tail, label: None },
718 syntax_node_ptr,
719 );
720
721 self.expander.def_map = prev_def_map;
722 self.expander.module = prev_local_module;
723 expr_id
704 } 724 }
705 725
706 fn collect_stmts_items(&mut self, stmts: ast::AstChildren<ast::Stmt>) { 726 fn collect_stmts_items(&mut self, stmts: ast::AstChildren<ast::Stmt>) {
@@ -792,7 +812,7 @@ impl ExprCollector<'_> {
792 } 812 }
793 Either::Right(e) => { 813 Either::Right(e) => {
794 let mac = MacroDefId { 814 let mac = MacroDefId {
795 krate: self.expander.module.krate, 815 krate: self.expander.def_map.krate(),
796 ast_id: Some(self.expander.ast_id(&e)), 816 ast_id: Some(self.expander.ast_id(&e)),
797 kind: MacroDefKind::Declarative, 817 kind: MacroDefKind::Declarative,
798 local_inner: false, 818 local_inner: false,
@@ -830,9 +850,9 @@ impl ExprCollector<'_> {
830 if annotation == BindingAnnotation::Unannotated && subpat.is_none() { 850 if annotation == BindingAnnotation::Unannotated && subpat.is_none() {
831 // This could also be a single-segment path pattern. To 851 // This could also be a single-segment path pattern. To
832 // decide that, we need to try resolving the name. 852 // decide that, we need to try resolving the name.
833 let (resolved, _) = self.expander.crate_def_map.resolve_path( 853 let (resolved, _) = self.expander.def_map.resolve_path(
834 self.db, 854 self.db,
835 self.expander.module.local_id, 855 self.expander.module,
836 &name.clone().into(), 856 &name.clone().into(),
837 BuiltinShadowMode::Other, 857 BuiltinShadowMode::Other,
838 ); 858 );
@@ -1045,11 +1065,16 @@ impl From<ast::LiteralKind> for Literal {
1045 fn from(ast_lit_kind: ast::LiteralKind) -> Self { 1065 fn from(ast_lit_kind: ast::LiteralKind) -> Self {
1046 match ast_lit_kind { 1066 match ast_lit_kind {
1047 LiteralKind::IntNumber(lit) => { 1067 LiteralKind::IntNumber(lit) => {
1048 if let Some(float_suffix) = lit.suffix().and_then(BuiltinFloat::from_suffix) { 1068 if let builtin @ Some(_) = lit.suffix().and_then(BuiltinFloat::from_suffix) {
1049 return Literal::Float(Default::default(), Some(float_suffix)); 1069 return Literal::Float(Default::default(), builtin);
1070 } else if let builtin @ Some(_) =
1071 lit.suffix().and_then(|it| BuiltinInt::from_suffix(&it))
1072 {
1073 Literal::Int(Default::default(), builtin)
1074 } else {
1075 let builtin = lit.suffix().and_then(|it| BuiltinUint::from_suffix(&it));
1076 Literal::Uint(Default::default(), builtin)
1050 } 1077 }
1051 let ty = lit.suffix().and_then(|it| BuiltinInt::from_suffix(&it));
1052 Literal::Int(Default::default(), ty)
1053 } 1078 }
1054 LiteralKind::FloatNumber(lit) => { 1079 LiteralKind::FloatNumber(lit) => {
1055 let ty = lit.suffix().and_then(|it| BuiltinFloat::from_suffix(&it)); 1080 let ty = lit.suffix().and_then(|it| BuiltinFloat::from_suffix(&it));
@@ -1057,7 +1082,7 @@ impl From<ast::LiteralKind> for Literal {
1057 } 1082 }
1058 LiteralKind::ByteString(_) => Literal::ByteString(Default::default()), 1083 LiteralKind::ByteString(_) => Literal::ByteString(Default::default()),
1059 LiteralKind::String(_) => Literal::String(Default::default()), 1084 LiteralKind::String(_) => Literal::String(Default::default()),
1060 LiteralKind::Byte => Literal::Int(Default::default(), Some(BuiltinInt::U8)), 1085 LiteralKind::Byte => Literal::Uint(Default::default(), Some(BuiltinUint::U8)),
1061 LiteralKind::Bool(val) => Literal::Bool(val), 1086 LiteralKind::Bool(val) => Literal::Bool(val),
1062 LiteralKind::Char => Literal::Char(Default::default()), 1087 LiteralKind::Char => Literal::Char(Default::default()),
1063 } 1088 }
diff --git a/crates/hir_def/src/body/scope.rs b/crates/hir_def/src/body/scope.rs
index 49f1427b4..210b4a617 100644
--- a/crates/hir_def/src/body/scope.rs
+++ b/crates/hir_def/src/body/scope.rs
@@ -9,7 +9,7 @@ use crate::{
9 body::Body, 9 body::Body,
10 db::DefDatabase, 10 db::DefDatabase,
11 expr::{Expr, ExprId, Pat, PatId, Statement}, 11 expr::{Expr, ExprId, Pat, PatId, Statement},
12 DefWithBodyId, 12 BlockId, DefWithBodyId,
13}; 13};
14 14
15pub type ScopeId = Idx<ScopeData>; 15pub type ScopeId = Idx<ScopeData>;
@@ -39,6 +39,7 @@ impl ScopeEntry {
39#[derive(Debug, PartialEq, Eq)] 39#[derive(Debug, PartialEq, Eq)]
40pub struct ScopeData { 40pub struct ScopeData {
41 parent: Option<ScopeId>, 41 parent: Option<ScopeId>,
42 block: Option<BlockId>,
42 entries: Vec<ScopeEntry>, 43 entries: Vec<ScopeEntry>,
43} 44}
44 45
@@ -61,6 +62,11 @@ impl ExprScopes {
61 &self.scopes[scope].entries 62 &self.scopes[scope].entries
62 } 63 }
63 64
65 /// If `scope` refers to a block expression scope, returns the corresponding `BlockId`.
66 pub fn block(&self, scope: ScopeId) -> Option<BlockId> {
67 self.scopes[scope].block
68 }
69
64 pub fn scope_chain(&self, scope: Option<ScopeId>) -> impl Iterator<Item = ScopeId> + '_ { 70 pub fn scope_chain(&self, scope: Option<ScopeId>) -> impl Iterator<Item = ScopeId> + '_ {
65 std::iter::successors(scope, move |&scope| self.scopes[scope].parent) 71 std::iter::successors(scope, move |&scope| self.scopes[scope].parent)
66 } 72 }
@@ -79,11 +85,15 @@ impl ExprScopes {
79 } 85 }
80 86
81 fn root_scope(&mut self) -> ScopeId { 87 fn root_scope(&mut self) -> ScopeId {
82 self.scopes.alloc(ScopeData { parent: None, entries: vec![] }) 88 self.scopes.alloc(ScopeData { parent: None, block: None, entries: vec![] })
83 } 89 }
84 90
85 fn new_scope(&mut self, parent: ScopeId) -> ScopeId { 91 fn new_scope(&mut self, parent: ScopeId) -> ScopeId {
86 self.scopes.alloc(ScopeData { parent: Some(parent), entries: vec![] }) 92 self.scopes.alloc(ScopeData { parent: Some(parent), block: None, entries: vec![] })
93 }
94
95 fn new_block_scope(&mut self, parent: ScopeId, block: BlockId) -> ScopeId {
96 self.scopes.alloc(ScopeData { parent: Some(parent), block: Some(block), entries: vec![] })
87 } 97 }
88 98
89 fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) { 99 fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) {
@@ -136,7 +146,11 @@ fn compute_block_scopes(
136fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope: ScopeId) { 146fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope: ScopeId) {
137 scopes.set_scope(expr, scope); 147 scopes.set_scope(expr, scope);
138 match &body[expr] { 148 match &body[expr] {
139 Expr::Block { statements, tail, .. } => { 149 Expr::Block { statements, tail, id, .. } => {
150 let scope = scopes.new_block_scope(scope, *id);
151 // Overwrite the old scope for the block expr, so that every block scope can be found
152 // via the block itself (important for blocks that only contain items, no expressions).
153 scopes.set_scope(expr, scope);
140 compute_block_scopes(&statements, *tail, body, scopes, scope); 154 compute_block_scopes(&statements, *tail, body, scopes, scope);
141 } 155 }
142 Expr::For { iterable, pat, body: body_expr, .. } => { 156 Expr::For { iterable, pat, body: body_expr, .. } => {
diff --git a/crates/hir_def/src/body/tests.rs b/crates/hir_def/src/body/tests.rs
index de77d5fc9..bb43569d7 100644
--- a/crates/hir_def/src/body/tests.rs
+++ b/crates/hir_def/src/body/tests.rs
@@ -1,4 +1,7 @@
1mod block;
2
1use base_db::{fixture::WithFixture, SourceDatabase}; 3use base_db::{fixture::WithFixture, SourceDatabase};
4use expect_test::Expect;
2use test_utils::mark; 5use test_utils::mark;
3 6
4use crate::{test_db::TestDB, ModuleDefId}; 7use crate::{test_db::TestDB, ModuleDefId};
@@ -6,18 +9,24 @@ use crate::{test_db::TestDB, ModuleDefId};
6use super::*; 9use super::*;
7 10
8fn lower(ra_fixture: &str) -> Arc<Body> { 11fn lower(ra_fixture: &str) -> Arc<Body> {
9 let (db, file_id) = crate::test_db::TestDB::with_single_file(ra_fixture); 12 let db = crate::test_db::TestDB::with_files(ra_fixture);
10 13
11 let krate = db.crate_graph().iter().next().unwrap(); 14 let krate = db.crate_graph().iter().next().unwrap();
12 let def_map = db.crate_def_map(krate); 15 let def_map = db.crate_def_map(krate);
13 let module = def_map.modules_for_file(file_id).next().unwrap(); 16 let mut fn_def = None;
14 let module = &def_map[module]; 17 'outer: for (_, module) in def_map.modules() {
15 let fn_def = match module.scope.declarations().next().unwrap() { 18 for decl in module.scope.declarations() {
16 ModuleDefId::FunctionId(it) => it, 19 match decl {
17 _ => panic!(), 20 ModuleDefId::FunctionId(it) => {
18 }; 21 fn_def = Some(it);
22 break 'outer;
23 }
24 _ => {}
25 }
26 }
27 }
19 28
20 db.body(fn_def.into()) 29 db.body(fn_def.unwrap().into())
21} 30}
22 31
23fn check_diagnostics(ra_fixture: &str) { 32fn check_diagnostics(ra_fixture: &str) {
@@ -25,6 +34,18 @@ fn check_diagnostics(ra_fixture: &str) {
25 db.check_diagnostics(); 34 db.check_diagnostics();
26} 35}
27 36
37fn block_def_map_at(ra_fixture: &str) -> String {
38 let (db, position) = crate::test_db::TestDB::with_position(ra_fixture);
39
40 let module = db.module_at_position(position);
41 module.def_map(&db).dump(&db)
42}
43
44fn check_at(ra_fixture: &str, expect: Expect) {
45 let actual = block_def_map_at(ra_fixture);
46 expect.assert_eq(&actual);
47}
48
28#[test] 49#[test]
29fn your_stack_belongs_to_me() { 50fn your_stack_belongs_to_me() {
30 mark::check!(your_stack_belongs_to_me); 51 mark::check!(your_stack_belongs_to_me);
@@ -42,6 +63,25 @@ fn main() { n_nuple!(1,2,3); }
42} 63}
43 64
44#[test] 65#[test]
66fn macro_resolve() {
67 // Regression test for a path resolution bug introduced with inner item handling.
68 lower(
69 r"
70macro_rules! vec {
71 () => { () };
72 ($elem:expr; $n:expr) => { () };
73 ($($x:expr),+ $(,)?) => { () };
74}
75mod m {
76 fn outer() {
77 let _ = vec![FileSet::default(); self.len()];
78 }
79}
80 ",
81 );
82}
83
84#[test]
45fn cfg_diagnostics() { 85fn cfg_diagnostics() {
46 check_diagnostics( 86 check_diagnostics(
47 r" 87 r"
diff --git a/crates/hir_def/src/body/tests/block.rs b/crates/hir_def/src/body/tests/block.rs
new file mode 100644
index 000000000..8bca72a17
--- /dev/null
+++ b/crates/hir_def/src/body/tests/block.rs
@@ -0,0 +1,290 @@
1use super::*;
2use expect_test::expect;
3
4#[test]
5fn inner_item_smoke() {
6 check_at(
7 r#"
8struct inner {}
9fn outer() {
10 $0
11 fn inner() {}
12}
13"#,
14 expect![[r#"
15 block scope
16 inner: v
17
18 crate
19 inner: t
20 outer: v
21 "#]],
22 );
23}
24
25#[test]
26fn use_from_crate() {
27 check_at(
28 r#"
29struct Struct {}
30fn outer() {
31 fn Struct() {}
32 use Struct as PlainStruct;
33 use crate::Struct as CrateStruct;
34 use self::Struct as SelfStruct;
35 use super::Struct as SuperStruct;
36 $0
37}
38"#,
39 expect![[r#"
40 block scope
41 CrateStruct: t
42 PlainStruct: t v
43 SelfStruct: t
44 Struct: v
45 SuperStruct: _
46
47 crate
48 Struct: t
49 outer: v
50 "#]],
51 );
52}
53
54#[test]
55fn merge_namespaces() {
56 check_at(
57 r#"
58struct name {}
59fn outer() {
60 fn name() {}
61
62 use name as imported; // should import both `name`s
63
64 $0
65}
66"#,
67 expect![[r#"
68 block scope
69 imported: t v
70 name: v
71
72 crate
73 name: t
74 outer: v
75 "#]],
76 );
77}
78
79#[test]
80fn nested_blocks() {
81 check_at(
82 r#"
83fn outer() {
84 struct inner1 {}
85 fn inner() {
86 use inner1;
87 use outer;
88 fn inner2() {}
89 $0
90 }
91}
92"#,
93 expect![[r#"
94 block scope
95 inner1: t
96 inner2: v
97 outer: v
98
99 block scope
100 inner: v
101 inner1: t
102
103 crate
104 outer: v
105 "#]],
106 );
107}
108
109#[test]
110fn super_imports() {
111 check_at(
112 r#"
113mod module {
114 fn f() {
115 use super::Struct;
116 $0
117 }
118}
119
120struct Struct {}
121"#,
122 expect![[r#"
123 block scope
124 Struct: t
125
126 crate
127 Struct: t
128 module: t
129
130 crate::module
131 f: v
132 "#]],
133 );
134}
135
136#[test]
137fn legacy_macro_items() {
138 // Checks that legacy-scoped `macro_rules!` from parent namespaces are resolved and expanded
139 // correctly.
140 check_at(
141 r#"
142macro_rules! hit {
143 () => {
144 struct Hit {}
145 }
146}
147
148fn f() {
149 hit!();
150 $0
151}
152"#,
153 expect![[r#"
154 block scope
155 Hit: t
156
157 crate
158 f: v
159 "#]],
160 );
161}
162
163#[test]
164fn macro_resolve() {
165 check_at(
166 r#"
167//- /lib.rs crate:lib deps:core
168use core::mark;
169
170fn f() {
171 fn nested() {
172 mark::hit!(Hit);
173 $0
174 }
175}
176//- /core.rs crate:core
177pub mod mark {
178 #[macro_export]
179 macro_rules! _hit {
180 ($name:ident) => {
181 struct $name {}
182 }
183 }
184
185 pub use crate::_hit as hit;
186}
187"#,
188 expect![[r#"
189 block scope
190 Hit: t
191
192 block scope
193 nested: v
194
195 crate
196 f: v
197 mark: t
198 "#]],
199 );
200}
201
202#[test]
203fn macro_resolve_legacy() {
204 check_at(
205 r#"
206//- /lib.rs
207mod module;
208
209//- /module.rs
210macro_rules! m {
211 () => {
212 struct Def {}
213 };
214}
215
216fn f() {
217 {
218 m!();
219 $0
220 }
221}
222 "#,
223 expect![[r#"
224 block scope
225 Def: t
226
227 crate
228 module: t
229
230 crate::module
231 f: v
232 "#]],
233 )
234}
235
236#[test]
237fn super_does_not_resolve_to_block_module() {
238 check_at(
239 r#"
240fn main() {
241 struct Struct {}
242 mod module {
243 use super::Struct;
244
245 $0
246 }
247}
248 "#,
249 expect![[r#"
250 block scope
251 Struct: t
252 module: t
253
254 block scope::module
255 Struct: _
256
257 crate
258 main: v
259 "#]],
260 );
261}
262
263#[test]
264fn underscore_import() {
265 // This used to panic, because the default (private) visibility inside block expressions would
266 // point into the containing `DefMap`, which visibilities should never be able to do.
267 mark::check!(adjust_vis_in_block_def_map);
268 check_at(
269 r#"
270mod m {
271 fn main() {
272 use Tr as _;
273 trait Tr {}
274 $0
275 }
276}
277 "#,
278 expect![[r#"
279 block scope
280 _: t
281 Tr: t
282
283 crate
284 m: t
285
286 crate::m
287 main: v
288 "#]],
289 );
290}