diff options
34 files changed, 474 insertions, 180 deletions
diff --git a/crates/ra_assists/src/ast_transform.rs b/crates/ra_assists/src/ast_transform.rs index 52b4c82db..9ac65ab39 100644 --- a/crates/ra_assists/src/ast_transform.rs +++ b/crates/ra_assists/src/ast_transform.rs | |||
@@ -85,6 +85,7 @@ impl<'a> SubstituteTypeParams<'a> { | |||
85 | ast::TypeRef::PathType(path_type) => path_type.path()?, | 85 | ast::TypeRef::PathType(path_type) => path_type.path()?, |
86 | _ => return None, | 86 | _ => return None, |
87 | }; | 87 | }; |
88 | // FIXME: use `hir::Path::from_src` instead. | ||
88 | let path = hir::Path::from_ast(path)?; | 89 | let path = hir::Path::from_ast(path)?; |
89 | let resolution = self.source_scope.resolve_hir_path(&path)?; | 90 | let resolution = self.source_scope.resolve_hir_path(&path)?; |
90 | match resolution { | 91 | match resolution { |
@@ -128,6 +129,7 @@ impl<'a> QualifyPaths<'a> { | |||
128 | // don't try to qualify `Fn(Foo) -> Bar` paths, they are in prelude anyway | 129 | // don't try to qualify `Fn(Foo) -> Bar` paths, they are in prelude anyway |
129 | return None; | 130 | return None; |
130 | } | 131 | } |
132 | // FIXME: use `hir::Path::from_src` instead. | ||
131 | let hir_path = hir::Path::from_ast(p.clone()); | 133 | let hir_path = hir::Path::from_ast(p.clone()); |
132 | let resolution = self.source_scope.resolve_hir_path(&hir_path?)?; | 134 | let resolution = self.source_scope.resolve_hir_path(&hir_path?)?; |
133 | match resolution { | 135 | match resolution { |
diff --git a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs index 2f02df303..918e8dd8d 100644 --- a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs +++ b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs | |||
@@ -27,7 +27,7 @@ pub(crate) fn replace_qualified_name_with_use(ctx: AssistCtx) -> Option<Assist> | |||
27 | return None; | 27 | return None; |
28 | } | 28 | } |
29 | 29 | ||
30 | let hir_path = hir::Path::from_ast(path.clone())?; | 30 | let hir_path = ctx.sema.lower_path(&path)?; |
31 | let segments = collect_hir_path_segments(&hir_path)?; | 31 | let segments = collect_hir_path_segments(&hir_path)?; |
32 | if segments.len() < 2 { | 32 | if segments.len() < 2 { |
33 | return None; | 33 | return None; |
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 312ef3814..c5df4ac24 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -70,6 +70,7 @@ pub use hir_def::{ | |||
70 | type_ref::Mutability, | 70 | type_ref::Mutability, |
71 | }; | 71 | }; |
72 | pub use hir_expand::{ | 72 | pub use hir_expand::{ |
73 | name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc, MacroDefId, MacroFile, Origin, | 73 | hygiene::Hygiene, name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc, MacroDefId, |
74 | MacroFile, Origin, | ||
74 | }; | 75 | }; |
75 | pub use hir_ty::{display::HirDisplay, CallableDef}; | 76 | pub use hir_ty::{display::HirDisplay, CallableDef}; |
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index a0a0f234b..515e5eb17 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs | |||
@@ -8,7 +8,7 @@ use hir_def::{ | |||
8 | resolver::{self, HasResolver, Resolver}, | 8 | resolver::{self, HasResolver, Resolver}, |
9 | AsMacroCall, TraitId, | 9 | AsMacroCall, TraitId, |
10 | }; | 10 | }; |
11 | use hir_expand::ExpansionInfo; | 11 | use hir_expand::{hygiene::Hygiene, ExpansionInfo}; |
12 | use hir_ty::associated_type_shorthand_candidates; | 12 | use hir_ty::associated_type_shorthand_candidates; |
13 | use itertools::Itertools; | 13 | use itertools::Itertools; |
14 | use ra_db::{FileId, FileRange}; | 14 | use ra_db::{FileId, FileRange}; |
@@ -246,6 +246,11 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
246 | self.analyze(path.syntax()).resolve_path(self.db, path) | 246 | self.analyze(path.syntax()).resolve_path(self.db, path) |
247 | } | 247 | } |
248 | 248 | ||
249 | pub fn lower_path(&self, path: &ast::Path) -> Option<Path> { | ||
250 | let src = self.find_file(path.syntax().clone()); | ||
251 | Path::from_src(path.clone(), &Hygiene::new(self.db.upcast(), src.file_id.into())) | ||
252 | } | ||
253 | |||
249 | pub fn resolve_bind_pat_to_const(&self, pat: &ast::BindPat) -> Option<ModuleDef> { | 254 | pub fn resolve_bind_pat_to_const(&self, pat: &ast::BindPat) -> Option<ModuleDef> { |
250 | self.analyze(pat.syntax()).resolve_bind_pat_to_const(self.db, pat) | 255 | self.analyze(pat.syntax()).resolve_bind_pat_to_const(self.db, pat) |
251 | } | 256 | } |
diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs index 74d64c97d..c63d1b847 100644 --- a/crates/ra_hir/src/source_analyzer.rs +++ b/crates/ra_hir/src/source_analyzer.rs | |||
@@ -224,7 +224,8 @@ impl SourceAnalyzer { | |||
224 | } | 224 | } |
225 | } | 225 | } |
226 | // This must be a normal source file rather than macro file. | 226 | // This must be a normal source file rather than macro file. |
227 | let hir_path = crate::Path::from_ast(path.clone())?; | 227 | let hir_path = |
228 | crate::Path::from_src(path.clone(), &Hygiene::new(db.upcast(), self.file_id))?; | ||
228 | resolve_hir_path(db, &self.resolver, &hir_path) | 229 | resolve_hir_path(db, &self.resolver, &hir_path) |
229 | } | 230 | } |
230 | 231 | ||
diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs index 753becc3d..8eef51828 100644 --- a/crates/ra_hir_def/src/adt.rs +++ b/crates/ra_hir_def/src/adt.rs | |||
@@ -12,9 +12,15 @@ use ra_prof::profile; | |||
12 | use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner, VisibilityOwner}; | 12 | use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner, VisibilityOwner}; |
13 | 13 | ||
14 | use crate::{ | 14 | use crate::{ |
15 | body::CfgExpander, db::DefDatabase, src::HasChildSource, src::HasSource, trace::Trace, | 15 | body::{CfgExpander, LowerCtx}, |
16 | type_ref::TypeRef, visibility::RawVisibility, EnumId, HasModule, LocalEnumVariantId, | 16 | db::DefDatabase, |
17 | LocalFieldId, Lookup, ModuleId, StructId, UnionId, VariantId, | 17 | src::HasChildSource, |
18 | src::HasSource, | ||
19 | trace::Trace, | ||
20 | type_ref::TypeRef, | ||
21 | visibility::RawVisibility, | ||
22 | EnumId, HasModule, LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StructId, UnionId, | ||
23 | VariantId, | ||
18 | }; | 24 | }; |
19 | 25 | ||
20 | /// Note that we use `StructData` for unions as well! | 26 | /// Note that we use `StructData` for unions as well! |
@@ -198,6 +204,8 @@ fn lower_struct( | |||
198 | trace: &mut Trace<FieldData, Either<ast::TupleFieldDef, ast::RecordFieldDef>>, | 204 | trace: &mut Trace<FieldData, Either<ast::TupleFieldDef, ast::RecordFieldDef>>, |
199 | ast: &InFile<ast::StructKind>, | 205 | ast: &InFile<ast::StructKind>, |
200 | ) -> StructKind { | 206 | ) -> StructKind { |
207 | let ctx = LowerCtx::new(db, ast.file_id); | ||
208 | |||
201 | match &ast.value { | 209 | match &ast.value { |
202 | ast::StructKind::Tuple(fl) => { | 210 | ast::StructKind::Tuple(fl) => { |
203 | for (i, fd) in fl.fields().enumerate() { | 211 | for (i, fd) in fl.fields().enumerate() { |
@@ -210,7 +218,7 @@ fn lower_struct( | |||
210 | || Either::Left(fd.clone()), | 218 | || Either::Left(fd.clone()), |
211 | || FieldData { | 219 | || FieldData { |
212 | name: Name::new_tuple_field(i), | 220 | name: Name::new_tuple_field(i), |
213 | type_ref: TypeRef::from_ast_opt(fd.type_ref()), | 221 | type_ref: TypeRef::from_ast_opt(&ctx, fd.type_ref()), |
214 | visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())), | 222 | visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())), |
215 | }, | 223 | }, |
216 | ); | 224 | ); |
@@ -228,7 +236,7 @@ fn lower_struct( | |||
228 | || Either::Right(fd.clone()), | 236 | || Either::Right(fd.clone()), |
229 | || FieldData { | 237 | || FieldData { |
230 | name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing), | 238 | name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing), |
231 | type_ref: TypeRef::from_ast_opt(fd.ascribed_type()), | 239 | type_ref: TypeRef::from_ast_opt(&ctx, fd.ascribed_type()), |
232 | visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())), | 240 | visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())), |
233 | }, | 241 | }, |
234 | ); | 242 | ); |
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index 890cefcaf..4edaad960 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs | |||
@@ -15,6 +15,8 @@ use ra_prof::profile; | |||
15 | use ra_syntax::{ast, AstNode, AstPtr}; | 15 | use ra_syntax::{ast, AstNode, AstPtr}; |
16 | use rustc_hash::FxHashMap; | 16 | use rustc_hash::FxHashMap; |
17 | 17 | ||
18 | pub(crate) use lower::LowerCtx; | ||
19 | |||
18 | use crate::{ | 20 | use crate::{ |
19 | attr::Attrs, | 21 | attr::Attrs, |
20 | db::DefDatabase, | 22 | db::DefDatabase, |
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index f467ed3fe..e9dd65b0a 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs | |||
@@ -3,8 +3,9 @@ | |||
3 | 3 | ||
4 | use either::Either; | 4 | use either::Either; |
5 | use hir_expand::{ | 5 | use hir_expand::{ |
6 | hygiene::Hygiene, | ||
6 | name::{name, AsName, Name}, | 7 | name::{name, AsName, Name}, |
7 | MacroDefId, MacroDefKind, | 8 | HirFileId, MacroDefId, MacroDefKind, |
8 | }; | 9 | }; |
9 | use ra_arena::Arena; | 10 | use ra_arena::Arena; |
10 | use ra_syntax::{ | 11 | use ra_syntax::{ |
@@ -26,7 +27,7 @@ use crate::{ | |||
26 | LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, | 27 | LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, |
27 | }, | 28 | }, |
28 | item_scope::BuiltinShadowMode, | 29 | item_scope::BuiltinShadowMode, |
29 | path::GenericArgs, | 30 | path::{GenericArgs, Path}, |
30 | type_ref::{Mutability, TypeRef}, | 31 | type_ref::{Mutability, TypeRef}, |
31 | AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId, | 32 | AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId, |
32 | StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, | 33 | StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, |
@@ -35,6 +36,23 @@ use crate::{ | |||
35 | use super::{ExprSource, PatSource}; | 36 | use super::{ExprSource, PatSource}; |
36 | use ast::AstChildren; | 37 | use ast::AstChildren; |
37 | 38 | ||
39 | pub(crate) struct LowerCtx { | ||
40 | hygiene: Hygiene, | ||
41 | } | ||
42 | |||
43 | impl LowerCtx { | ||
44 | pub fn new(db: &dyn DefDatabase, file_id: HirFileId) -> Self { | ||
45 | LowerCtx { hygiene: Hygiene::new(db.upcast(), file_id) } | ||
46 | } | ||
47 | pub fn with_hygiene(hygiene: &Hygiene) -> Self { | ||
48 | LowerCtx { hygiene: hygiene.clone() } | ||
49 | } | ||
50 | |||
51 | pub fn lower_path(&self, ast: ast::Path) -> Option<Path> { | ||
52 | Path::from_src(ast, &self.hygiene) | ||
53 | } | ||
54 | } | ||
55 | |||
38 | pub(super) fn lower( | 56 | pub(super) fn lower( |
39 | db: &dyn DefDatabase, | 57 | db: &dyn DefDatabase, |
40 | def: DefWithBodyId, | 58 | def: DefWithBodyId, |
@@ -42,10 +60,13 @@ pub(super) fn lower( | |||
42 | params: Option<ast::ParamList>, | 60 | params: Option<ast::ParamList>, |
43 | body: Option<ast::Expr>, | 61 | body: Option<ast::Expr>, |
44 | ) -> (Body, BodySourceMap) { | 62 | ) -> (Body, BodySourceMap) { |
63 | let ctx = LowerCtx::new(db, expander.current_file_id.clone()); | ||
64 | |||
45 | ExprCollector { | 65 | ExprCollector { |
46 | db, | 66 | db, |
47 | def, | 67 | def, |
48 | expander, | 68 | expander, |
69 | ctx, | ||
49 | source_map: BodySourceMap::default(), | 70 | source_map: BodySourceMap::default(), |
50 | body: Body { | 71 | body: Body { |
51 | exprs: Arena::default(), | 72 | exprs: Arena::default(), |
@@ -62,7 +83,7 @@ struct ExprCollector<'a> { | |||
62 | db: &'a dyn DefDatabase, | 83 | db: &'a dyn DefDatabase, |
63 | def: DefWithBodyId, | 84 | def: DefWithBodyId, |
64 | expander: Expander, | 85 | expander: Expander, |
65 | 86 | ctx: LowerCtx, | |
66 | body: Body, | 87 | body: Body, |
67 | source_map: BodySourceMap, | 88 | source_map: BodySourceMap, |
68 | } | 89 | } |
@@ -237,7 +258,8 @@ impl ExprCollector<'_> { | |||
237 | Vec::new() | 258 | Vec::new() |
238 | }; | 259 | }; |
239 | let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); | 260 | let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); |
240 | let generic_args = e.type_arg_list().and_then(GenericArgs::from_ast); | 261 | let generic_args = |
262 | e.type_arg_list().and_then(|it| GenericArgs::from_ast(&self.ctx, it)); | ||
241 | self.alloc_expr( | 263 | self.alloc_expr( |
242 | Expr::MethodCall { receiver, method_name, args, generic_args }, | 264 | Expr::MethodCall { receiver, method_name, args, generic_args }, |
243 | syntax_ptr, | 265 | syntax_ptr, |
@@ -343,7 +365,7 @@ impl ExprCollector<'_> { | |||
343 | } | 365 | } |
344 | ast::Expr::CastExpr(e) => { | 366 | ast::Expr::CastExpr(e) => { |
345 | let expr = self.collect_expr_opt(e.expr()); | 367 | let expr = self.collect_expr_opt(e.expr()); |
346 | let type_ref = TypeRef::from_ast_opt(e.type_ref()); | 368 | let type_ref = TypeRef::from_ast_opt(&self.ctx, e.type_ref()); |
347 | self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr) | 369 | self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr) |
348 | } | 370 | } |
349 | ast::Expr::RefExpr(e) => { | 371 | ast::Expr::RefExpr(e) => { |
@@ -365,12 +387,16 @@ impl ExprCollector<'_> { | |||
365 | if let Some(pl) = e.param_list() { | 387 | if let Some(pl) = e.param_list() { |
366 | for param in pl.params() { | 388 | for param in pl.params() { |
367 | let pat = self.collect_pat_opt(param.pat()); | 389 | let pat = self.collect_pat_opt(param.pat()); |
368 | let type_ref = param.ascribed_type().map(TypeRef::from_ast); | 390 | let type_ref = |
391 | param.ascribed_type().map(|it| TypeRef::from_ast(&self.ctx, it)); | ||
369 | args.push(pat); | 392 | args.push(pat); |
370 | arg_types.push(type_ref); | 393 | arg_types.push(type_ref); |
371 | } | 394 | } |
372 | } | 395 | } |
373 | let ret_type = e.ret_type().and_then(|r| r.type_ref()).map(TypeRef::from_ast); | 396 | let ret_type = e |
397 | .ret_type() | ||
398 | .and_then(|r| r.type_ref()) | ||
399 | .map(|it| TypeRef::from_ast(&self.ctx, it)); | ||
374 | let body = self.collect_expr_opt(e.body()); | 400 | let body = self.collect_expr_opt(e.body()); |
375 | self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr) | 401 | self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr) |
376 | } | 402 | } |
@@ -476,7 +502,7 @@ impl ExprCollector<'_> { | |||
476 | .map(|s| match s { | 502 | .map(|s| match s { |
477 | ast::Stmt::LetStmt(stmt) => { | 503 | ast::Stmt::LetStmt(stmt) => { |
478 | let pat = self.collect_pat_opt(stmt.pat()); | 504 | let pat = self.collect_pat_opt(stmt.pat()); |
479 | let type_ref = stmt.ascribed_type().map(TypeRef::from_ast); | 505 | let type_ref = stmt.ascribed_type().map(|it| TypeRef::from_ast(&self.ctx, it)); |
480 | let initializer = stmt.initializer().map(|e| self.collect_expr(e)); | 506 | let initializer = stmt.initializer().map(|e| self.collect_expr(e)); |
481 | Statement::Let { pat, type_ref, initializer } | 507 | Statement::Let { pat, type_ref, initializer } |
482 | } | 508 | } |
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index ccb682f9a..7a2067e49 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs | |||
@@ -15,6 +15,7 @@ use ra_syntax::ast::{ | |||
15 | 15 | ||
16 | use crate::{ | 16 | use crate::{ |
17 | attr::Attrs, | 17 | attr::Attrs, |
18 | body::LowerCtx, | ||
18 | db::DefDatabase, | 19 | db::DefDatabase, |
19 | path::{path, AssociatedTypeBinding, GenericArgs, Path}, | 20 | path::{path, AssociatedTypeBinding, GenericArgs, Path}, |
20 | src::HasSource, | 21 | src::HasSource, |
@@ -40,13 +41,14 @@ impl FunctionData { | |||
40 | pub(crate) fn fn_data_query(db: &impl DefDatabase, func: FunctionId) -> Arc<FunctionData> { | 41 | pub(crate) fn fn_data_query(db: &impl DefDatabase, func: FunctionId) -> Arc<FunctionData> { |
41 | let loc = func.lookup(db); | 42 | let loc = func.lookup(db); |
42 | let src = loc.source(db); | 43 | let src = loc.source(db); |
44 | let ctx = LowerCtx::new(db, src.file_id); | ||
43 | let name = src.value.name().map(|n| n.as_name()).unwrap_or_else(Name::missing); | 45 | let name = src.value.name().map(|n| n.as_name()).unwrap_or_else(Name::missing); |
44 | let mut params = Vec::new(); | 46 | let mut params = Vec::new(); |
45 | let mut has_self_param = false; | 47 | let mut has_self_param = false; |
46 | if let Some(param_list) = src.value.param_list() { | 48 | if let Some(param_list) = src.value.param_list() { |
47 | if let Some(self_param) = param_list.self_param() { | 49 | if let Some(self_param) = param_list.self_param() { |
48 | let self_type = if let Some(type_ref) = self_param.ascribed_type() { | 50 | let self_type = if let Some(type_ref) = self_param.ascribed_type() { |
49 | TypeRef::from_ast(type_ref) | 51 | TypeRef::from_ast(&ctx, type_ref) |
50 | } else { | 52 | } else { |
51 | let self_type = TypeRef::Path(name![Self].into()); | 53 | let self_type = TypeRef::Path(name![Self].into()); |
52 | match self_param.kind() { | 54 | match self_param.kind() { |
@@ -63,14 +65,14 @@ impl FunctionData { | |||
63 | has_self_param = true; | 65 | has_self_param = true; |
64 | } | 66 | } |
65 | for param in param_list.params() { | 67 | for param in param_list.params() { |
66 | let type_ref = TypeRef::from_ast_opt(param.ascribed_type()); | 68 | let type_ref = TypeRef::from_ast_opt(&ctx, param.ascribed_type()); |
67 | params.push(type_ref); | 69 | params.push(type_ref); |
68 | } | 70 | } |
69 | } | 71 | } |
70 | let attrs = Attrs::new(&src.value, &Hygiene::new(db.upcast(), src.file_id)); | 72 | let attrs = Attrs::new(&src.value, &Hygiene::new(db.upcast(), src.file_id)); |
71 | 73 | ||
72 | let ret_type = if let Some(type_ref) = src.value.ret_type().and_then(|rt| rt.type_ref()) { | 74 | let ret_type = if let Some(type_ref) = src.value.ret_type().and_then(|rt| rt.type_ref()) { |
73 | TypeRef::from_ast(type_ref) | 75 | TypeRef::from_ast(&ctx, type_ref) |
74 | } else { | 76 | } else { |
75 | TypeRef::unit() | 77 | TypeRef::unit() |
76 | }; | 78 | }; |
@@ -122,7 +124,8 @@ impl TypeAliasData { | |||
122 | let loc = typ.lookup(db); | 124 | let loc = typ.lookup(db); |
123 | let node = loc.source(db); | 125 | let node = loc.source(db); |
124 | let name = node.value.name().map_or_else(Name::missing, |n| n.as_name()); | 126 | let name = node.value.name().map_or_else(Name::missing, |n| n.as_name()); |
125 | let type_ref = node.value.type_ref().map(TypeRef::from_ast); | 127 | let lower_ctx = LowerCtx::new(db, node.file_id); |
128 | let type_ref = node.value.type_ref().map(|it| TypeRef::from_ast(&lower_ctx, it)); | ||
126 | let vis_default = RawVisibility::default_for_container(loc.container); | 129 | let vis_default = RawVisibility::default_for_container(loc.container); |
127 | let visibility = RawVisibility::from_ast_with_default( | 130 | let visibility = RawVisibility::from_ast_with_default( |
128 | db, | 131 | db, |
@@ -130,7 +133,7 @@ impl TypeAliasData { | |||
130 | node.as_ref().map(|n| n.visibility()), | 133 | node.as_ref().map(|n| n.visibility()), |
131 | ); | 134 | ); |
132 | let bounds = if let Some(bound_list) = node.value.type_bound_list() { | 135 | let bounds = if let Some(bound_list) = node.value.type_bound_list() { |
133 | bound_list.bounds().map(TypeBound::from_ast).collect() | 136 | bound_list.bounds().map(|it| TypeBound::from_ast(&lower_ctx, it)).collect() |
134 | } else { | 137 | } else { |
135 | Vec::new() | 138 | Vec::new() |
136 | }; | 139 | }; |
@@ -223,9 +226,10 @@ impl ImplData { | |||
223 | let _p = profile("impl_data_query"); | 226 | let _p = profile("impl_data_query"); |
224 | let impl_loc = id.lookup(db); | 227 | let impl_loc = id.lookup(db); |
225 | let src = impl_loc.source(db); | 228 | let src = impl_loc.source(db); |
229 | let lower_ctx = LowerCtx::new(db, src.file_id); | ||
226 | 230 | ||
227 | let target_trait = src.value.target_trait().map(TypeRef::from_ast); | 231 | let target_trait = src.value.target_trait().map(|it| TypeRef::from_ast(&lower_ctx, it)); |
228 | let target_type = TypeRef::from_ast_opt(src.value.target_type()); | 232 | let target_type = TypeRef::from_ast_opt(&lower_ctx, src.value.target_type()); |
229 | let is_negative = src.value.excl_token().is_some(); | 233 | let is_negative = src.value.excl_token().is_some(); |
230 | let module_id = impl_loc.container.module(db); | 234 | let module_id = impl_loc.container.module(db); |
231 | 235 | ||
@@ -279,8 +283,9 @@ impl ConstData { | |||
279 | vis_default: RawVisibility, | 283 | vis_default: RawVisibility, |
280 | node: InFile<N>, | 284 | node: InFile<N>, |
281 | ) -> ConstData { | 285 | ) -> ConstData { |
286 | let ctx = LowerCtx::new(db, node.file_id); | ||
282 | let name = node.value.name().map(|n| n.as_name()); | 287 | let name = node.value.name().map(|n| n.as_name()); |
283 | let type_ref = TypeRef::from_ast_opt(node.value.ascribed_type()); | 288 | let type_ref = TypeRef::from_ast_opt(&ctx, node.value.ascribed_type()); |
284 | let visibility = | 289 | let visibility = |
285 | RawVisibility::from_ast_with_default(db, vis_default, node.map(|n| n.visibility())); | 290 | RawVisibility::from_ast_with_default(db, vis_default, node.map(|n| n.visibility())); |
286 | ConstData { name, type_ref, visibility } | 291 | ConstData { name, type_ref, visibility } |
diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs index d850244c4..09a5241f7 100644 --- a/crates/ra_hir_def/src/generics.rs +++ b/crates/ra_hir_def/src/generics.rs | |||
@@ -15,6 +15,7 @@ use ra_prof::profile; | |||
15 | use ra_syntax::ast::{self, NameOwner, TypeBoundsOwner, TypeParamsOwner}; | 15 | use ra_syntax::ast::{self, NameOwner, TypeBoundsOwner, TypeParamsOwner}; |
16 | 16 | ||
17 | use crate::{ | 17 | use crate::{ |
18 | body::LowerCtx, | ||
18 | child_by_source::ChildBySource, | 19 | child_by_source::ChildBySource, |
19 | db::DefDatabase, | 20 | db::DefDatabase, |
20 | dyn_map::DynMap, | 21 | dyn_map::DynMap, |
@@ -80,11 +81,13 @@ impl GenericParams { | |||
80 | fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMap>) { | 81 | fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMap>) { |
81 | let mut generics = GenericParams { types: Arena::default(), where_predicates: Vec::new() }; | 82 | let mut generics = GenericParams { types: Arena::default(), where_predicates: Vec::new() }; |
82 | let mut sm = ArenaMap::default(); | 83 | let mut sm = ArenaMap::default(); |
84 | |||
83 | // FIXME: add `: Sized` bound for everything except for `Self` in traits | 85 | // FIXME: add `: Sized` bound for everything except for `Self` in traits |
84 | let file_id = match def { | 86 | let file_id = match def { |
85 | GenericDefId::FunctionId(it) => { | 87 | GenericDefId::FunctionId(it) => { |
86 | let src = it.lookup(db).source(db); | 88 | let src = it.lookup(db).source(db); |
87 | generics.fill(&mut sm, &src.value); | 89 | let lower_ctx = LowerCtx::new(db, src.file_id); |
90 | generics.fill(&lower_ctx, &mut sm, &src.value); | ||
88 | // lower `impl Trait` in arguments | 91 | // lower `impl Trait` in arguments |
89 | let data = db.function_data(it); | 92 | let data = db.function_data(it); |
90 | for param in &data.params { | 93 | for param in &data.params { |
@@ -94,21 +97,25 @@ impl GenericParams { | |||
94 | } | 97 | } |
95 | GenericDefId::AdtId(AdtId::StructId(it)) => { | 98 | GenericDefId::AdtId(AdtId::StructId(it)) => { |
96 | let src = it.lookup(db).source(db); | 99 | let src = it.lookup(db).source(db); |
97 | generics.fill(&mut sm, &src.value); | 100 | let lower_ctx = LowerCtx::new(db, src.file_id); |
101 | generics.fill(&lower_ctx, &mut sm, &src.value); | ||
98 | src.file_id | 102 | src.file_id |
99 | } | 103 | } |
100 | GenericDefId::AdtId(AdtId::UnionId(it)) => { | 104 | GenericDefId::AdtId(AdtId::UnionId(it)) => { |
101 | let src = it.lookup(db).source(db); | 105 | let src = it.lookup(db).source(db); |
102 | generics.fill(&mut sm, &src.value); | 106 | let lower_ctx = LowerCtx::new(db, src.file_id); |
107 | generics.fill(&lower_ctx, &mut sm, &src.value); | ||
103 | src.file_id | 108 | src.file_id |
104 | } | 109 | } |
105 | GenericDefId::AdtId(AdtId::EnumId(it)) => { | 110 | GenericDefId::AdtId(AdtId::EnumId(it)) => { |
106 | let src = it.lookup(db).source(db); | 111 | let src = it.lookup(db).source(db); |
107 | generics.fill(&mut sm, &src.value); | 112 | let lower_ctx = LowerCtx::new(db, src.file_id); |
113 | generics.fill(&lower_ctx, &mut sm, &src.value); | ||
108 | src.file_id | 114 | src.file_id |
109 | } | 115 | } |
110 | GenericDefId::TraitId(it) => { | 116 | GenericDefId::TraitId(it) => { |
111 | let src = it.lookup(db).source(db); | 117 | let src = it.lookup(db).source(db); |
118 | let lower_ctx = LowerCtx::new(db, src.file_id); | ||
112 | 119 | ||
113 | // traits get the Self type as an implicit first type parameter | 120 | // traits get the Self type as an implicit first type parameter |
114 | let self_param_id = generics.types.alloc(TypeParamData { | 121 | let self_param_id = generics.types.alloc(TypeParamData { |
@@ -120,14 +127,16 @@ impl GenericParams { | |||
120 | // add super traits as bounds on Self | 127 | // add super traits as bounds on Self |
121 | // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar | 128 | // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar |
122 | let self_param = TypeRef::Path(name![Self].into()); | 129 | let self_param = TypeRef::Path(name![Self].into()); |
123 | generics.fill_bounds(&src.value, self_param); | 130 | generics.fill_bounds(&lower_ctx, &src.value, self_param); |
124 | 131 | ||
125 | generics.fill(&mut sm, &src.value); | 132 | generics.fill(&lower_ctx, &mut sm, &src.value); |
126 | src.file_id | 133 | src.file_id |
127 | } | 134 | } |
128 | GenericDefId::TypeAliasId(it) => { | 135 | GenericDefId::TypeAliasId(it) => { |
129 | let src = it.lookup(db).source(db); | 136 | let src = it.lookup(db).source(db); |
130 | generics.fill(&mut sm, &src.value); | 137 | let lower_ctx = LowerCtx::new(db, src.file_id); |
138 | |||
139 | generics.fill(&lower_ctx, &mut sm, &src.value); | ||
131 | src.file_id | 140 | src.file_id |
132 | } | 141 | } |
133 | // Note that we don't add `Self` here: in `impl`s, `Self` is not a | 142 | // Note that we don't add `Self` here: in `impl`s, `Self` is not a |
@@ -135,7 +144,9 @@ impl GenericParams { | |||
135 | // type, so this is handled by the resolver. | 144 | // type, so this is handled by the resolver. |
136 | GenericDefId::ImplId(it) => { | 145 | GenericDefId::ImplId(it) => { |
137 | let src = it.lookup(db).source(db); | 146 | let src = it.lookup(db).source(db); |
138 | generics.fill(&mut sm, &src.value); | 147 | let lower_ctx = LowerCtx::new(db, src.file_id); |
148 | |||
149 | generics.fill(&lower_ctx, &mut sm, &src.value); | ||
139 | src.file_id | 150 | src.file_id |
140 | } | 151 | } |
141 | // We won't be using this ID anyway | 152 | // We won't be using this ID anyway |
@@ -145,28 +156,38 @@ impl GenericParams { | |||
145 | (generics, InFile::new(file_id, sm)) | 156 | (generics, InFile::new(file_id, sm)) |
146 | } | 157 | } |
147 | 158 | ||
148 | fn fill(&mut self, sm: &mut SourceMap, node: &dyn TypeParamsOwner) { | 159 | fn fill(&mut self, lower_ctx: &LowerCtx, sm: &mut SourceMap, node: &dyn TypeParamsOwner) { |
149 | if let Some(params) = node.type_param_list() { | 160 | if let Some(params) = node.type_param_list() { |
150 | self.fill_params(sm, params) | 161 | self.fill_params(lower_ctx, sm, params) |
151 | } | 162 | } |
152 | if let Some(where_clause) = node.where_clause() { | 163 | if let Some(where_clause) = node.where_clause() { |
153 | self.fill_where_predicates(where_clause); | 164 | self.fill_where_predicates(lower_ctx, where_clause); |
154 | } | 165 | } |
155 | } | 166 | } |
156 | 167 | ||
157 | fn fill_bounds(&mut self, node: &dyn ast::TypeBoundsOwner, type_ref: TypeRef) { | 168 | fn fill_bounds( |
169 | &mut self, | ||
170 | lower_ctx: &LowerCtx, | ||
171 | node: &dyn ast::TypeBoundsOwner, | ||
172 | type_ref: TypeRef, | ||
173 | ) { | ||
158 | for bound in | 174 | for bound in |
159 | node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds()) | 175 | node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds()) |
160 | { | 176 | { |
161 | self.add_where_predicate_from_bound(bound, type_ref.clone()); | 177 | self.add_where_predicate_from_bound(lower_ctx, bound, type_ref.clone()); |
162 | } | 178 | } |
163 | } | 179 | } |
164 | 180 | ||
165 | fn fill_params(&mut self, sm: &mut SourceMap, params: ast::TypeParamList) { | 181 | fn fill_params( |
182 | &mut self, | ||
183 | lower_ctx: &LowerCtx, | ||
184 | sm: &mut SourceMap, | ||
185 | params: ast::TypeParamList, | ||
186 | ) { | ||
166 | for type_param in params.type_params() { | 187 | for type_param in params.type_params() { |
167 | let name = type_param.name().map_or_else(Name::missing, |it| it.as_name()); | 188 | let name = type_param.name().map_or_else(Name::missing, |it| it.as_name()); |
168 | // FIXME: Use `Path::from_src` | 189 | // FIXME: Use `Path::from_src` |
169 | let default = type_param.default_type().map(TypeRef::from_ast); | 190 | let default = type_param.default_type().map(|it| TypeRef::from_ast(lower_ctx, it)); |
170 | let param = TypeParamData { | 191 | let param = TypeParamData { |
171 | name: Some(name.clone()), | 192 | name: Some(name.clone()), |
172 | default, | 193 | default, |
@@ -176,29 +197,34 @@ impl GenericParams { | |||
176 | sm.insert(param_id, Either::Right(type_param.clone())); | 197 | sm.insert(param_id, Either::Right(type_param.clone())); |
177 | 198 | ||
178 | let type_ref = TypeRef::Path(name.into()); | 199 | let type_ref = TypeRef::Path(name.into()); |
179 | self.fill_bounds(&type_param, type_ref); | 200 | self.fill_bounds(&lower_ctx, &type_param, type_ref); |
180 | } | 201 | } |
181 | } | 202 | } |
182 | 203 | ||
183 | fn fill_where_predicates(&mut self, where_clause: ast::WhereClause) { | 204 | fn fill_where_predicates(&mut self, lower_ctx: &LowerCtx, where_clause: ast::WhereClause) { |
184 | for pred in where_clause.predicates() { | 205 | for pred in where_clause.predicates() { |
185 | let type_ref = match pred.type_ref() { | 206 | let type_ref = match pred.type_ref() { |
186 | Some(type_ref) => type_ref, | 207 | Some(type_ref) => type_ref, |
187 | None => continue, | 208 | None => continue, |
188 | }; | 209 | }; |
189 | let type_ref = TypeRef::from_ast(type_ref); | 210 | let type_ref = TypeRef::from_ast(lower_ctx, type_ref); |
190 | for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) { | 211 | for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) { |
191 | self.add_where_predicate_from_bound(bound, type_ref.clone()); | 212 | self.add_where_predicate_from_bound(lower_ctx, bound, type_ref.clone()); |
192 | } | 213 | } |
193 | } | 214 | } |
194 | } | 215 | } |
195 | 216 | ||
196 | fn add_where_predicate_from_bound(&mut self, bound: ast::TypeBound, type_ref: TypeRef) { | 217 | fn add_where_predicate_from_bound( |
218 | &mut self, | ||
219 | lower_ctx: &LowerCtx, | ||
220 | bound: ast::TypeBound, | ||
221 | type_ref: TypeRef, | ||
222 | ) { | ||
197 | if bound.question_token().is_some() { | 223 | if bound.question_token().is_some() { |
198 | // FIXME: remove this bound | 224 | // FIXME: remove this bound |
199 | return; | 225 | return; |
200 | } | 226 | } |
201 | let bound = TypeBound::from_ast(bound); | 227 | let bound = TypeBound::from_ast(lower_ctx, bound); |
202 | self.where_predicates | 228 | self.where_predicates |
203 | .push(WherePredicate { target: WherePredicateTarget::TypeRef(type_ref), bound }); | 229 | .push(WherePredicate { target: WherePredicateTarget::TypeRef(type_ref), bound }); |
204 | } | 230 | } |
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs index 162b3c8c7..e84efe2ab 100644 --- a/crates/ra_hir_def/src/path.rs +++ b/crates/ra_hir_def/src/path.rs | |||
@@ -7,6 +7,7 @@ use std::{ | |||
7 | sync::Arc, | 7 | sync::Arc, |
8 | }; | 8 | }; |
9 | 9 | ||
10 | use crate::body::LowerCtx; | ||
10 | use hir_expand::{ | 11 | use hir_expand::{ |
11 | hygiene::Hygiene, | 12 | hygiene::Hygiene, |
12 | name::{AsName, Name}, | 13 | name::{AsName, Name}, |
@@ -244,8 +245,8 @@ impl<'a> PathSegments<'a> { | |||
244 | } | 245 | } |
245 | 246 | ||
246 | impl GenericArgs { | 247 | impl GenericArgs { |
247 | pub(crate) fn from_ast(node: ast::TypeArgList) -> Option<GenericArgs> { | 248 | pub(crate) fn from_ast(lower_ctx: &LowerCtx, node: ast::TypeArgList) -> Option<GenericArgs> { |
248 | lower::lower_generic_args(node) | 249 | lower::lower_generic_args(lower_ctx, node) |
249 | } | 250 | } |
250 | 251 | ||
251 | pub(crate) fn empty() -> GenericArgs { | 252 | pub(crate) fn empty() -> GenericArgs { |
diff --git a/crates/ra_hir_def/src/path/lower.rs b/crates/ra_hir_def/src/path/lower.rs index 9ec2e0dcd..e3d237a0a 100644 --- a/crates/ra_hir_def/src/path/lower.rs +++ b/crates/ra_hir_def/src/path/lower.rs | |||
@@ -13,6 +13,7 @@ use ra_syntax::ast::{self, AstNode, TypeAscriptionOwner, TypeBoundsOwner}; | |||
13 | 13 | ||
14 | use super::AssociatedTypeBinding; | 14 | use super::AssociatedTypeBinding; |
15 | use crate::{ | 15 | use crate::{ |
16 | body::LowerCtx, | ||
16 | path::{GenericArg, GenericArgs, ModPath, Path, PathKind}, | 17 | path::{GenericArg, GenericArgs, ModPath, Path, PathKind}, |
17 | type_ref::{TypeBound, TypeRef}, | 18 | type_ref::{TypeBound, TypeRef}, |
18 | }; | 19 | }; |
@@ -26,6 +27,7 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> | |||
26 | let mut type_anchor = None; | 27 | let mut type_anchor = None; |
27 | let mut segments = Vec::new(); | 28 | let mut segments = Vec::new(); |
28 | let mut generic_args = Vec::new(); | 29 | let mut generic_args = Vec::new(); |
30 | let ctx = LowerCtx::with_hygiene(hygiene); | ||
29 | loop { | 31 | loop { |
30 | let segment = path.segment()?; | 32 | let segment = path.segment()?; |
31 | 33 | ||
@@ -40,9 +42,10 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> | |||
40 | Either::Left(name) => { | 42 | Either::Left(name) => { |
41 | let args = segment | 43 | let args = segment |
42 | .type_arg_list() | 44 | .type_arg_list() |
43 | .and_then(lower_generic_args) | 45 | .and_then(|it| lower_generic_args(&ctx, it)) |
44 | .or_else(|| { | 46 | .or_else(|| { |
45 | lower_generic_args_from_fn_path( | 47 | lower_generic_args_from_fn_path( |
48 | &ctx, | ||
46 | segment.param_list(), | 49 | segment.param_list(), |
47 | segment.ret_type(), | 50 | segment.ret_type(), |
48 | ) | 51 | ) |
@@ -60,7 +63,7 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> | |||
60 | ast::PathSegmentKind::Type { type_ref, trait_ref } => { | 63 | ast::PathSegmentKind::Type { type_ref, trait_ref } => { |
61 | assert!(path.qualifier().is_none()); // this can only occur at the first segment | 64 | assert!(path.qualifier().is_none()); // this can only occur at the first segment |
62 | 65 | ||
63 | let self_type = TypeRef::from_ast(type_ref?); | 66 | let self_type = TypeRef::from_ast(&ctx, type_ref?); |
64 | 67 | ||
65 | match trait_ref { | 68 | match trait_ref { |
66 | // <T>::foo | 69 | // <T>::foo |
@@ -128,10 +131,13 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> | |||
128 | } | 131 | } |
129 | } | 132 | } |
130 | 133 | ||
131 | pub(super) fn lower_generic_args(node: ast::TypeArgList) -> Option<GenericArgs> { | 134 | pub(super) fn lower_generic_args( |
135 | lower_ctx: &LowerCtx, | ||
136 | node: ast::TypeArgList, | ||
137 | ) -> Option<GenericArgs> { | ||
132 | let mut args = Vec::new(); | 138 | let mut args = Vec::new(); |
133 | for type_arg in node.type_args() { | 139 | for type_arg in node.type_args() { |
134 | let type_ref = TypeRef::from_ast_opt(type_arg.type_ref()); | 140 | let type_ref = TypeRef::from_ast_opt(lower_ctx, type_arg.type_ref()); |
135 | args.push(GenericArg::Type(type_ref)); | 141 | args.push(GenericArg::Type(type_ref)); |
136 | } | 142 | } |
137 | // lifetimes ignored for now | 143 | // lifetimes ignored for now |
@@ -140,9 +146,9 @@ pub(super) fn lower_generic_args(node: ast::TypeArgList) -> Option<GenericArgs> | |||
140 | let assoc_type_arg: ast::AssocTypeArg = assoc_type_arg; | 146 | let assoc_type_arg: ast::AssocTypeArg = assoc_type_arg; |
141 | if let Some(name_ref) = assoc_type_arg.name_ref() { | 147 | if let Some(name_ref) = assoc_type_arg.name_ref() { |
142 | let name = name_ref.as_name(); | 148 | let name = name_ref.as_name(); |
143 | let type_ref = assoc_type_arg.type_ref().map(TypeRef::from_ast); | 149 | let type_ref = assoc_type_arg.type_ref().map(|it| TypeRef::from_ast(lower_ctx, it)); |
144 | let bounds = if let Some(l) = assoc_type_arg.type_bound_list() { | 150 | let bounds = if let Some(l) = assoc_type_arg.type_bound_list() { |
145 | l.bounds().map(TypeBound::from_ast).collect() | 151 | l.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)).collect() |
146 | } else { | 152 | } else { |
147 | Vec::new() | 153 | Vec::new() |
148 | }; | 154 | }; |
@@ -159,6 +165,7 @@ pub(super) fn lower_generic_args(node: ast::TypeArgList) -> Option<GenericArgs> | |||
159 | /// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y) | 165 | /// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y) |
160 | /// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`). | 166 | /// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`). |
161 | fn lower_generic_args_from_fn_path( | 167 | fn lower_generic_args_from_fn_path( |
168 | ctx: &LowerCtx, | ||
162 | params: Option<ast::ParamList>, | 169 | params: Option<ast::ParamList>, |
163 | ret_type: Option<ast::RetType>, | 170 | ret_type: Option<ast::RetType>, |
164 | ) -> Option<GenericArgs> { | 171 | ) -> Option<GenericArgs> { |
@@ -167,14 +174,14 @@ fn lower_generic_args_from_fn_path( | |||
167 | if let Some(params) = params { | 174 | if let Some(params) = params { |
168 | let mut param_types = Vec::new(); | 175 | let mut param_types = Vec::new(); |
169 | for param in params.params() { | 176 | for param in params.params() { |
170 | let type_ref = TypeRef::from_ast_opt(param.ascribed_type()); | 177 | let type_ref = TypeRef::from_ast_opt(&ctx, param.ascribed_type()); |
171 | param_types.push(type_ref); | 178 | param_types.push(type_ref); |
172 | } | 179 | } |
173 | let arg = GenericArg::Type(TypeRef::Tuple(param_types)); | 180 | let arg = GenericArg::Type(TypeRef::Tuple(param_types)); |
174 | args.push(arg); | 181 | args.push(arg); |
175 | } | 182 | } |
176 | if let Some(ret_type) = ret_type { | 183 | if let Some(ret_type) = ret_type { |
177 | let type_ref = TypeRef::from_ast_opt(ret_type.type_ref()); | 184 | let type_ref = TypeRef::from_ast_opt(&ctx, ret_type.type_ref()); |
178 | bindings.push(AssociatedTypeBinding { | 185 | bindings.push(AssociatedTypeBinding { |
179 | name: name![Output], | 186 | name: name![Output], |
180 | type_ref: Some(type_ref), | 187 | type_ref: Some(type_ref), |
diff --git a/crates/ra_hir_def/src/type_ref.rs b/crates/ra_hir_def/src/type_ref.rs index f308c6bdf..5bdad9efd 100644 --- a/crates/ra_hir_def/src/type_ref.rs +++ b/crates/ra_hir_def/src/type_ref.rs | |||
@@ -3,7 +3,7 @@ | |||
3 | 3 | ||
4 | use ra_syntax::ast::{self, TypeAscriptionOwner, TypeBoundsOwner}; | 4 | use ra_syntax::ast::{self, TypeAscriptionOwner, TypeBoundsOwner}; |
5 | 5 | ||
6 | use crate::path::Path; | 6 | use crate::{body::LowerCtx, path::Path}; |
7 | 7 | ||
8 | #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] | 8 | #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] |
9 | pub enum Mutability { | 9 | pub enum Mutability { |
@@ -64,30 +64,34 @@ pub enum TypeBound { | |||
64 | 64 | ||
65 | impl TypeRef { | 65 | impl TypeRef { |
66 | /// Converts an `ast::TypeRef` to a `hir::TypeRef`. | 66 | /// Converts an `ast::TypeRef` to a `hir::TypeRef`. |
67 | pub(crate) fn from_ast(node: ast::TypeRef) -> Self { | 67 | pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::TypeRef) -> Self { |
68 | match node { | 68 | match node { |
69 | ast::TypeRef::ParenType(inner) => TypeRef::from_ast_opt(inner.type_ref()), | 69 | ast::TypeRef::ParenType(inner) => TypeRef::from_ast_opt(&ctx, inner.type_ref()), |
70 | ast::TypeRef::TupleType(inner) => { | 70 | ast::TypeRef::TupleType(inner) => { |
71 | TypeRef::Tuple(inner.fields().map(TypeRef::from_ast).collect()) | 71 | TypeRef::Tuple(inner.fields().map(|it| TypeRef::from_ast(ctx, it)).collect()) |
72 | } | 72 | } |
73 | ast::TypeRef::NeverType(..) => TypeRef::Never, | 73 | ast::TypeRef::NeverType(..) => TypeRef::Never, |
74 | ast::TypeRef::PathType(inner) => { | 74 | ast::TypeRef::PathType(inner) => { |
75 | // FIXME: Use `Path::from_src` | 75 | // FIXME: Use `Path::from_src` |
76 | inner.path().and_then(Path::from_ast).map(TypeRef::Path).unwrap_or(TypeRef::Error) | 76 | inner |
77 | .path() | ||
78 | .and_then(|it| ctx.lower_path(it)) | ||
79 | .map(TypeRef::Path) | ||
80 | .unwrap_or(TypeRef::Error) | ||
77 | } | 81 | } |
78 | ast::TypeRef::PointerType(inner) => { | 82 | ast::TypeRef::PointerType(inner) => { |
79 | let inner_ty = TypeRef::from_ast_opt(inner.type_ref()); | 83 | let inner_ty = TypeRef::from_ast_opt(&ctx, inner.type_ref()); |
80 | let mutability = Mutability::from_mutable(inner.mut_token().is_some()); | 84 | let mutability = Mutability::from_mutable(inner.mut_token().is_some()); |
81 | TypeRef::RawPtr(Box::new(inner_ty), mutability) | 85 | TypeRef::RawPtr(Box::new(inner_ty), mutability) |
82 | } | 86 | } |
83 | ast::TypeRef::ArrayType(inner) => { | 87 | ast::TypeRef::ArrayType(inner) => { |
84 | TypeRef::Array(Box::new(TypeRef::from_ast_opt(inner.type_ref()))) | 88 | TypeRef::Array(Box::new(TypeRef::from_ast_opt(&ctx, inner.type_ref()))) |
85 | } | 89 | } |
86 | ast::TypeRef::SliceType(inner) => { | 90 | ast::TypeRef::SliceType(inner) => { |
87 | TypeRef::Slice(Box::new(TypeRef::from_ast_opt(inner.type_ref()))) | 91 | TypeRef::Slice(Box::new(TypeRef::from_ast_opt(&ctx, inner.type_ref()))) |
88 | } | 92 | } |
89 | ast::TypeRef::ReferenceType(inner) => { | 93 | ast::TypeRef::ReferenceType(inner) => { |
90 | let inner_ty = TypeRef::from_ast_opt(inner.type_ref()); | 94 | let inner_ty = TypeRef::from_ast_opt(&ctx, inner.type_ref()); |
91 | let mutability = Mutability::from_mutable(inner.mut_token().is_some()); | 95 | let mutability = Mutability::from_mutable(inner.mut_token().is_some()); |
92 | TypeRef::Reference(Box::new(inner_ty), mutability) | 96 | TypeRef::Reference(Box::new(inner_ty), mutability) |
93 | } | 97 | } |
@@ -96,10 +100,13 @@ impl TypeRef { | |||
96 | let ret_ty = inner | 100 | let ret_ty = inner |
97 | .ret_type() | 101 | .ret_type() |
98 | .and_then(|rt| rt.type_ref()) | 102 | .and_then(|rt| rt.type_ref()) |
99 | .map(TypeRef::from_ast) | 103 | .map(|it| TypeRef::from_ast(ctx, it)) |
100 | .unwrap_or_else(|| TypeRef::Tuple(Vec::new())); | 104 | .unwrap_or_else(|| TypeRef::Tuple(Vec::new())); |
101 | let mut params = if let Some(pl) = inner.param_list() { | 105 | let mut params = if let Some(pl) = inner.param_list() { |
102 | pl.params().map(|p| p.ascribed_type()).map(TypeRef::from_ast_opt).collect() | 106 | pl.params() |
107 | .map(|p| p.ascribed_type()) | ||
108 | .map(|it| TypeRef::from_ast_opt(&ctx, it)) | ||
109 | .collect() | ||
103 | } else { | 110 | } else { |
104 | Vec::new() | 111 | Vec::new() |
105 | }; | 112 | }; |
@@ -107,19 +114,19 @@ impl TypeRef { | |||
107 | TypeRef::Fn(params) | 114 | TypeRef::Fn(params) |
108 | } | 115 | } |
109 | // for types are close enough for our purposes to the inner type for now... | 116 | // for types are close enough for our purposes to the inner type for now... |
110 | ast::TypeRef::ForType(inner) => TypeRef::from_ast_opt(inner.type_ref()), | 117 | ast::TypeRef::ForType(inner) => TypeRef::from_ast_opt(&ctx, inner.type_ref()), |
111 | ast::TypeRef::ImplTraitType(inner) => { | 118 | ast::TypeRef::ImplTraitType(inner) => { |
112 | TypeRef::ImplTrait(type_bounds_from_ast(inner.type_bound_list())) | 119 | TypeRef::ImplTrait(type_bounds_from_ast(ctx, inner.type_bound_list())) |
113 | } | 120 | } |
114 | ast::TypeRef::DynTraitType(inner) => { | 121 | ast::TypeRef::DynTraitType(inner) => { |
115 | TypeRef::DynTrait(type_bounds_from_ast(inner.type_bound_list())) | 122 | TypeRef::DynTrait(type_bounds_from_ast(ctx, inner.type_bound_list())) |
116 | } | 123 | } |
117 | } | 124 | } |
118 | } | 125 | } |
119 | 126 | ||
120 | pub(crate) fn from_ast_opt(node: Option<ast::TypeRef>) -> Self { | 127 | pub(crate) fn from_ast_opt(ctx: &LowerCtx, node: Option<ast::TypeRef>) -> Self { |
121 | if let Some(node) = node { | 128 | if let Some(node) = node { |
122 | TypeRef::from_ast(node) | 129 | TypeRef::from_ast(ctx, node) |
123 | } else { | 130 | } else { |
124 | TypeRef::Error | 131 | TypeRef::Error |
125 | } | 132 | } |
@@ -180,24 +187,27 @@ impl TypeRef { | |||
180 | } | 187 | } |
181 | } | 188 | } |
182 | 189 | ||
183 | pub(crate) fn type_bounds_from_ast(type_bounds_opt: Option<ast::TypeBoundList>) -> Vec<TypeBound> { | 190 | pub(crate) fn type_bounds_from_ast( |
191 | lower_ctx: &LowerCtx, | ||
192 | type_bounds_opt: Option<ast::TypeBoundList>, | ||
193 | ) -> Vec<TypeBound> { | ||
184 | if let Some(type_bounds) = type_bounds_opt { | 194 | if let Some(type_bounds) = type_bounds_opt { |
185 | type_bounds.bounds().map(TypeBound::from_ast).collect() | 195 | type_bounds.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)).collect() |
186 | } else { | 196 | } else { |
187 | vec![] | 197 | vec![] |
188 | } | 198 | } |
189 | } | 199 | } |
190 | 200 | ||
191 | impl TypeBound { | 201 | impl TypeBound { |
192 | pub(crate) fn from_ast(node: ast::TypeBound) -> Self { | 202 | pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::TypeBound) -> Self { |
193 | match node.kind() { | 203 | match node.kind() { |
194 | ast::TypeBoundKind::PathType(path_type) => { | 204 | ast::TypeBoundKind::PathType(path_type) => { |
195 | let path = match path_type.path() { | 205 | let path = match path_type.path() { |
196 | Some(p) => p, | 206 | Some(p) => p, |
197 | None => return TypeBound::Error, | 207 | None => return TypeBound::Error, |
198 | }; | 208 | }; |
199 | // FIXME: Use `Path::from_src` | 209 | |
200 | let path = match Path::from_ast(path) { | 210 | let path = match ctx.lower_path(path) { |
201 | Some(p) => p, | 211 | Some(p) => p, |
202 | None => return TypeBound::Error, | 212 | None => return TypeBound::Error, |
203 | }; | 213 | }; |
diff --git a/crates/ra_hir_expand/src/hygiene.rs b/crates/ra_hir_expand/src/hygiene.rs index 0b41d0e95..53866bbcb 100644 --- a/crates/ra_hir_expand/src/hygiene.rs +++ b/crates/ra_hir_expand/src/hygiene.rs | |||
@@ -12,7 +12,7 @@ use crate::{ | |||
12 | HirFileId, HirFileIdRepr, MacroCallId, MacroDefKind, | 12 | HirFileId, HirFileIdRepr, MacroCallId, MacroDefKind, |
13 | }; | 13 | }; |
14 | 14 | ||
15 | #[derive(Debug)] | 15 | #[derive(Clone, Debug)] |
16 | pub struct Hygiene { | 16 | pub struct Hygiene { |
17 | // This is what `$crate` expands to | 17 | // This is what `$crate` expands to |
18 | def_crate: Option<CrateId>, | 18 | def_crate: Option<CrateId>, |
diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs index 5ddecbdc6..1f796876d 100644 --- a/crates/ra_hir_ty/src/tests/macros.rs +++ b/crates/ra_hir_ty/src/tests/macros.rs | |||
@@ -339,6 +339,46 @@ pub fn baz() -> usize { 31usize } | |||
339 | } | 339 | } |
340 | 340 | ||
341 | #[test] | 341 | #[test] |
342 | fn infer_macro_with_dollar_crate_is_correct_in_trait_associate_type() { | ||
343 | let (db, pos) = TestDB::with_position( | ||
344 | r#" | ||
345 | //- /main.rs crate:main deps:foo | ||
346 | use foo::Trait; | ||
347 | |||
348 | fn test() { | ||
349 | let msg = foo::Message(foo::MessageRef); | ||
350 | let r = msg.deref(); | ||
351 | r<|>; | ||
352 | } | ||
353 | |||
354 | //- /lib.rs crate:foo | ||
355 | pub struct MessageRef; | ||
356 | pub struct Message(MessageRef); | ||
357 | |||
358 | pub trait Trait { | ||
359 | type Target; | ||
360 | fn deref(&self) -> &Self::Target; | ||
361 | } | ||
362 | |||
363 | #[macro_export] | ||
364 | macro_rules! expand { | ||
365 | () => { | ||
366 | impl Trait for Message { | ||
367 | type Target = $crate::MessageRef; | ||
368 | fn deref(&self) -> &Self::Target { | ||
369 | &self.0 | ||
370 | } | ||
371 | } | ||
372 | } | ||
373 | } | ||
374 | |||
375 | expand!(); | ||
376 | "#, | ||
377 | ); | ||
378 | assert_eq!("&MessageRef", type_at_pos(&db, pos)); | ||
379 | } | ||
380 | |||
381 | #[test] | ||
342 | fn infer_type_value_non_legacy_macro_use_as() { | 382 | fn infer_type_value_non_legacy_macro_use_as() { |
343 | assert_snapshot!( | 383 | assert_snapshot!( |
344 | infer(r#" | 384 | infer(r#" |
diff --git a/crates/ra_ide/src/display/short_label.rs b/crates/ra_ide/src/display/short_label.rs index 4b081bf6c..d37260e96 100644 --- a/crates/ra_ide/src/display/short_label.rs +++ b/crates/ra_ide/src/display/short_label.rs | |||
@@ -33,7 +33,11 @@ impl ShortLabel for ast::EnumDef { | |||
33 | 33 | ||
34 | impl ShortLabel for ast::TraitDef { | 34 | impl ShortLabel for ast::TraitDef { |
35 | fn short_label(&self) -> Option<String> { | 35 | fn short_label(&self) -> Option<String> { |
36 | short_label_from_node(self, "trait ") | 36 | if self.unsafe_token().is_some() { |
37 | short_label_from_node(self, "unsafe trait ") | ||
38 | } else { | ||
39 | short_label_from_node(self, "trait ") | ||
40 | } | ||
37 | } | 41 | } |
38 | } | 42 | } |
39 | 43 | ||
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index a62f598f0..54d318858 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs | |||
@@ -869,4 +869,15 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
869 | &[r#"pub(crate) async unsafe extern "C" fn foo()"#], | 869 | &[r#"pub(crate) async unsafe extern "C" fn foo()"#], |
870 | ); | 870 | ); |
871 | } | 871 | } |
872 | |||
873 | #[test] | ||
874 | fn test_hover_trait_show_qualifiers() { | ||
875 | check_hover_result( | ||
876 | " | ||
877 | //- /lib.rs | ||
878 | unsafe trait foo<|>() {} | ||
879 | ", | ||
880 | &["unsafe trait foo"], | ||
881 | ); | ||
882 | } | ||
872 | } | 883 | } |
diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs index f2ea5088e..45e3dd2d3 100644 --- a/crates/ra_syntax/src/ast/extensions.rs +++ b/crates/ra_syntax/src/ast/extensions.rs | |||
@@ -407,7 +407,7 @@ impl ast::Visibility { | |||
407 | } else if self.super_token().is_some() { | 407 | } else if self.super_token().is_some() { |
408 | VisibilityKind::PubSuper | 408 | VisibilityKind::PubSuper |
409 | } else if self.self_token().is_some() { | 409 | } else if self.self_token().is_some() { |
410 | VisibilityKind::PubSuper | 410 | VisibilityKind::PubSelf |
411 | } else { | 411 | } else { |
412 | VisibilityKind::Pub | 412 | VisibilityKind::Pub |
413 | } | 413 | } |
diff --git a/crates/ra_syntax/src/ast/generated/nodes.rs b/crates/ra_syntax/src/ast/generated/nodes.rs index 81260680f..3f16592b6 100644 --- a/crates/ra_syntax/src/ast/generated/nodes.rs +++ b/crates/ra_syntax/src/ast/generated/nodes.rs | |||
@@ -1241,6 +1241,8 @@ pub struct PathSegment { | |||
1241 | impl PathSegment { | 1241 | impl PathSegment { |
1242 | pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) } | 1242 | pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) } |
1243 | pub fn crate_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![crate]) } | 1243 | pub fn crate_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![crate]) } |
1244 | pub fn self_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![self]) } | ||
1245 | pub fn super_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![super]) } | ||
1244 | pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) } | 1246 | pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) } |
1245 | pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) } | 1247 | pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) } |
1246 | pub fn type_arg_list(&self) -> Option<TypeArgList> { support::child(&self.syntax) } | 1248 | pub fn type_arg_list(&self) -> Option<TypeArgList> { support::child(&self.syntax) } |
diff --git a/crates/ra_syntax/src/validation.rs b/crates/ra_syntax/src/validation.rs index f0b3dec63..e075cd801 100644 --- a/crates/ra_syntax/src/validation.rs +++ b/crates/ra_syntax/src/validation.rs | |||
@@ -96,7 +96,7 @@ pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> { | |||
96 | ast::RecordField(it) => validate_numeric_name(it.name_ref(), &mut errors), | 96 | ast::RecordField(it) => validate_numeric_name(it.name_ref(), &mut errors), |
97 | ast::Visibility(it) => validate_visibility(it, &mut errors), | 97 | ast::Visibility(it) => validate_visibility(it, &mut errors), |
98 | ast::RangeExpr(it) => validate_range_expr(it, &mut errors), | 98 | ast::RangeExpr(it) => validate_range_expr(it, &mut errors), |
99 | ast::PathSegment(it) => validate_crate_keyword_in_path_segment(it, &mut errors), | 99 | ast::PathSegment(it) => validate_path_keywords(it, &mut errors), |
100 | _ => (), | 100 | _ => (), |
101 | } | 101 | } |
102 | } | 102 | } |
@@ -224,59 +224,82 @@ fn validate_range_expr(expr: ast::RangeExpr, errors: &mut Vec<SyntaxError>) { | |||
224 | } | 224 | } |
225 | } | 225 | } |
226 | 226 | ||
227 | fn validate_crate_keyword_in_path_segment( | 227 | fn validate_path_keywords(segment: ast::PathSegment, errors: &mut Vec<SyntaxError>) { |
228 | segment: ast::PathSegment, | 228 | use ast::PathSegmentKind; |
229 | errors: &mut Vec<SyntaxError>, | ||
230 | ) { | ||
231 | const ERR_MSG: &str = "The `crate` keyword is only allowed as the first segment of a path"; | ||
232 | 229 | ||
233 | let crate_token = match segment.crate_token() { | 230 | let path = segment.parent_path(); |
234 | None => return, | 231 | let is_path_start = segment.coloncolon_token().is_none() && path.qualifier().is_none(); |
235 | Some(it) => it, | 232 | |
236 | }; | 233 | if let Some(token) = segment.self_token() { |
234 | if !is_path_start { | ||
235 | errors.push(SyntaxError::new( | ||
236 | "The `self` keyword is only allowed as the first segment of a path", | ||
237 | token.text_range(), | ||
238 | )); | ||
239 | } | ||
240 | } else if let Some(token) = segment.crate_token() { | ||
241 | if !is_path_start || use_prefix(path).is_some() { | ||
242 | errors.push(SyntaxError::new( | ||
243 | "The `crate` keyword is only allowed as the first segment of a path", | ||
244 | token.text_range(), | ||
245 | )); | ||
246 | } | ||
247 | } else if let Some(token) = segment.super_token() { | ||
248 | if !all_supers(&path) { | ||
249 | errors.push(SyntaxError::new( | ||
250 | "The `super` keyword may only be preceded by other `super`s", | ||
251 | token.text_range(), | ||
252 | )); | ||
253 | return; | ||
254 | } | ||
237 | 255 | ||
238 | // Disallow both ::crate and foo::crate | 256 | let mut curr_path = path; |
239 | let mut path = segment.parent_path(); | 257 | while let Some(prefix) = use_prefix(curr_path) { |
240 | if segment.coloncolon_token().is_some() || path.qualifier().is_some() { | 258 | if !all_supers(&prefix) { |
241 | errors.push(SyntaxError::new(ERR_MSG, crate_token.text_range())); | 259 | errors.push(SyntaxError::new( |
242 | return; | 260 | "The `super` keyword may only be preceded by other `super`s", |
261 | token.text_range(), | ||
262 | )); | ||
263 | return; | ||
264 | } | ||
265 | curr_path = prefix; | ||
266 | } | ||
243 | } | 267 | } |
244 | 268 | ||
245 | // For expressions and types, validation is complete, but we still have | 269 | fn use_prefix(mut path: ast::Path) -> Option<ast::Path> { |
246 | // to handle invalid UseItems like this: | 270 | for node in path.syntax().ancestors().skip(1) { |
247 | // | 271 | match_ast! { |
248 | // use foo:{crate::bar::baz}; | 272 | match node { |
249 | // | 273 | ast::UseTree(it) => if let Some(tree_path) = it.path() { |
250 | // To handle this we must inspect the parent `UseItem`s and `UseTree`s | 274 | // Even a top-level path exists within a `UseTree` so we must explicitly |
251 | // but right now we're looking deep inside the nested `Path` nodes because | 275 | // allow our path but disallow anything else |
252 | // `Path`s are left-associative: | 276 | if tree_path != path { |
253 | // | 277 | return Some(tree_path); |
254 | // ((crate)::bar)::baz) | 278 | } |
255 | // ^ current value of path | 279 | }, |
256 | // | 280 | ast::UseTreeList(_it) => continue, |
257 | // So we need to climb to the top | 281 | ast::Path(parent) => path = parent, |
258 | while let Some(parent) = path.parent_path() { | 282 | _ => return None, |
259 | path = parent; | 283 | } |
284 | }; | ||
285 | } | ||
286 | return None; | ||
260 | } | 287 | } |
261 | 288 | ||
262 | // Now that we've found the whole path we need to see if there's a prefix | 289 | fn all_supers(path: &ast::Path) -> bool { |
263 | // somewhere in the UseTree hierarchy. This check is arbitrarily deep | 290 | let segment = match path.segment() { |
264 | // because rust allows arbitrary nesting like so: | 291 | Some(it) => it, |
265 | // | 292 | None => return false, |
266 | // use {foo::{{{{crate::bar::baz}}}}}; | ||
267 | for node in path.syntax().ancestors().skip(1) { | ||
268 | match_ast! { | ||
269 | match node { | ||
270 | ast::UseTree(it) => if let Some(tree_path) = it.path() { | ||
271 | // Even a top-level path exists within a `UseTree` so we must explicitly | ||
272 | // allow our path but disallow anything else | ||
273 | if tree_path != path { | ||
274 | errors.push(SyntaxError::new(ERR_MSG, crate_token.text_range())); | ||
275 | } | ||
276 | }, | ||
277 | ast::UseTreeList(_it) => continue, | ||
278 | _ => return, | ||
279 | } | ||
280 | }; | 293 | }; |
294 | |||
295 | if segment.kind() != Some(PathSegmentKind::SuperKw) { | ||
296 | return false; | ||
297 | } | ||
298 | |||
299 | if let Some(ref subpath) = path.qualifier() { | ||
300 | return all_supers(subpath); | ||
301 | } | ||
302 | |||
303 | return true; | ||
281 | } | 304 | } |
282 | } | 305 | } |
diff --git a/crates/ra_syntax/test_data/parser/err/0041_illegal_super_keyword_location.rast b/crates/ra_syntax/test_data/parser/err/0041_illegal_super_keyword_location.rast new file mode 100644 index 000000000..d0360c467 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/err/0041_illegal_super_keyword_location.rast | |||
@@ -0,0 +1,70 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "use" | ||
4 | [email protected] " " | ||
5 | [email protected] | ||
6 | [email protected] | ||
7 | [email protected] | ||
8 | [email protected] "::" | ||
9 | [email protected] "super" | ||
10 | [email protected] ";" | ||
11 | [email protected] "\n" | ||
12 | [email protected] | ||
13 | [email protected] "use" | ||
14 | [email protected] " " | ||
15 | [email protected] | ||
16 | [email protected] | ||
17 | [email protected] | ||
18 | [email protected] | ||
19 | [email protected] | ||
20 | [email protected] "a" | ||
21 | [email protected] "::" | ||
22 | [email protected] | ||
23 | [email protected] "super" | ||
24 | [email protected] ";" | ||
25 | [email protected] "\n" | ||
26 | [email protected] | ||
27 | [email protected] "use" | ||
28 | [email protected] " " | ||
29 | [email protected] | ||
30 | [email protected] | ||
31 | [email protected] | ||
32 | [email protected] | ||
33 | [email protected] | ||
34 | [email protected] "super" | ||
35 | [email protected] "::" | ||
36 | [email protected] | ||
37 | [email protected] | ||
38 | [email protected] "a" | ||
39 | [email protected] "::" | ||
40 | [email protected] | ||
41 | [email protected] "super" | ||
42 | [email protected] ";" | ||
43 | [email protected] "\n" | ||
44 | [email protected] | ||
45 | [email protected] "use" | ||
46 | [email protected] " " | ||
47 | [email protected] | ||
48 | [email protected] | ||
49 | [email protected] | ||
50 | [email protected] | ||
51 | [email protected] "a" | ||
52 | [email protected] "::" | ||
53 | [email protected] | ||
54 | [email protected] "{" | ||
55 | [email protected] | ||
56 | [email protected] | ||
57 | [email protected] | ||
58 | [email protected] | ||
59 | [email protected] "super" | ||
60 | [email protected] "::" | ||
61 | [email protected] | ||
62 | [email protected] | ||
63 | [email protected] "b" | ||
64 | [email protected] "}" | ||
65 | [email protected] ";" | ||
66 | [email protected] "\n" | ||
67 | error 6..11: The `super` keyword may only be preceded by other `super`s | ||
68 | error 20..25: The `super` keyword may only be preceded by other `super`s | ||
69 | error 41..46: The `super` keyword may only be preceded by other `super`s | ||
70 | error 56..61: The `super` keyword may only be preceded by other `super`s | ||
diff --git a/crates/ra_syntax/test_data/parser/err/0041_illegal_super_keyword_location.rs b/crates/ra_syntax/test_data/parser/err/0041_illegal_super_keyword_location.rs new file mode 100644 index 000000000..bd4d58042 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/err/0041_illegal_super_keyword_location.rs | |||
@@ -0,0 +1,4 @@ | |||
1 | use ::super; | ||
2 | use a::super; | ||
3 | use super::a::super; | ||
4 | use a::{super::b}; | ||
diff --git a/crates/ra_syntax/test_data/parser/err/0042_illegal_self_keyword_location.rast b/crates/ra_syntax/test_data/parser/err/0042_illegal_self_keyword_location.rast new file mode 100644 index 000000000..4f382b06c --- /dev/null +++ b/crates/ra_syntax/test_data/parser/err/0042_illegal_self_keyword_location.rast | |||
@@ -0,0 +1,27 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "use" | ||
4 | [email protected] " " | ||
5 | [email protected] | ||
6 | [email protected] | ||
7 | [email protected] | ||
8 | [email protected] "::" | ||
9 | [email protected] "self" | ||
10 | [email protected] ";" | ||
11 | [email protected] "\n" | ||
12 | [email protected] | ||
13 | [email protected] "use" | ||
14 | [email protected] " " | ||
15 | [email protected] | ||
16 | [email protected] | ||
17 | [email protected] | ||
18 | [email protected] | ||
19 | [email protected] | ||
20 | [email protected] "a" | ||
21 | [email protected] "::" | ||
22 | [email protected] | ||
23 | [email protected] "self" | ||
24 | [email protected] ";" | ||
25 | [email protected] "\n" | ||
26 | error 6..10: The `self` keyword is only allowed as the first segment of a path | ||
27 | error 19..23: The `self` keyword is only allowed as the first segment of a path | ||
diff --git a/crates/ra_syntax/test_data/parser/err/0042_illegal_self_keyword_location.rs b/crates/ra_syntax/test_data/parser/err/0042_illegal_self_keyword_location.rs new file mode 100644 index 000000000..b9e1d7d8b --- /dev/null +++ b/crates/ra_syntax/test_data/parser/err/0042_illegal_self_keyword_location.rs | |||
@@ -0,0 +1,2 @@ | |||
1 | use ::self; | ||
2 | use a::self; | ||
diff --git a/crates/ra_syntax/test_data/parser/ok/0013_use_path_self_super.rast b/crates/ra_syntax/test_data/parser/ok/0013_use_path_self_super.rast index a5a90df7b..05d9c05ad 100644 --- a/crates/ra_syntax/test_data/parser/ok/0013_use_path_self_super.rast +++ b/crates/ra_syntax/test_data/parser/ok/0013_use_path_self_super.rast | |||
@@ -1,4 +1,4 @@ | |||
1 | SOURCE_FILE@0..65 | 1 | SOURCE_FILE@0..38 |
2 | [email protected] | 2 | [email protected] |
3 | [email protected] "use" | 3 | [email protected] "use" |
4 | [email protected] " " | 4 | [email protected] " " |
@@ -31,27 +31,3 @@ [email protected] | |||
31 | [email protected] "bar" | 31 | [email protected] "bar" |
32 | [email protected] ";" | 32 | [email protected] ";" |
33 | [email protected] "\n" | 33 | [email protected] "\n" |
34 | [email protected] | ||
35 | [email protected] "use" | ||
36 | [email protected] " " | ||
37 | [email protected] | ||
38 | [email protected] | ||
39 | [email protected] | ||
40 | [email protected] | ||
41 | [email protected] | ||
42 | [email protected] | ||
43 | [email protected] "::" | ||
44 | [email protected] "self" | ||
45 | [email protected] "::" | ||
46 | [email protected] | ||
47 | [email protected] | ||
48 | [email protected] "a" | ||
49 | [email protected] "::" | ||
50 | [email protected] | ||
51 | [email protected] "super" | ||
52 | [email protected] "::" | ||
53 | [email protected] | ||
54 | [email protected] | ||
55 | [email protected] "bar" | ||
56 | [email protected] ";" | ||
57 | [email protected] "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/ok/0013_use_path_self_super.rs b/crates/ra_syntax/test_data/parser/ok/0013_use_path_self_super.rs index faf6a42c7..9d9eb9917 100644 --- a/crates/ra_syntax/test_data/parser/ok/0013_use_path_self_super.rs +++ b/crates/ra_syntax/test_data/parser/ok/0013_use_path_self_super.rs | |||
@@ -1,3 +1,2 @@ | |||
1 | use self::foo; | 1 | use self::foo; |
2 | use super::super::bar; | 2 | use super::super::bar; |
3 | use ::self::a::super::bar; | ||
diff --git a/crates/rust-analyzer/src/caps.rs b/crates/rust-analyzer/src/caps.rs index e22ab8402..c0d320926 100644 --- a/crates/rust-analyzer/src/caps.rs +++ b/crates/rust-analyzer/src/caps.rs | |||
@@ -3,13 +3,13 @@ | |||
3 | use crate::semantic_tokens; | 3 | use crate::semantic_tokens; |
4 | 4 | ||
5 | use lsp_types::{ | 5 | use lsp_types::{ |
6 | CallHierarchyServerCapability, CodeActionProviderCapability, CodeLensOptions, | 6 | CallHierarchyServerCapability, CodeActionOptions, CodeActionProviderCapability, |
7 | CompletionOptions, DocumentOnTypeFormattingOptions, FoldingRangeProviderCapability, | 7 | CodeLensOptions, CompletionOptions, DocumentOnTypeFormattingOptions, |
8 | ImplementationProviderCapability, RenameOptions, RenameProviderCapability, SaveOptions, | 8 | FoldingRangeProviderCapability, ImplementationProviderCapability, RenameOptions, |
9 | SelectionRangeProviderCapability, SemanticTokensDocumentProvider, SemanticTokensLegend, | 9 | RenameProviderCapability, SaveOptions, SelectionRangeProviderCapability, |
10 | SemanticTokensOptions, ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability, | 10 | SemanticTokensDocumentProvider, SemanticTokensLegend, SemanticTokensOptions, |
11 | TextDocumentSyncKind, TextDocumentSyncOptions, TypeDefinitionProviderCapability, | 11 | ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind, |
12 | WorkDoneProgressOptions, | 12 | TextDocumentSyncOptions, TypeDefinitionProviderCapability, WorkDoneProgressOptions, |
13 | }; | 13 | }; |
14 | 14 | ||
15 | pub fn server_capabilities() -> ServerCapabilities { | 15 | pub fn server_capabilities() -> ServerCapabilities { |
@@ -40,7 +40,20 @@ pub fn server_capabilities() -> ServerCapabilities { | |||
40 | document_highlight_provider: Some(true), | 40 | document_highlight_provider: Some(true), |
41 | document_symbol_provider: Some(true), | 41 | document_symbol_provider: Some(true), |
42 | workspace_symbol_provider: Some(true), | 42 | workspace_symbol_provider: Some(true), |
43 | code_action_provider: Some(CodeActionProviderCapability::Simple(true)), | 43 | code_action_provider: Some(CodeActionProviderCapability::Options(CodeActionOptions { |
44 | // Advertise support for all built-in CodeActionKinds | ||
45 | code_action_kinds: Some(vec![ | ||
46 | String::new(), | ||
47 | lsp_types::code_action_kind::QUICKFIX.to_string(), | ||
48 | lsp_types::code_action_kind::REFACTOR.to_string(), | ||
49 | lsp_types::code_action_kind::REFACTOR_EXTRACT.to_string(), | ||
50 | lsp_types::code_action_kind::REFACTOR_INLINE.to_string(), | ||
51 | lsp_types::code_action_kind::REFACTOR_REWRITE.to_string(), | ||
52 | lsp_types::code_action_kind::SOURCE.to_string(), | ||
53 | lsp_types::code_action_kind::SOURCE_ORGANIZE_IMPORTS.to_string(), | ||
54 | ]), | ||
55 | work_done_progress_options: Default::default(), | ||
56 | })), | ||
44 | code_lens_provider: Some(CodeLensOptions { resolve_provider: Some(true) }), | 57 | code_lens_provider: Some(CodeLensOptions { resolve_provider: Some(true) }), |
45 | document_formatting_provider: Some(true), | 58 | document_formatting_provider: Some(true), |
46 | document_range_formatting_provider: None, | 59 | document_range_formatting_provider: None, |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 74a63e32a..177da94cc 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -70,6 +70,7 @@ pub struct ClientCapsConfig { | |||
70 | pub location_link: bool, | 70 | pub location_link: bool, |
71 | pub line_folding_only: bool, | 71 | pub line_folding_only: bool, |
72 | pub hierarchical_symbols: bool, | 72 | pub hierarchical_symbols: bool, |
73 | pub code_action_literals: bool, | ||
73 | } | 74 | } |
74 | 75 | ||
75 | impl Default for Config { | 76 | impl Default for Config { |
@@ -221,6 +222,11 @@ impl Config { | |||
221 | { | 222 | { |
222 | self.client_caps.hierarchical_symbols = value | 223 | self.client_caps.hierarchical_symbols = value |
223 | } | 224 | } |
225 | if let Some(value) = | ||
226 | caps.code_action.as_ref().and_then(|it| Some(it.code_action_literal_support.is_some())) | ||
227 | { | ||
228 | self.client_caps.code_action_literals = value; | ||
229 | } | ||
224 | self.completion.allow_snippets(false); | 230 | self.completion.allow_snippets(false); |
225 | if let Some(completion) = &caps.completion { | 231 | if let Some(completion) = &caps.completion { |
226 | if let Some(completion_item) = &completion.completion_item { | 232 | if let Some(completion_item) = &completion.completion_item { |
diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index 8db2dfa0c..0f623949e 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs | |||
@@ -19,8 +19,7 @@ use lsp_types::{ | |||
19 | TextEdit, Url, WorkspaceEdit, | 19 | TextEdit, Url, WorkspaceEdit, |
20 | }; | 20 | }; |
21 | use ra_ide::{ | 21 | use ra_ide::{ |
22 | Assist, AssistId, FileId, FilePosition, FileRange, Query, RangeInfo, Runnable, RunnableKind, | 22 | Assist, FileId, FilePosition, FileRange, Query, RangeInfo, Runnable, RunnableKind, SearchScope, |
23 | SearchScope, | ||
24 | }; | 23 | }; |
25 | use ra_prof::profile; | 24 | use ra_prof::profile; |
26 | use ra_syntax::{AstNode, SyntaxKind, TextRange, TextSize}; | 25 | use ra_syntax::{AstNode, SyntaxKind, TextRange, TextSize}; |
@@ -702,15 +701,9 @@ fn create_single_code_action(assist: Assist, world: &WorldSnapshot) -> Result<Co | |||
702 | arguments: Some(vec![arg]), | 701 | arguments: Some(vec![arg]), |
703 | }; | 702 | }; |
704 | 703 | ||
705 | let kind = match assist.id { | ||
706 | AssistId("introduce_variable") => Some("refactor.extract.variable".to_string()), | ||
707 | AssistId("add_custom_impl") => Some("refactor.rewrite.add_custom_impl".to_string()), | ||
708 | _ => None, | ||
709 | }; | ||
710 | |||
711 | Ok(CodeAction { | 704 | Ok(CodeAction { |
712 | title, | 705 | title, |
713 | kind, | 706 | kind: Some(String::new()), |
714 | diagnostics: None, | 707 | diagnostics: None, |
715 | edit: None, | 708 | edit: None, |
716 | command: Some(command), | 709 | command: Some(command), |
@@ -812,6 +805,23 @@ pub fn handle_code_action( | |||
812 | } | 805 | } |
813 | } | 806 | } |
814 | 807 | ||
808 | // If the client only supports commands then filter the list | ||
809 | // and remove and actions that depend on edits. | ||
810 | if !world.config.client_caps.code_action_literals { | ||
811 | // FIXME: use drain_filter once it hits stable. | ||
812 | res = res | ||
813 | .into_iter() | ||
814 | .filter_map(|it| match it { | ||
815 | cmd @ lsp_types::CodeActionOrCommand::Command(_) => Some(cmd), | ||
816 | lsp_types::CodeActionOrCommand::CodeAction(action) => match action.command { | ||
817 | Some(cmd) if action.edit.is_none() => { | ||
818 | Some(lsp_types::CodeActionOrCommand::Command(cmd)) | ||
819 | } | ||
820 | _ => None, | ||
821 | }, | ||
822 | }) | ||
823 | .collect(); | ||
824 | } | ||
815 | Ok(Some(res)) | 825 | Ok(Some(res)) |
816 | } | 826 | } |
817 | 827 | ||
diff --git a/crates/rust-analyzer/tests/heavy_tests/support.rs b/crates/rust-analyzer/tests/heavy_tests/support.rs index e4fe3411a..8d47ee4f6 100644 --- a/crates/rust-analyzer/tests/heavy_tests/support.rs +++ b/crates/rust-analyzer/tests/heavy_tests/support.rs | |||
@@ -77,7 +77,11 @@ impl<'a> Project<'a> { | |||
77 | let roots = self.roots.into_iter().map(|root| tmp_dir.path().join(root)).collect(); | 77 | let roots = self.roots.into_iter().map(|root| tmp_dir.path().join(root)).collect(); |
78 | 78 | ||
79 | let mut config = Config { | 79 | let mut config = Config { |
80 | client_caps: ClientCapsConfig { location_link: true, ..Default::default() }, | 80 | client_caps: ClientCapsConfig { |
81 | location_link: true, | ||
82 | code_action_literals: true, | ||
83 | ..Default::default() | ||
84 | }, | ||
81 | with_sysroot: self.with_sysroot, | 85 | with_sysroot: self.with_sysroot, |
82 | ..Config::default() | 86 | ..Config::default() |
83 | }; | 87 | }; |
diff --git a/docs/dev/architecture.md b/docs/dev/architecture.md index 3a337c574..cee916c09 100644 --- a/docs/dev/architecture.md +++ b/docs/dev/architecture.md | |||
@@ -46,7 +46,7 @@ can be quickly updated for small modifications. | |||
46 | 46 | ||
47 | Some of the components of this repository are generated through automatic | 47 | Some of the components of this repository are generated through automatic |
48 | processes. `cargo xtask codegen` runs all generation tasks. Generated code is | 48 | processes. `cargo xtask codegen` runs all generation tasks. Generated code is |
49 | commited to the git repository. | 49 | committed to the git repository. |
50 | 50 | ||
51 | In particular, `cargo xtask codegen` generates: | 51 | In particular, `cargo xtask codegen` generates: |
52 | 52 | ||
@@ -114,7 +114,7 @@ is responsible for guessing a HIR for a particular source position. | |||
114 | Underneath, HIR works on top of salsa, using a `HirDatabase` trait. | 114 | Underneath, HIR works on top of salsa, using a `HirDatabase` trait. |
115 | 115 | ||
116 | `ra_hir_xxx` crates have a strong ECS flavor, in that they work with raw ids and | 116 | `ra_hir_xxx` crates have a strong ECS flavor, in that they work with raw ids and |
117 | directly query the databse. | 117 | directly query the database. |
118 | 118 | ||
119 | The top-level `ra_hir` façade crate wraps ids into a more OO-flavored API. | 119 | The top-level `ra_hir` façade crate wraps ids into a more OO-flavored API. |
120 | 120 | ||
diff --git a/docs/dev/guide.md b/docs/dev/guide.md index abbe4c154..c3252f1f6 100644 --- a/docs/dev/guide.md +++ b/docs/dev/guide.md | |||
@@ -26,7 +26,7 @@ properties hold: | |||
26 | 26 | ||
27 | ## IDE API | 27 | ## IDE API |
28 | 28 | ||
29 | To see the bigger picture of how the IDE features works, let's take a look at the [`AnalysisHost`] and | 29 | To see the bigger picture of how the IDE features work, let's take a look at the [`AnalysisHost`] and |
30 | [`Analysis`] pair of types. `AnalysisHost` has three methods: | 30 | [`Analysis`] pair of types. `AnalysisHost` has three methods: |
31 | 31 | ||
32 | * `default()` for creating an empty analysis instance | 32 | * `default()` for creating an empty analysis instance |
@@ -131,7 +131,7 @@ mapping between `SourceRoot` IDs (which are assigned by the client) and actual | |||
131 | analyzer. | 131 | analyzer. |
132 | 132 | ||
133 | Note that `mod`, `#[path]` and `include!()` can only reference files from the | 133 | Note that `mod`, `#[path]` and `include!()` can only reference files from the |
134 | same source root. It is of course is possible to explicitly add extra files to | 134 | same source root. It is of course possible to explicitly add extra files to |
135 | the source root, even `/dev/random`. | 135 | the source root, even `/dev/random`. |
136 | 136 | ||
137 | ## Language Server Protocol | 137 | ## Language Server Protocol |
@@ -192,7 +192,7 @@ task will be canceled as soon as the main loop calls `apply_change` on the | |||
192 | [`schedule`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop.rs#L426-L455 | 192 | [`schedule`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop.rs#L426-L455 |
193 | [The task]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop/handlers.rs#L205-L223 | 193 | [The task]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_lsp_server/src/main_loop/handlers.rs#L205-L223 |
194 | 194 | ||
195 | This concludes the overview of the analyzer's programing *interface*. Next, lets | 195 | This concludes the overview of the analyzer's programing *interface*. Next, let's |
196 | dig into the implementation! | 196 | dig into the implementation! |
197 | 197 | ||
198 | ## Salsa | 198 | ## Salsa |
@@ -480,7 +480,7 @@ throughout the analyzer: | |||
480 | ## Source Map pattern | 480 | ## Source Map pattern |
481 | 481 | ||
482 | Due to an obscure edge case in completion, IDE needs to know the syntax node of | 482 | Due to an obscure edge case in completion, IDE needs to know the syntax node of |
483 | an use statement which imported the given completion candidate. We can't just | 483 | a use statement which imported the given completion candidate. We can't just |
484 | store the syntax node as a part of name resolution: this will break | 484 | store the syntax node as a part of name resolution: this will break |
485 | incrementality, due to the fact that syntax changes after every file | 485 | incrementality, due to the fact that syntax changes after every file |
486 | modification. | 486 | modification. |
diff --git a/docs/user/readme.adoc b/docs/user/readme.adoc index 4cb1e23e8..b1af72ce6 100644 --- a/docs/user/readme.adoc +++ b/docs/user/readme.adoc | |||
@@ -201,7 +201,7 @@ let g:LanguageClient_serverCommands = { | |||
201 | 201 | ||
202 | 2. Configure by adding this to your vim/neovim config file (replacing the existing Rust-specific line if it exists): | 202 | 2. Configure by adding this to your vim/neovim config file (replacing the existing Rust-specific line if it exists): |
203 | + | 203 | + |
204 | [source,vim] | 204 | [source,vim] |
205 | ---- | 205 | ---- |
206 | let g:ycm_language_server = | 206 | let g:ycm_language_server = |
207 | \ [ | 207 | \ [ |
@@ -252,6 +252,15 @@ If it worked, you should see "rust-analyzer, Line X, Column Y" on the left side | |||
252 | 252 | ||
253 | If you get an error saying `No such file or directory: 'rust-analyzer'`, see the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>> section on installing the language server binary. | 253 | If you get an error saying `No such file or directory: 'rust-analyzer'`, see the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>> section on installing the language server binary. |
254 | 254 | ||
255 | === Gnome Builder | ||
256 | |||
257 | Prerequisites: You have installed the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>>. | ||
258 | |||
259 | Gnome Builder currently has support for RLS, and there's no way to configure the language server executable. A future version might support `rust-analyzer` out of the box. | ||
260 | |||
261 | 1. Rename, symlink or copy the `rust-analyzer` binary to `rls` and place it somewhere Builder can find (in `PATH`, or under `~/.cargo/bin`). | ||
262 | 2. Enable the Rust Builder plugin. | ||
263 | |||
255 | == Usage | 264 | == Usage |
256 | 265 | ||
257 | See https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/user/features.md[features.md]. | 266 | See https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/user/features.md[features.md]. |
diff --git a/xtask/src/ast_src.rs b/xtask/src/ast_src.rs index bdd42cb76..703fb9be9 100644 --- a/xtask/src/ast_src.rs +++ b/xtask/src/ast_src.rs | |||
@@ -593,7 +593,7 @@ pub(crate) const AST_SRC: AstSrc = AstSrc { | |||
593 | qualifier: Path, | 593 | qualifier: Path, |
594 | } | 594 | } |
595 | struct PathSegment { | 595 | struct PathSegment { |
596 | T![::], T![crate], T![<], NameRef, TypeArgList, ParamList, RetType, PathType, T![>] | 596 | T![::], T![crate], T![self], T![super], T![<], NameRef, TypeArgList, ParamList, RetType, PathType, T![>] |
597 | } | 597 | } |
598 | struct TypeArgList { | 598 | struct TypeArgList { |
599 | T![::], | 599 | T![::], |