aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir/src/generics.rs20
-rw-r--r--crates/ra_hir/src/ty.rs133
-rw-r--r--crates/ra_hir/src/ty/lower.rs65
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs16
-rw-r--r--crates/ra_hir/src/ty/tests.rs175
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs4
-rw-r--r--crates/ra_hir/src/type_ref.rs49
-rw-r--r--crates/ra_parser/src/grammar/expressions/atom.rs2
-rw-r--r--crates/ra_parser/src/grammar/patterns.rs2
-rw-r--r--crates/ra_project_model/src/sysroot.rs32
-rw-r--r--crates/ra_syntax/src/ast.rs2
-rw-r--r--crates/ra_syntax/src/ast/extensions.rs29
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0066_match_arm.rs2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0066_match_arm.txt59
-rw-r--r--docs/user/README.md1
15 files changed, 523 insertions, 68 deletions
diff --git a/crates/ra_hir/src/generics.rs b/crates/ra_hir/src/generics.rs
index e75337cdf..d6728cc9f 100644
--- a/crates/ra_hir/src/generics.rs
+++ b/crates/ra_hir/src/generics.rs
@@ -11,7 +11,7 @@ use crate::{
11 db::{AstDatabase, DefDatabase, HirDatabase}, 11 db::{AstDatabase, DefDatabase, HirDatabase},
12 name::SELF_TYPE, 12 name::SELF_TYPE,
13 path::Path, 13 path::Path,
14 type_ref::TypeRef, 14 type_ref::{TypeBound, TypeRef},
15 AdtDef, AsName, Container, Enum, EnumVariant, Function, HasSource, ImplBlock, Name, Struct, 15 AdtDef, AsName, Container, Enum, EnumVariant, Function, HasSource, ImplBlock, Name, Struct,
16 Trait, TypeAlias, Union, 16 Trait, TypeAlias, Union,
17}; 17};
@@ -35,10 +35,12 @@ pub struct GenericParams {
35 35
36/// A single predicate from a where clause, i.e. `where Type: Trait`. Combined 36/// A single predicate from a where clause, i.e. `where Type: Trait`. Combined
37/// where clauses like `where T: Foo + Bar` are turned into multiple of these. 37/// where clauses like `where T: Foo + Bar` are turned into multiple of these.
38/// It might still result in multiple actual predicates though, because of
39/// associated type bindings like `Iterator<Item = u32>`.
38#[derive(Clone, PartialEq, Eq, Debug)] 40#[derive(Clone, PartialEq, Eq, Debug)]
39pub struct WherePredicate { 41pub struct WherePredicate {
40 pub(crate) type_ref: TypeRef, 42 pub(crate) type_ref: TypeRef,
41 pub(crate) trait_ref: Path, 43 pub(crate) bound: TypeBound,
42} 44}
43 45
44// FIXME: consts can have type parameters from their parents (i.e. associated consts of traits) 46// FIXME: consts can have type parameters from their parents (i.e. associated consts of traits)
@@ -143,18 +145,8 @@ impl GenericParams {
143 // FIXME: remove this bound 145 // FIXME: remove this bound
144 return; 146 return;
145 } 147 }
146 let path = bound 148 let bound = TypeBound::from_ast(bound);
147 .type_ref() 149 self.where_predicates.push(WherePredicate { type_ref, bound });
148 .and_then(|tr| match tr {
149 ast::TypeRef::PathType(path) => path.path(),
150 _ => None,
151 })
152 .and_then(Path::from_ast);
153 let path = match path {
154 Some(p) => p,
155 None => return,
156 };
157 self.where_predicates.push(WherePredicate { type_ref, trait_ref: path });
158 } 150 }
159 151
160 pub(crate) fn find_by_name(&self, name: &Name) -> Option<&GenericParam> { 152 pub(crate) fn find_by_name(&self, name: &Name) -> Option<&GenericParam> {
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index 642dd02cb..b54c80318 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -161,14 +161,28 @@ pub enum Ty {
161 name: Name, 161 name: Name,
162 }, 162 },
163 163
164 /// A bound type variable. Only used during trait resolution to represent 164 /// A bound type variable. Used during trait resolution to represent Chalk
165 /// Chalk variables. 165 /// variables, and in `Dyn` and `Opaque` bounds to represent the `Self` type.
166 Bound(u32), 166 Bound(u32),
167 167
168 /// A type variable used during type checking. Not to be confused with a 168 /// A type variable used during type checking. Not to be confused with a
169 /// type parameter. 169 /// type parameter.
170 Infer(InferTy), 170 Infer(InferTy),
171 171
172 /// A trait object (`dyn Trait` or bare `Trait` in pre-2018 Rust).
173 ///
174 /// The predicates are quantified over the `Self` type, i.e. `Ty::Bound(0)`
175 /// represents the `Self` type inside the bounds. This is currently
176 /// implicit; Chalk has the `Binders` struct to make it explicit, but it
177 /// didn't seem worth the overhead yet.
178 Dyn(Arc<[GenericPredicate]>),
179
180 /// An opaque type (`impl Trait`).
181 ///
182 /// The predicates are quantified over the `Self` type; see `Ty::Dyn` for
183 /// more.
184 Opaque(Arc<[GenericPredicate]>),
185
172 /// A placeholder for a type which could not be computed; this is propagated 186 /// A placeholder for a type which could not be computed; this is propagated
173 /// to avoid useless error messages. Doubles as a placeholder where type 187 /// to avoid useless error messages. Doubles as a placeholder where type
174 /// variables are inserted before type checking, since we want to try to 188 /// variables are inserted before type checking, since we want to try to
@@ -194,6 +208,12 @@ impl Substs {
194 Substs(self.0.iter().cloned().take(n).collect::<Vec<_>>().into()) 208 Substs(self.0.iter().cloned().take(n).collect::<Vec<_>>().into())
195 } 209 }
196 210
211 pub fn walk(&self, f: &mut impl FnMut(&Ty)) {
212 for t in self.0.iter() {
213 t.walk(f);
214 }
215 }
216
197 pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { 217 pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
198 // Without an Arc::make_mut_slice, we can't avoid the clone here: 218 // Without an Arc::make_mut_slice, we can't avoid the clone here:
199 let mut v: Vec<_> = self.0.iter().cloned().collect(); 219 let mut v: Vec<_> = self.0.iter().cloned().collect();
@@ -270,6 +290,14 @@ impl TraitRef {
270 }); 290 });
271 self 291 self
272 } 292 }
293
294 pub fn walk(&self, f: &mut impl FnMut(&Ty)) {
295 self.substs.walk(f);
296 }
297
298 pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
299 self.substs.walk_mut(f);
300 }
273} 301}
274 302
275/// Like `generics::WherePredicate`, but with resolved types: A condition on the 303/// Like `generics::WherePredicate`, but with resolved types: A condition on the
@@ -299,6 +327,20 @@ impl GenericPredicate {
299 GenericPredicate::Error => self, 327 GenericPredicate::Error => self,
300 } 328 }
301 } 329 }
330
331 pub fn walk(&self, f: &mut impl FnMut(&Ty)) {
332 match self {
333 GenericPredicate::Implemented(trait_ref) => trait_ref.walk(f),
334 GenericPredicate::Error => {}
335 }
336 }
337
338 pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
339 match self {
340 GenericPredicate::Implemented(trait_ref) => trait_ref.walk_mut(f),
341 GenericPredicate::Error => {}
342 }
343 }
302} 344}
303 345
304/// Basically a claim (currently not validated / checked) that the contained 346/// Basically a claim (currently not validated / checked) that the contained
@@ -386,6 +428,11 @@ impl Ty {
386 t.walk(f); 428 t.walk(f);
387 } 429 }
388 } 430 }
431 Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
432 for p in predicates.iter() {
433 p.walk(f);
434 }
435 }
389 Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} 436 Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
390 } 437 }
391 f(self); 438 f(self);
@@ -402,6 +449,13 @@ impl Ty {
402 Ty::UnselectedProjection(p_ty) => { 449 Ty::UnselectedProjection(p_ty) => {
403 p_ty.parameters.walk_mut(f); 450 p_ty.parameters.walk_mut(f);
404 } 451 }
452 Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
453 let mut v: Vec<_> = predicates.iter().cloned().collect();
454 for p in &mut v {
455 p.walk_mut(f);
456 }
457 *predicates = v.into();
458 }
405 Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} 459 Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
406 } 460 }
407 f(self); 461 f(self);
@@ -529,6 +583,19 @@ impl Ty {
529 ty => ty, 583 ty => ty,
530 }) 584 })
531 } 585 }
586
587 /// If this is an `impl Trait` or `dyn Trait`, returns that trait.
588 pub fn inherent_trait(&self) -> Option<Trait> {
589 match self {
590 Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
591 predicates.iter().find_map(|pred| match pred {
592 GenericPredicate::Implemented(tr) => Some(tr.trait_),
593 _ => None,
594 })
595 }
596 _ => None,
597 }
598 }
532} 599}
533 600
534impl HirDisplay for &Ty { 601impl HirDisplay for &Ty {
@@ -669,6 +736,28 @@ impl HirDisplay for Ty {
669 Ty::UnselectedProjection(p_ty) => p_ty.hir_fmt(f)?, 736 Ty::UnselectedProjection(p_ty) => p_ty.hir_fmt(f)?,
670 Ty::Param { name, .. } => write!(f, "{}", name)?, 737 Ty::Param { name, .. } => write!(f, "{}", name)?,
671 Ty::Bound(idx) => write!(f, "?{}", idx)?, 738 Ty::Bound(idx) => write!(f, "?{}", idx)?,
739 Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
740 match self {
741 Ty::Dyn(_) => write!(f, "dyn ")?,
742 Ty::Opaque(_) => write!(f, "impl ")?,
743 _ => unreachable!(),
744 };
745 // looping by hand here just to format the bounds in a slightly nicer way
746 let mut first = true;
747 for p in predicates.iter() {
748 if !first {
749 write!(f, " + ")?;
750 }
751 first = false;
752 match p {
753 // don't show the $0 self type
754 GenericPredicate::Implemented(trait_ref) => {
755 trait_ref.hir_fmt_ext(f, false)?
756 }
757 GenericPredicate::Error => p.hir_fmt(f)?,
758 }
759 }
760 }
672 Ty::Unknown => write!(f, "{{unknown}}")?, 761 Ty::Unknown => write!(f, "{{unknown}}")?,
673 Ty::Infer(..) => write!(f, "_")?, 762 Ty::Infer(..) => write!(f, "_")?,
674 } 763 }
@@ -676,14 +765,16 @@ impl HirDisplay for Ty {
676 } 765 }
677} 766}
678 767
679impl HirDisplay for TraitRef { 768impl TraitRef {
680 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { 769 fn hir_fmt_ext(
681 write!( 770 &self,
682 f, 771 f: &mut HirFormatter<impl HirDatabase>,
683 "{}: {}", 772 with_self_ty: bool,
684 self.substs[0].display(f.db), 773 ) -> fmt::Result {
685 self.trait_.name(f.db).unwrap_or_else(Name::missing) 774 if with_self_ty {
686 )?; 775 write!(f, "{}: ", self.substs[0].display(f.db),)?;
776 }
777 write!(f, "{}", self.trait_.name(f.db).unwrap_or_else(Name::missing))?;
687 if self.substs.len() > 1 { 778 if self.substs.len() > 1 {
688 write!(f, "<")?; 779 write!(f, "<")?;
689 f.write_joined(&self.substs[1..], ", ")?; 780 f.write_joined(&self.substs[1..], ", ")?;
@@ -693,6 +784,28 @@ impl HirDisplay for TraitRef {
693 } 784 }
694} 785}
695 786
787impl HirDisplay for TraitRef {
788 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
789 self.hir_fmt_ext(f, true)
790 }
791}
792
793impl HirDisplay for &GenericPredicate {
794 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
795 HirDisplay::hir_fmt(*self, f)
796 }
797}
798
799impl HirDisplay for GenericPredicate {
800 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
801 match self {
802 GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?,
803 GenericPredicate::Error => write!(f, "{{error}}")?,
804 }
805 Ok(())
806 }
807}
808
696impl HirDisplay for Obligation { 809impl HirDisplay for Obligation {
697 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { 810 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
698 match self { 811 match self {
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs
index debedcbb8..47d161277 100644
--- a/crates/ra_hir/src/ty/lower.rs
+++ b/crates/ra_hir/src/ty/lower.rs
@@ -17,7 +17,7 @@ use crate::{
17 path::{GenericArg, PathSegment}, 17 path::{GenericArg, PathSegment},
18 resolve::{Resolution, Resolver}, 18 resolve::{Resolution, Resolver},
19 ty::AdtDef, 19 ty::AdtDef,
20 type_ref::TypeRef, 20 type_ref::{TypeBound, TypeRef},
21 BuiltinType, Const, Enum, EnumVariant, Function, HirDatabase, ModuleDef, Path, Static, Struct, 21 BuiltinType, Const, Enum, EnumVariant, Function, HirDatabase, ModuleDef, Path, Static, Struct,
22 StructField, Trait, TypeAlias, Union, 22 StructField, Trait, TypeAlias, Union,
23}; 23};
@@ -58,6 +58,22 @@ impl Ty {
58 let sig = Substs(inner_tys.into()); 58 let sig = Substs(inner_tys.into());
59 Ty::apply(TypeCtor::FnPtr { num_args: sig.len() as u16 - 1 }, sig) 59 Ty::apply(TypeCtor::FnPtr { num_args: sig.len() as u16 - 1 }, sig)
60 } 60 }
61 TypeRef::DynTrait(bounds) => {
62 let self_ty = Ty::Bound(0);
63 let predicates = bounds
64 .iter()
65 .map(|b| GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone()))
66 .collect::<Vec<_>>();
67 Ty::Dyn(predicates.into())
68 }
69 TypeRef::ImplTrait(bounds) => {
70 let self_ty = Ty::Bound(0);
71 let predicates = bounds
72 .iter()
73 .map(|b| GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone()))
74 .collect::<Vec<_>>();
75 Ty::Opaque(predicates.into())
76 }
61 TypeRef::Error => Ty::Unknown, 77 TypeRef::Error => Ty::Unknown,
62 } 78 }
63 } 79 }
@@ -310,13 +326,46 @@ impl TraitRef {
310 TraitRef { trait_, substs } 326 TraitRef { trait_, substs }
311 } 327 }
312 328
313 pub(crate) fn for_where_predicate( 329 pub(crate) fn from_where_predicate(
314 db: &impl HirDatabase, 330 db: &impl HirDatabase,
315 resolver: &Resolver, 331 resolver: &Resolver,
316 pred: &WherePredicate, 332 pred: &WherePredicate,
317 ) -> Option<TraitRef> { 333 ) -> Option<TraitRef> {
318 let self_ty = Ty::from_hir(db, resolver, &pred.type_ref); 334 let self_ty = Ty::from_hir(db, resolver, &pred.type_ref);
319 TraitRef::from_path(db, resolver, &pred.trait_ref, Some(self_ty)) 335 TraitRef::from_type_bound(db, resolver, &pred.bound, self_ty)
336 }
337
338 pub(crate) fn from_type_bound(
339 db: &impl HirDatabase,
340 resolver: &Resolver,
341 bound: &TypeBound,
342 self_ty: Ty,
343 ) -> Option<TraitRef> {
344 match bound {
345 TypeBound::Path(path) => TraitRef::from_path(db, resolver, path, Some(self_ty)),
346 TypeBound::Error => None,
347 }
348 }
349}
350
351impl GenericPredicate {
352 pub(crate) fn from_where_predicate(
353 db: &impl HirDatabase,
354 resolver: &Resolver,
355 where_predicate: &WherePredicate,
356 ) -> GenericPredicate {
357 TraitRef::from_where_predicate(db, &resolver, where_predicate)
358 .map_or(GenericPredicate::Error, GenericPredicate::Implemented)
359 }
360
361 pub(crate) fn from_type_bound(
362 db: &impl HirDatabase,
363 resolver: &Resolver,
364 bound: &TypeBound,
365 self_ty: Ty,
366 ) -> GenericPredicate {
367 TraitRef::from_type_bound(db, &resolver, bound, self_ty)
368 .map_or(GenericPredicate::Error, GenericPredicate::Implemented)
320 } 369 }
321} 370}
322 371
@@ -376,10 +425,7 @@ pub(crate) fn trait_env(
376) -> Arc<super::TraitEnvironment> { 425) -> Arc<super::TraitEnvironment> {
377 let predicates = resolver 426 let predicates = resolver
378 .where_predicates_in_scope() 427 .where_predicates_in_scope()
379 .map(|pred| { 428 .map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred))
380 TraitRef::for_where_predicate(db, &resolver, pred)
381 .map_or(GenericPredicate::Error, GenericPredicate::Implemented)
382 })
383 .collect::<Vec<_>>(); 429 .collect::<Vec<_>>();
384 430
385 Arc::new(super::TraitEnvironment { predicates }) 431 Arc::new(super::TraitEnvironment { predicates })
@@ -393,10 +439,7 @@ pub(crate) fn generic_predicates_query(
393 let resolver = def.resolver(db); 439 let resolver = def.resolver(db);
394 let predicates = resolver 440 let predicates = resolver
395 .where_predicates_in_scope() 441 .where_predicates_in_scope()
396 .map(|pred| { 442 .map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred))
397 TraitRef::for_where_predicate(db, &resolver, pred)
398 .map_or(GenericPredicate::Error, GenericPredicate::Implemented)
399 })
400 .collect::<Vec<_>>(); 443 .collect::<Vec<_>>();
401 predicates.into() 444 predicates.into()
402} 445}
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index 3f4c43aee..9873a0440 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -211,12 +211,19 @@ fn iterate_trait_method_candidates<T>(
211 let krate = resolver.krate()?; 211 let krate = resolver.krate()?;
212 // FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that) 212 // FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that)
213 let env = lower::trait_env(db, resolver); 213 let env = lower::trait_env(db, resolver);
214 'traits: for t in resolver.traits_in_scope(db) { 214 // if ty is `impl Trait` or `dyn Trait`, the trait doesn't need to be in scope
215 let traits = ty.value.inherent_trait().into_iter().chain(resolver.traits_in_scope(db));
216 'traits: for t in traits {
215 let data = t.trait_data(db); 217 let data = t.trait_data(db);
218
219 // FIXME this is a bit of a hack, since Chalk should say the same thing
220 // anyway, but currently Chalk doesn't implement `dyn/impl Trait` yet
221 let inherently_implemented = ty.value.inherent_trait() == Some(t);
222
216 // we'll be lazy about checking whether the type implements the 223 // we'll be lazy about checking whether the type implements the
217 // trait, but if we find out it doesn't, we'll skip the rest of the 224 // trait, but if we find out it doesn't, we'll skip the rest of the
218 // iteration 225 // iteration
219 let mut known_implemented = false; 226 let mut known_implemented = inherently_implemented;
220 for item in data.items() { 227 for item in data.items() {
221 if let TraitItem::Function(m) = *item { 228 if let TraitItem::Function(m) = *item {
222 let data = m.data(db); 229 let data = m.data(db);
@@ -271,6 +278,11 @@ pub(crate) fn implements_trait(
271 krate: Crate, 278 krate: Crate,
272 trait_: Trait, 279 trait_: Trait,
273) -> bool { 280) -> bool {
281 if ty.value.inherent_trait() == Some(trait_) {
282 // FIXME this is a bit of a hack, since Chalk should say the same thing
283 // anyway, but currently Chalk doesn't implement `dyn/impl Trait` yet
284 return true;
285 }
274 let env = lower::trait_env(db, resolver); 286 let env = lower::trait_env(db, resolver);
275 let goal = generic_implements_goal(db, env.clone(), trait_, ty.clone()); 287 let goal = generic_implements_goal(db, env.clone(), trait_, ty.clone());
276 let solution = db.trait_solve(krate, goal); 288 let solution = db.trait_solve(krate, goal);
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 57fd5492d..c5818b738 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -3273,6 +3273,181 @@ fn test<T: ApplyL>(t: T) {
3273 assert_eq!(t, "{unknown}"); 3273 assert_eq!(t, "{unknown}");
3274} 3274}
3275 3275
3276#[test]
3277fn impl_trait() {
3278 assert_snapshot_matches!(
3279 infer(r#"
3280trait Trait<T> {
3281 fn foo(&self) -> T;
3282 fn foo2(&self) -> i64;
3283}
3284fn bar() -> impl Trait<u64> {}
3285
3286fn test(x: impl Trait<u64>, y: &impl Trait<u64>) {
3287 x;
3288 y;
3289 let z = bar();
3290 x.foo();
3291 y.foo();
3292 z.foo();
3293 x.foo2();
3294 y.foo2();
3295 z.foo2();
3296}
3297"#),
3298 @r###"
3299 â‹®
3300 â‹®[30; 34) 'self': &Self
3301 â‹®[55; 59) 'self': &Self
3302 â‹®[99; 101) '{}': ()
3303 â‹®[111; 112) 'x': impl Trait<u64>
3304 â‹®[131; 132) 'y': &impl Trait<u64>
3305 â‹®[152; 269) '{ ...2(); }': ()
3306 â‹®[158; 159) 'x': impl Trait<u64>
3307 â‹®[165; 166) 'y': &impl Trait<u64>
3308 â‹®[176; 177) 'z': impl Trait<u64>
3309 â‹®[180; 183) 'bar': fn bar() -> impl Trait<u64>
3310 â‹®[180; 185) 'bar()': impl Trait<u64>
3311 â‹®[191; 192) 'x': impl Trait<u64>
3312 â‹®[191; 198) 'x.foo()': {unknown}
3313 â‹®[204; 205) 'y': &impl Trait<u64>
3314 â‹®[204; 211) 'y.foo()': {unknown}
3315 â‹®[217; 218) 'z': impl Trait<u64>
3316 â‹®[217; 224) 'z.foo()': {unknown}
3317 â‹®[230; 231) 'x': impl Trait<u64>
3318 â‹®[230; 238) 'x.foo2()': i64
3319 â‹®[244; 245) 'y': &impl Trait<u64>
3320 â‹®[244; 252) 'y.foo2()': i64
3321 â‹®[258; 259) 'z': impl Trait<u64>
3322 â‹®[258; 266) 'z.foo2()': i64
3323 "###
3324 );
3325}
3326
3327#[test]
3328fn dyn_trait() {
3329 assert_snapshot_matches!(
3330 infer(r#"
3331trait Trait<T> {
3332 fn foo(&self) -> T;
3333 fn foo2(&self) -> i64;
3334}
3335fn bar() -> dyn Trait<u64> {}
3336
3337fn test(x: dyn Trait<u64>, y: &dyn Trait<u64>) {
3338 x;
3339 y;
3340 let z = bar();
3341 x.foo();
3342 y.foo();
3343 z.foo();
3344 x.foo2();
3345 y.foo2();
3346 z.foo2();
3347}
3348"#),
3349 @r###"
3350 â‹®
3351 â‹®[30; 34) 'self': &Self
3352 â‹®[55; 59) 'self': &Self
3353 â‹®[98; 100) '{}': ()
3354 â‹®[110; 111) 'x': dyn Trait<u64>
3355 â‹®[129; 130) 'y': &dyn Trait<u64>
3356 â‹®[149; 266) '{ ...2(); }': ()
3357 â‹®[155; 156) 'x': dyn Trait<u64>
3358 â‹®[162; 163) 'y': &dyn Trait<u64>
3359 â‹®[173; 174) 'z': dyn Trait<u64>
3360 â‹®[177; 180) 'bar': fn bar() -> dyn Trait<u64>
3361 â‹®[177; 182) 'bar()': dyn Trait<u64>
3362 â‹®[188; 189) 'x': dyn Trait<u64>
3363 â‹®[188; 195) 'x.foo()': {unknown}
3364 â‹®[201; 202) 'y': &dyn Trait<u64>
3365 â‹®[201; 208) 'y.foo()': {unknown}
3366 â‹®[214; 215) 'z': dyn Trait<u64>
3367 â‹®[214; 221) 'z.foo()': {unknown}
3368 â‹®[227; 228) 'x': dyn Trait<u64>
3369 â‹®[227; 235) 'x.foo2()': i64
3370 â‹®[241; 242) 'y': &dyn Trait<u64>
3371 â‹®[241; 249) 'y.foo2()': i64
3372 â‹®[255; 256) 'z': dyn Trait<u64>
3373 â‹®[255; 263) 'z.foo2()': i64
3374 "###
3375 );
3376}
3377
3378#[test]
3379fn dyn_trait_bare() {
3380 assert_snapshot_matches!(
3381 infer(r#"
3382trait Trait {
3383 fn foo(&self) -> u64;
3384}
3385fn bar() -> Trait {}
3386
3387fn test(x: Trait, y: &Trait) -> u64 {
3388 x;
3389 y;
3390 let z = bar();
3391 x.foo();
3392 y.foo();
3393 z.foo();
3394}
3395"#),
3396 @r###"
3397 â‹®
3398 â‹®[27; 31) 'self': &Self
3399 â‹®[61; 63) '{}': ()
3400 â‹®[73; 74) 'x': {unknown}
3401 â‹®[83; 84) 'y': &{unknown}
3402 â‹®[101; 176) '{ ...o(); }': ()
3403 â‹®[107; 108) 'x': {unknown}
3404 â‹®[114; 115) 'y': &{unknown}
3405 â‹®[125; 126) 'z': {unknown}
3406 â‹®[129; 132) 'bar': fn bar() -> {unknown}
3407 â‹®[129; 134) 'bar()': {unknown}
3408 â‹®[140; 141) 'x': {unknown}
3409 â‹®[140; 147) 'x.foo()': {unknown}
3410 â‹®[153; 154) 'y': &{unknown}
3411 â‹®[153; 160) 'y.foo()': {unknown}
3412 â‹®[166; 167) 'z': {unknown}
3413 â‹®[166; 173) 'z.foo()': {unknown}
3414 "###
3415 );
3416}
3417
3418#[test]
3419fn weird_bounds() {
3420 assert_snapshot_matches!(
3421 infer(r#"
3422trait Trait {}
3423fn test() {
3424 let a: impl Trait + 'lifetime = foo;
3425 let b: impl 'lifetime = foo;
3426 let b: impl (Trait) = foo;
3427 let b: impl ('lifetime) = foo;
3428 let d: impl ?Sized = foo;
3429 let e: impl Trait + ?Sized = foo;
3430}
3431"#),
3432 @r###"
3433 â‹®
3434 â‹®[26; 237) '{ ...foo; }': ()
3435 â‹®[36; 37) 'a': impl Trait + {error}
3436 â‹®[64; 67) 'foo': impl Trait + {error}
3437 â‹®[77; 78) 'b': impl {error}
3438 â‹®[97; 100) 'foo': impl {error}
3439 â‹®[110; 111) 'b': impl Trait
3440 â‹®[128; 131) 'foo': impl Trait
3441 â‹®[141; 142) 'b': impl {error}
3442 â‹®[163; 166) 'foo': impl {error}
3443 â‹®[176; 177) 'd': impl {error}
3444 â‹®[193; 196) 'foo': impl {error}
3445 â‹®[206; 207) 'e': impl Trait + {error}
3446 â‹®[231; 234) 'foo': impl Trait + {error}
3447 "###
3448 );
3449}
3450
3276fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { 3451fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String {
3277 let file = db.parse(pos.file_id).ok().unwrap(); 3452 let file = db.parse(pos.file_id).ok().unwrap();
3278 let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); 3453 let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap();
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs
index 6df7094c5..2ebc06135 100644
--- a/crates/ra_hir/src/ty/traits/chalk.rs
+++ b/crates/ra_hir/src/ty/traits/chalk.rs
@@ -80,7 +80,9 @@ impl ToChalk for Ty {
80 // FIXME this is clearly incorrect, but probably not too incorrect 80 // FIXME this is clearly incorrect, but probably not too incorrect
81 // and I'm not sure what to actually do with Ty::Unknown 81 // and I'm not sure what to actually do with Ty::Unknown
82 // maybe an alternative would be `for<T> T`? (meaningless in rust, but expressible in chalk's Ty) 82 // maybe an alternative would be `for<T> T`? (meaningless in rust, but expressible in chalk's Ty)
83 Ty::Unknown => { 83 //
84 // FIXME also dyn and impl Trait are currently handled like Unknown because Chalk doesn't have them yet
85 Ty::Unknown | Ty::Dyn(_) | Ty::Opaque(_) => {
84 PlaceholderIndex { ui: UniverseIndex::ROOT, idx: usize::max_value() }.to_ty() 86 PlaceholderIndex { ui: UniverseIndex::ROOT, idx: usize::max_value() }.to_ty()
85 } 87 }
86 } 88 }
diff --git a/crates/ra_hir/src/type_ref.rs b/crates/ra_hir/src/type_ref.rs
index b92a0b55a..fa91bfb22 100644
--- a/crates/ra_hir/src/type_ref.rs
+++ b/crates/ra_hir/src/type_ref.rs
@@ -1,7 +1,7 @@
1//! HIR for references to types. Paths in these are not yet resolved. They can 1//! HIR for references to types. Paths in these are not yet resolved. They can
2//! be directly created from an ast::TypeRef, without further queries. 2//! be directly created from an ast::TypeRef, without further queries.
3 3
4use ra_syntax::ast::{self, TypeAscriptionOwner}; 4use ra_syntax::ast::{self, TypeAscriptionOwner, TypeBoundsOwner};
5 5
6use crate::Path; 6use crate::Path;
7 7
@@ -49,8 +49,16 @@ pub enum TypeRef {
49 /// A fn pointer. Last element of the vector is the return type. 49 /// A fn pointer. Last element of the vector is the return type.
50 Fn(Vec<TypeRef>), 50 Fn(Vec<TypeRef>),
51 // For 51 // For
52 // ImplTrait, 52 ImplTrait(Vec<TypeBound>),
53 // DynTrait, 53 DynTrait(Vec<TypeBound>),
54 Error,
55}
56
57#[derive(Clone, PartialEq, Eq, Hash, Debug)]
58pub enum TypeBound {
59 Path(Path),
60 // also for<> bounds
61 // also Lifetimes
54 Error, 62 Error,
55} 63}
56 64
@@ -95,8 +103,12 @@ impl TypeRef {
95 } 103 }
96 // for types are close enough for our purposes to the inner type for now... 104 // for types are close enough for our purposes to the inner type for now...
97 ast::TypeRef::ForType(inner) => TypeRef::from_ast_opt(inner.type_ref()), 105 ast::TypeRef::ForType(inner) => TypeRef::from_ast_opt(inner.type_ref()),
98 ast::TypeRef::ImplTraitType(_inner) => TypeRef::Error, 106 ast::TypeRef::ImplTraitType(inner) => {
99 ast::TypeRef::DynTraitType(_inner) => TypeRef::Error, 107 TypeRef::ImplTrait(type_bounds_from_ast(inner.type_bound_list()))
108 }
109 ast::TypeRef::DynTraitType(inner) => {
110 TypeRef::DynTrait(type_bounds_from_ast(inner.type_bound_list()))
111 }
100 } 112 }
101 } 113 }
102 114
@@ -112,3 +124,30 @@ impl TypeRef {
112 TypeRef::Tuple(Vec::new()) 124 TypeRef::Tuple(Vec::new())
113 } 125 }
114} 126}
127
128pub(crate) fn type_bounds_from_ast(type_bounds_opt: Option<ast::TypeBoundList>) -> Vec<TypeBound> {
129 if let Some(type_bounds) = type_bounds_opt {
130 type_bounds.bounds().map(TypeBound::from_ast).collect()
131 } else {
132 vec![]
133 }
134}
135
136impl TypeBound {
137 pub(crate) fn from_ast(node: ast::TypeBound) -> Self {
138 match node.kind() {
139 ast::TypeBoundKind::PathType(path_type) => {
140 let path = match path_type.path() {
141 Some(p) => p,
142 None => return TypeBound::Error,
143 };
144 let path = match Path::from_ast(path) {
145 Some(p) => p,
146 None => return TypeBound::Error,
147 };
148 TypeBound::Path(path)
149 }
150 ast::TypeBoundKind::ForType(_) | ast::TypeBoundKind::Lifetime(_) => TypeBound::Error,
151 }
152 }
153}
diff --git a/crates/ra_parser/src/grammar/expressions/atom.rs b/crates/ra_parser/src/grammar/expressions/atom.rs
index bc942ae01..ab8fb9f6e 100644
--- a/crates/ra_parser/src/grammar/expressions/atom.rs
+++ b/crates/ra_parser/src/grammar/expressions/atom.rs
@@ -414,6 +414,8 @@ pub(crate) fn match_arm_list(p: &mut Parser) {
414// X | Y if Z => (), 414// X | Y if Z => (),
415// | X | Y if Z => (), 415// | X | Y if Z => (),
416// | X => (), 416// | X => (),
417// box X => (),
418// Some(box X) => (),
417// }; 419// };
418// } 420// }
419fn match_arm(p: &mut Parser) -> BlockLike { 421fn match_arm(p: &mut Parser) -> BlockLike {
diff --git a/crates/ra_parser/src/grammar/patterns.rs b/crates/ra_parser/src/grammar/patterns.rs
index df6000707..1f6a6fd48 100644
--- a/crates/ra_parser/src/grammar/patterns.rs
+++ b/crates/ra_parser/src/grammar/patterns.rs
@@ -2,7 +2,7 @@ use super::*;
2 2
3pub(super) const PATTERN_FIRST: TokenSet = expressions::LITERAL_FIRST 3pub(super) const PATTERN_FIRST: TokenSet = expressions::LITERAL_FIRST
4 .union(paths::PATH_FIRST) 4 .union(paths::PATH_FIRST)
5 .union(token_set![REF_KW, MUT_KW, L_PAREN, L_BRACK, AMP, UNDERSCORE, MINUS]); 5 .union(token_set![BOX_KW, REF_KW, MUT_KW, L_PAREN, L_BRACK, AMP, UNDERSCORE, MINUS]);
6 6
7pub(super) fn pattern(p: &mut Parser) { 7pub(super) fn pattern(p: &mut Parser) {
8 pattern_r(p, PAT_RECOVERY_SET); 8 pattern_r(p, PAT_RECOVERY_SET);
diff --git a/crates/ra_project_model/src/sysroot.rs b/crates/ra_project_model/src/sysroot.rs
index 2a7927f7e..0c27d4f4b 100644
--- a/crates/ra_project_model/src/sysroot.rs
+++ b/crates/ra_project_model/src/sysroot.rs
@@ -1,4 +1,5 @@
1use std::{ 1use std::{
2 env,
2 path::{Path, PathBuf}, 3 path::{Path, PathBuf},
3 process::Command, 4 process::Command,
4}; 5};
@@ -33,21 +34,13 @@ impl Sysroot {
33 } 34 }
34 35
35 pub fn discover(cargo_toml: &Path) -> Result<Sysroot> { 36 pub fn discover(cargo_toml: &Path) -> Result<Sysroot> {
36 let rustc_output = Command::new("rustc") 37 let src = try_find_src_path(cargo_toml)?;
37 .current_dir(cargo_toml.parent().unwrap()) 38
38 .args(&["--print", "sysroot"])
39 .output()?;
40 if !rustc_output.status.success() {
41 Err("failed to locate sysroot")?
42 }
43 let stdout = String::from_utf8(rustc_output.stdout)?;
44 let sysroot_path = Path::new(stdout.trim());
45 let src = sysroot_path.join("lib/rustlib/src/rust/src");
46 if !src.exists() { 39 if !src.exists() {
47 Err(format!( 40 Err(format!(
48 "can't load standard library from sysroot\n\ 41 "can't load standard library from sysroot\n\
49 {:?}\n\ 42 {:?}\n\
50 try running `rustup component add rust-src`", 43 try running `rustup component add rust-src` or set `RUST_SRC_PATH`",
51 src, 44 src,
52 ))?; 45 ))?;
53 } 46 }
@@ -83,6 +76,23 @@ impl Sysroot {
83 } 76 }
84} 77}
85 78
79fn try_find_src_path(cargo_toml: &Path) -> Result<PathBuf> {
80 if let Ok(path) = env::var("RUST_SRC_PATH") {
81 return Ok(path.into());
82 }
83
84 let rustc_output = Command::new("rustc")
85 .current_dir(cargo_toml.parent().unwrap())
86 .args(&["--print", "sysroot"])
87 .output()?;
88 if !rustc_output.status.success() {
89 Err("failed to locate sysroot")?;
90 }
91 let stdout = String::from_utf8(rustc_output.stdout)?;
92 let sysroot_path = Path::new(stdout.trim());
93 Ok(sysroot_path.join("lib/rustlib/src/rust/src"))
94}
95
86impl SysrootCrate { 96impl SysrootCrate {
87 pub fn name(self, sysroot: &Sysroot) -> &str { 97 pub fn name(self, sysroot: &Sysroot) -> &str {
88 &sysroot.crates[self].name 98 &sysroot.crates[self].name
diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs
index 6f0489617..afdfca66e 100644
--- a/crates/ra_syntax/src/ast.rs
+++ b/crates/ra_syntax/src/ast.rs
@@ -15,7 +15,7 @@ use crate::{
15 15
16pub use self::{ 16pub use self::{
17 expr_extensions::{ArrayExprKind, BinOp, ElseBranch, LiteralKind, PrefixOp}, 17 expr_extensions::{ArrayExprKind, BinOp, ElseBranch, LiteralKind, PrefixOp},
18 extensions::{FieldKind, PathSegmentKind, SelfParamKind, StructKind}, 18 extensions::{FieldKind, PathSegmentKind, SelfParamKind, StructKind, TypeBoundKind},
19 generated::*, 19 generated::*,
20 tokens::*, 20 tokens::*,
21 traits::*, 21 traits::*,
diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs
index efe261fc2..e0ea3e5ab 100644
--- a/crates/ra_syntax/src/ast/extensions.rs
+++ b/crates/ra_syntax/src/ast/extensions.rs
@@ -382,7 +382,36 @@ impl ast::WherePred {
382 } 382 }
383} 383}
384 384
385#[derive(Clone, Debug, PartialEq, Eq, Hash)]
386pub enum TypeBoundKind {
387 /// Trait
388 PathType(ast::PathType),
389 /// for<'a> ...
390 ForType(ast::ForType),
391 /// 'a
392 Lifetime(ast::SyntaxToken),
393}
394
385impl ast::TypeBound { 395impl ast::TypeBound {
396 pub fn kind(&self) -> TypeBoundKind {
397 if let Some(path_type) = children(self).next() {
398 TypeBoundKind::PathType(path_type)
399 } else if let Some(for_type) = children(self).next() {
400 TypeBoundKind::ForType(for_type)
401 } else if let Some(lifetime) = self.lifetime() {
402 TypeBoundKind::Lifetime(lifetime)
403 } else {
404 unreachable!()
405 }
406 }
407
408 fn lifetime(&self) -> Option<SyntaxToken> {
409 self.syntax()
410 .children_with_tokens()
411 .filter_map(|it| it.into_token())
412 .find(|it| it.kind() == LIFETIME)
413 }
414
386 pub fn question_mark_token(&self) -> Option<SyntaxToken> { 415 pub fn question_mark_token(&self) -> Option<SyntaxToken> {
387 self.syntax() 416 self.syntax()
388 .children_with_tokens() 417 .children_with_tokens()
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0066_match_arm.rs b/crates/ra_syntax/test_data/parser/inline/ok/0066_match_arm.rs
index 9e009e24f..2d476278d 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0066_match_arm.rs
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0066_match_arm.rs
@@ -5,5 +5,7 @@ fn foo() {
5 X | Y if Z => (), 5 X | Y if Z => (),
6 | X | Y if Z => (), 6 | X | Y if Z => (),
7 | X => (), 7 | X => (),
8 box X => (),
9 Some(box X) => (),
8 }; 10 };
9} 11}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0066_match_arm.txt b/crates/ra_syntax/test_data/parser/inline/ok/0066_match_arm.txt
index 041e7179e..28d501459 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0066_match_arm.txt
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0066_match_arm.txt
@@ -1,5 +1,5 @@
1SOURCE_FILE@[0; 167) 1SOURCE_FILE@[0; 215)
2 FN_DEF@[0; 166) 2 FN_DEF@[0; 214)
3 FN_KW@[0; 2) "fn" 3 FN_KW@[0; 2) "fn"
4 WHITESPACE@[2; 3) " " 4 WHITESPACE@[2; 3) " "
5 NAME@[3; 6) 5 NAME@[3; 6)
@@ -8,18 +8,18 @@ SOURCE_FILE@[0; 167)
8 L_PAREN@[6; 7) "(" 8 L_PAREN@[6; 7) "("
9 R_PAREN@[7; 8) ")" 9 R_PAREN@[7; 8) ")"
10 WHITESPACE@[8; 9) " " 10 WHITESPACE@[8; 9) " "
11 BLOCK@[9; 166) 11 BLOCK@[9; 214)
12 L_CURLY@[9; 10) "{" 12 L_CURLY@[9; 10) "{"
13 WHITESPACE@[10; 15) "\n " 13 WHITESPACE@[10; 15) "\n "
14 EXPR_STMT@[15; 164) 14 EXPR_STMT@[15; 212)
15 MATCH_EXPR@[15; 163) 15 MATCH_EXPR@[15; 211)
16 MATCH_KW@[15; 20) "match" 16 MATCH_KW@[15; 20) "match"
17 WHITESPACE@[20; 21) " " 17 WHITESPACE@[20; 21) " "
18 TUPLE_EXPR@[21; 23) 18 TUPLE_EXPR@[21; 23)
19 L_PAREN@[21; 22) "(" 19 L_PAREN@[21; 22) "("
20 R_PAREN@[22; 23) ")" 20 R_PAREN@[22; 23) ")"
21 WHITESPACE@[23; 24) " " 21 WHITESPACE@[23; 24) " "
22 MATCH_ARM_LIST@[24; 163) 22 MATCH_ARM_LIST@[24; 211)
23 L_CURLY@[24; 25) "{" 23 L_CURLY@[24; 25) "{"
24 WHITESPACE@[25; 34) "\n " 24 WHITESPACE@[25; 34) "\n "
25 MATCH_ARM@[34; 41) 25 MATCH_ARM@[34; 41)
@@ -141,9 +141,44 @@ SOURCE_FILE@[0; 167)
141 L_PAREN@[154; 155) "(" 141 L_PAREN@[154; 155) "("
142 R_PAREN@[155; 156) ")" 142 R_PAREN@[155; 156) ")"
143 COMMA@[156; 157) "," 143 COMMA@[156; 157) ","
144 WHITESPACE@[157; 162) "\n " 144 WHITESPACE@[157; 166) "\n "
145 R_CURLY@[162; 163) "}" 145 MATCH_ARM@[166; 177)
146 SEMI@[163; 164) ";" 146 BIND_PAT@[166; 171)
147 WHITESPACE@[164; 165) "\n" 147 BOX_KW@[166; 169) "box"
148 R_CURLY@[165; 166) "}" 148 WHITESPACE@[169; 170) " "
149 WHITESPACE@[166; 167) "\n" 149 NAME@[170; 171)
150 IDENT@[170; 171) "X"
151 WHITESPACE@[171; 172) " "
152 FAT_ARROW@[172; 174) "=>"
153 WHITESPACE@[174; 175) " "
154 TUPLE_EXPR@[175; 177)
155 L_PAREN@[175; 176) "("
156 R_PAREN@[176; 177) ")"
157 COMMA@[177; 178) ","
158 WHITESPACE@[178; 187) "\n "
159 MATCH_ARM@[187; 204)
160 TUPLE_STRUCT_PAT@[187; 198)
161 PATH@[187; 191)
162 PATH_SEGMENT@[187; 191)
163 NAME_REF@[187; 191)
164 IDENT@[187; 191) "Some"
165 L_PAREN@[191; 192) "("
166 BIND_PAT@[192; 197)
167 BOX_KW@[192; 195) "box"
168 WHITESPACE@[195; 196) " "
169 NAME@[196; 197)
170 IDENT@[196; 197) "X"
171 R_PAREN@[197; 198) ")"
172 WHITESPACE@[198; 199) " "
173 FAT_ARROW@[199; 201) "=>"
174 WHITESPACE@[201; 202) " "
175 TUPLE_EXPR@[202; 204)
176 L_PAREN@[202; 203) "("
177 R_PAREN@[203; 204) ")"
178 COMMA@[204; 205) ","
179 WHITESPACE@[205; 210) "\n "
180 R_CURLY@[210; 211) "}"
181 SEMI@[211; 212) ";"
182 WHITESPACE@[212; 213) "\n"
183 R_CURLY@[213; 214) "}"
184 WHITESPACE@[214; 215) "\n"
diff --git a/docs/user/README.md b/docs/user/README.md
index 7990d1d31..453e8e273 100644
--- a/docs/user/README.md
+++ b/docs/user/README.md
@@ -78,6 +78,7 @@ See https://github.com/microsoft/vscode/issues/72308[microsoft/vscode#72308] for
78 (e.g: `--features="shumway,pdf"` will run as `cargo watch -x "check --features="shumway,pdf""` ) 78 (e.g: `--features="shumway,pdf"` will run as `cargo watch -x "check --features="shumway,pdf""` )
79* `rust-analyzer.trace.server`: enables internal logging 79* `rust-analyzer.trace.server`: enables internal logging
80* `rust-analyzer.trace.cargo-watch`: enables cargo-watch logging 80* `rust-analyzer.trace.cargo-watch`: enables cargo-watch logging
81* `RUST_SRC_PATH`: environment variable that overwrites the sysroot
81 82
82 83
83## Emacs 84## Emacs