aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_ty/src')
-rw-r--r--crates/ra_hir_ty/src/db.rs29
-rw-r--r--crates/ra_hir_ty/src/infer.rs4
-rw-r--r--crates/ra_hir_ty/src/infer/path.rs4
-rw-r--r--crates/ra_hir_ty/src/lib.rs4
-rw-r--r--crates/ra_hir_ty/src/lower.rs86
-rw-r--r--crates/ra_hir_ty/src/method_resolution.rs28
-rw-r--r--crates/ra_hir_ty/src/test_db.rs7
-rw-r--r--crates/ra_hir_ty/src/tests/macros.rs65
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs41
-rw-r--r--crates/ra_hir_ty/src/traits.rs119
10 files changed, 242 insertions, 145 deletions
diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs
index c43619d1c..74b309005 100644
--- a/crates/ra_hir_ty/src/db.rs
+++ b/crates/ra_hir_ty/src/db.rs
@@ -16,15 +16,16 @@ use crate::{
16 Binders, CallableDef, GenericPredicate, InferenceResult, PolyFnSig, Substs, TraitRef, Ty, 16 Binders, CallableDef, GenericPredicate, InferenceResult, PolyFnSig, Substs, TraitRef, Ty,
17 TyDefId, TypeCtor, ValueTyDefId, 17 TyDefId, TypeCtor, ValueTyDefId,
18}; 18};
19use hir_expand::name::Name;
19 20
20#[salsa::query_group(HirDatabaseStorage)] 21#[salsa::query_group(HirDatabaseStorage)]
21#[salsa::requires(salsa::Database)] 22#[salsa::requires(salsa::Database)]
22pub trait HirDatabase: DefDatabase { 23pub trait HirDatabase: DefDatabase {
23 #[salsa::transparent] 24 #[salsa::invoke(infer_wait)]
24 fn infer(&self, def: DefWithBodyId) -> Arc<InferenceResult>; 25 fn infer(&self, def: DefWithBodyId) -> Arc<InferenceResult>;
25 26
26 #[salsa::invoke(crate::do_infer_query)] 27 #[salsa::invoke(crate::infer::infer_query)]
27 fn do_infer(&self, def: DefWithBodyId) -> Arc<InferenceResult>; 28 fn infer_query(&self, def: DefWithBodyId) -> Arc<InferenceResult>;
28 29
29 #[salsa::invoke(crate::lower::ty_query)] 30 #[salsa::invoke(crate::lower::ty_query)]
30 #[salsa::cycle(crate::lower::ty_recover)] 31 #[salsa::cycle(crate::lower::ty_recover)]
@@ -65,14 +66,6 @@ pub trait HirDatabase: DefDatabase {
65 #[salsa::invoke(crate::traits::impls_for_trait_query)] 66 #[salsa::invoke(crate::traits::impls_for_trait_query)]
66 fn impls_for_trait(&self, krate: CrateId, trait_: TraitId) -> Arc<[ImplId]>; 67 fn impls_for_trait(&self, krate: CrateId, trait_: TraitId) -> Arc<[ImplId]>;
67 68
68 /// This provides the Chalk trait solver instance. Because Chalk always
69 /// works from a specific crate, this query is keyed on the crate; and
70 /// because Chalk does its own internal caching, the solver is wrapped in a
71 /// Mutex and the query does an untracked read internally, to make sure the
72 /// cached state is thrown away when input facts change.
73 #[salsa::invoke(crate::traits::trait_solver_query)]
74 fn trait_solver(&self, krate: CrateId) -> crate::traits::TraitSolver;
75
76 // Interned IDs for Chalk integration 69 // Interned IDs for Chalk integration
77 #[salsa::interned] 70 #[salsa::interned]
78 fn intern_type_ctor(&self, type_ctor: TypeCtor) -> crate::TypeCtorId; 71 fn intern_type_ctor(&self, type_ctor: TypeCtor) -> crate::TypeCtorId;
@@ -110,9 +103,17 @@ pub trait HirDatabase: DefDatabase {
110 ) -> Option<crate::traits::Solution>; 103 ) -> Option<crate::traits::Solution>;
111} 104}
112 105
113fn infer(db: &impl HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> { 106fn infer_wait(db: &impl HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> {
114 let _p = profile("wait_infer"); 107 let _p = profile("infer:wait").detail(|| match def {
115 db.do_infer(def) 108 DefWithBodyId::FunctionId(it) => db.function_data(it).name.to_string(),
109 DefWithBodyId::StaticId(it) => {
110 db.static_data(it).name.clone().unwrap_or_else(Name::missing).to_string()
111 }
112 DefWithBodyId::ConstId(it) => {
113 db.const_data(it).name.clone().unwrap_or_else(Name::missing).to_string()
114 }
115 });
116 db.infer_query(def)
116} 117}
117 118
118#[test] 119#[test]
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs
index 437086ff6..947833412 100644
--- a/crates/ra_hir_ty/src/infer.rs
+++ b/crates/ra_hir_ty/src/infer.rs
@@ -63,8 +63,8 @@ mod pat;
63mod coerce; 63mod coerce;
64 64
65/// The entry point of type inference. 65/// The entry point of type inference.
66pub fn do_infer_query(db: &impl HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> { 66pub(crate) fn infer_query(db: &impl HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> {
67 let _p = profile("infer"); 67 let _p = profile("infer_query");
68 let resolver = def.resolver(db); 68 let resolver = def.resolver(db);
69 let mut ctx = InferenceContext::new(db, def, resolver); 69 let mut ctx = InferenceContext::new(db, def, resolver);
70 70
diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs
index 471d60342..c733b9e1d 100644
--- a/crates/ra_hir_ty/src/infer/path.rs
+++ b/crates/ra_hir_ty/src/infer/path.rs
@@ -40,7 +40,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
40 let ty = self.make_ty(type_ref); 40 let ty = self.make_ty(type_ref);
41 let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1); 41 let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1);
42 let ctx = crate::lower::TyLoweringContext::new(self.db, &resolver); 42 let ctx = crate::lower::TyLoweringContext::new(self.db, &resolver);
43 let ty = Ty::from_type_relative_path(&ctx, ty, remaining_segments_for_ty); 43 let (ty, _) = Ty::from_type_relative_path(&ctx, ty, None, remaining_segments_for_ty);
44 self.resolve_ty_assoc_item( 44 self.resolve_ty_assoc_item(
45 ty, 45 ty,
46 &path.segments().last().expect("path had at least one segment").name, 46 &path.segments().last().expect("path had at least one segment").name,
@@ -115,7 +115,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
115 let remaining_segments_for_ty = 115 let remaining_segments_for_ty =
116 remaining_segments.take(remaining_segments.len() - 1); 116 remaining_segments.take(remaining_segments.len() - 1);
117 let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); 117 let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
118 let ty = Ty::from_partly_resolved_hir_path( 118 let (ty, _) = Ty::from_partly_resolved_hir_path(
119 &ctx, 119 &ctx,
120 def, 120 def,
121 resolved_segment, 121 resolved_segment,
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index ca194f806..4127f1a8d 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -26,7 +26,7 @@ pub mod traits;
26pub mod method_resolution; 26pub mod method_resolution;
27mod op; 27mod op;
28mod lower; 28mod lower;
29mod infer; 29pub(crate) mod infer;
30pub mod display; 30pub mod display;
31pub(crate) mod utils; 31pub(crate) mod utils;
32pub mod db; 32pub mod db;
@@ -57,7 +57,7 @@ use crate::{
57use display::HirDisplay; 57use display::HirDisplay;
58 58
59pub use autoderef::autoderef; 59pub use autoderef::autoderef;
60pub use infer::{do_infer_query, InferTy, InferenceResult}; 60pub use infer::{InferTy, InferenceResult};
61pub use lower::CallableDef; 61pub use lower::CallableDef;
62pub use lower::{ 62pub use lower::{
63 callable_item_sig, ImplTraitLoweringMode, TyDefId, TyLoweringContext, ValueTyDefId, 63 callable_item_sig, ImplTraitLoweringMode, TyDefId, TyLoweringContext, ValueTyDefId,
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs
index 092977e93..b96dc126c 100644
--- a/crates/ra_hir_ty/src/lower.rs
+++ b/crates/ra_hir_ty/src/lower.rs
@@ -91,7 +91,14 @@ pub enum TypeParamLoweringMode {
91 91
92impl Ty { 92impl Ty {
93 pub fn from_hir(ctx: &TyLoweringContext<'_, impl HirDatabase>, type_ref: &TypeRef) -> Self { 93 pub fn from_hir(ctx: &TyLoweringContext<'_, impl HirDatabase>, type_ref: &TypeRef) -> Self {
94 match type_ref { 94 Ty::from_hir_ext(ctx, type_ref).0
95 }
96 pub fn from_hir_ext(
97 ctx: &TyLoweringContext<'_, impl HirDatabase>,
98 type_ref: &TypeRef,
99 ) -> (Self, Option<TypeNs>) {
100 let mut res = None;
101 let ty = match type_ref {
95 TypeRef::Never => Ty::simple(TypeCtor::Never), 102 TypeRef::Never => Ty::simple(TypeCtor::Never),
96 TypeRef::Tuple(inner) => { 103 TypeRef::Tuple(inner) => {
97 let inner_tys: Arc<[Ty]> = inner.iter().map(|tr| Ty::from_hir(ctx, tr)).collect(); 104 let inner_tys: Arc<[Ty]> = inner.iter().map(|tr| Ty::from_hir(ctx, tr)).collect();
@@ -100,7 +107,11 @@ impl Ty {
100 Substs(inner_tys), 107 Substs(inner_tys),
101 ) 108 )
102 } 109 }
103 TypeRef::Path(path) => Ty::from_hir_path(ctx, path), 110 TypeRef::Path(path) => {
111 let (ty, res_) = Ty::from_hir_path(ctx, path);
112 res = res_;
113 ty
114 }
104 TypeRef::RawPtr(inner, mutability) => { 115 TypeRef::RawPtr(inner, mutability) => {
105 let inner_ty = Ty::from_hir(ctx, inner); 116 let inner_ty = Ty::from_hir(ctx, inner);
106 Ty::apply_one(TypeCtor::RawPtr(*mutability), inner_ty) 117 Ty::apply_one(TypeCtor::RawPtr(*mutability), inner_ty)
@@ -183,7 +194,8 @@ impl Ty {
183 } 194 }
184 } 195 }
185 TypeRef::Error => Ty::Unknown, 196 TypeRef::Error => Ty::Unknown,
186 } 197 };
198 (ty, res)
187 } 199 }
188 200
189 /// This is only for `generic_predicates_for_param`, where we can't just 201 /// This is only for `generic_predicates_for_param`, where we can't just
@@ -217,17 +229,19 @@ impl Ty {
217 pub(crate) fn from_type_relative_path( 229 pub(crate) fn from_type_relative_path(
218 ctx: &TyLoweringContext<'_, impl HirDatabase>, 230 ctx: &TyLoweringContext<'_, impl HirDatabase>,
219 ty: Ty, 231 ty: Ty,
232 // We need the original resolution to lower `Self::AssocTy` correctly
233 res: Option<TypeNs>,
220 remaining_segments: PathSegments<'_>, 234 remaining_segments: PathSegments<'_>,
221 ) -> Ty { 235 ) -> (Ty, Option<TypeNs>) {
222 if remaining_segments.len() == 1 { 236 if remaining_segments.len() == 1 {
223 // resolve unselected assoc types 237 // resolve unselected assoc types
224 let segment = remaining_segments.first().unwrap(); 238 let segment = remaining_segments.first().unwrap();
225 Ty::select_associated_type(ctx, ty, segment) 239 (Ty::select_associated_type(ctx, ty, res, segment), None)
226 } else if remaining_segments.len() > 1 { 240 } else if remaining_segments.len() > 1 {
227 // FIXME report error (ambiguous associated type) 241 // FIXME report error (ambiguous associated type)
228 Ty::Unknown 242 (Ty::Unknown, None)
229 } else { 243 } else {
230 ty 244 (ty, res)
231 } 245 }
232 } 246 }
233 247
@@ -236,14 +250,14 @@ impl Ty {
236 resolution: TypeNs, 250 resolution: TypeNs,
237 resolved_segment: PathSegment<'_>, 251 resolved_segment: PathSegment<'_>,
238 remaining_segments: PathSegments<'_>, 252 remaining_segments: PathSegments<'_>,
239 ) -> Ty { 253 ) -> (Ty, Option<TypeNs>) {
240 let ty = match resolution { 254 let ty = match resolution {
241 TypeNs::TraitId(trait_) => { 255 TypeNs::TraitId(trait_) => {
242 // if this is a bare dyn Trait, we'll directly put the required ^0 for the self type in there 256 // if this is a bare dyn Trait, we'll directly put the required ^0 for the self type in there
243 let self_ty = if remaining_segments.len() == 0 { Some(Ty::Bound(0)) } else { None }; 257 let self_ty = if remaining_segments.len() == 0 { Some(Ty::Bound(0)) } else { None };
244 let trait_ref = 258 let trait_ref =
245 TraitRef::from_resolved_path(ctx, trait_, resolved_segment, self_ty); 259 TraitRef::from_resolved_path(ctx, trait_, resolved_segment, self_ty);
246 return if remaining_segments.len() == 1 { 260 let ty = if remaining_segments.len() == 1 {
247 let segment = remaining_segments.first().unwrap(); 261 let segment = remaining_segments.first().unwrap();
248 let associated_ty = associated_type_by_name_including_super_traits( 262 let associated_ty = associated_type_by_name_including_super_traits(
249 ctx.db, 263 ctx.db,
@@ -269,6 +283,7 @@ impl Ty {
269 } else { 283 } else {
270 Ty::Dyn(Arc::new([GenericPredicate::Implemented(trait_ref)])) 284 Ty::Dyn(Arc::new([GenericPredicate::Implemented(trait_ref)]))
271 }; 285 };
286 return (ty, None);
272 } 287 }
273 TypeNs::GenericParam(param_id) => { 288 TypeNs::GenericParam(param_id) => {
274 let generics = 289 let generics =
@@ -306,22 +321,25 @@ impl Ty {
306 TypeNs::BuiltinType(it) => Ty::from_hir_path_inner(ctx, resolved_segment, it.into()), 321 TypeNs::BuiltinType(it) => Ty::from_hir_path_inner(ctx, resolved_segment, it.into()),
307 TypeNs::TypeAliasId(it) => Ty::from_hir_path_inner(ctx, resolved_segment, it.into()), 322 TypeNs::TypeAliasId(it) => Ty::from_hir_path_inner(ctx, resolved_segment, it.into()),
308 // FIXME: report error 323 // FIXME: report error
309 TypeNs::EnumVariantId(_) => return Ty::Unknown, 324 TypeNs::EnumVariantId(_) => return (Ty::Unknown, None),
310 }; 325 };
311 326
312 Ty::from_type_relative_path(ctx, ty, remaining_segments) 327 Ty::from_type_relative_path(ctx, ty, Some(resolution), remaining_segments)
313 } 328 }
314 329
315 pub(crate) fn from_hir_path(ctx: &TyLoweringContext<'_, impl HirDatabase>, path: &Path) -> Ty { 330 pub(crate) fn from_hir_path(
331 ctx: &TyLoweringContext<'_, impl HirDatabase>,
332 path: &Path,
333 ) -> (Ty, Option<TypeNs>) {
316 // Resolve the path (in type namespace) 334 // Resolve the path (in type namespace)
317 if let Some(type_ref) = path.type_anchor() { 335 if let Some(type_ref) = path.type_anchor() {
318 let ty = Ty::from_hir(ctx, &type_ref); 336 let (ty, res) = Ty::from_hir_ext(ctx, &type_ref);
319 return Ty::from_type_relative_path(ctx, ty, path.segments()); 337 return Ty::from_type_relative_path(ctx, ty, res, path.segments());
320 } 338 }
321 let (resolution, remaining_index) = 339 let (resolution, remaining_index) =
322 match ctx.resolver.resolve_path_in_type_ns(ctx.db, path.mod_path()) { 340 match ctx.resolver.resolve_path_in_type_ns(ctx.db, path.mod_path()) {
323 Some(it) => it, 341 Some(it) => it,
324 None => return Ty::Unknown, 342 None => return (Ty::Unknown, None),
325 }; 343 };
326 let (resolved_segment, remaining_segments) = match remaining_index { 344 let (resolved_segment, remaining_segments) = match remaining_index {
327 None => ( 345 None => (
@@ -336,31 +354,27 @@ impl Ty {
336 fn select_associated_type( 354 fn select_associated_type(
337 ctx: &TyLoweringContext<'_, impl HirDatabase>, 355 ctx: &TyLoweringContext<'_, impl HirDatabase>,
338 self_ty: Ty, 356 self_ty: Ty,
357 res: Option<TypeNs>,
339 segment: PathSegment<'_>, 358 segment: PathSegment<'_>,
340 ) -> Ty { 359 ) -> Ty {
341 let def = match ctx.resolver.generic_def() { 360 let traits_from_env: Vec<_> = match res {
342 Some(def) => def, 361 Some(TypeNs::SelfType(impl_id)) => match ctx.db.impl_trait(impl_id) {
343 None => return Ty::Unknown, // this can't actually happen 362 None => return Ty::Unknown,
344 }; 363 Some(trait_ref) => vec![trait_ref.value.trait_],
345 let param_id = match self_ty { 364 },
346 Ty::Placeholder(id) if ctx.type_param_mode == TypeParamLoweringMode::Placeholder => id, 365 Some(TypeNs::GenericParam(param_id)) => {
347 Ty::Bound(idx) if ctx.type_param_mode == TypeParamLoweringMode::Variable => { 366 let predicates = ctx.db.generic_predicates_for_param(param_id);
348 let generics = generics(ctx.db, def); 367 predicates
349 let param_id = if let Some((id, _)) = generics.iter().nth(idx as usize) { 368 .iter()
350 id 369 .filter_map(|pred| match &pred.value {
351 } else { 370 GenericPredicate::Implemented(tr) => Some(tr.trait_),
352 return Ty::Unknown; 371 _ => None,
353 }; 372 })
354 param_id 373 .collect()
355 } 374 }
356 _ => return Ty::Unknown, // Error: Ambiguous associated type 375 _ => return Ty::Unknown,
357 }; 376 };
358 let predicates = ctx.db.generic_predicates_for_param(param_id); 377 let traits = traits_from_env.into_iter().flat_map(|t| all_super_traits(ctx.db, t));
359 let traits_from_env = predicates.iter().filter_map(|pred| match &pred.value {
360 GenericPredicate::Implemented(tr) => Some(tr.trait_),
361 _ => None,
362 });
363 let traits = traits_from_env.flat_map(|t| all_super_traits(ctx.db, t));
364 for t in traits { 378 for t in traits {
365 if let Some(associated_ty) = ctx.db.trait_data(t).associated_type_by_name(&segment.name) 379 if let Some(associated_ty) = ctx.db.trait_data(t).associated_type_by_name(&segment.name)
366 { 380 {
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs
index b7e8855fb..7f5e1469e 100644
--- a/crates/ra_hir_ty/src/method_resolution.rs
+++ b/crates/ra_hir_ty/src/method_resolution.rs
@@ -516,9 +516,31 @@ pub(crate) fn inherent_impl_substs(
516 let self_ty_with_vars = 516 let self_ty_with_vars =
517 Canonical { num_vars: vars.len() + self_ty.num_vars, value: self_ty_with_vars }; 517 Canonical { num_vars: vars.len() + self_ty.num_vars, value: self_ty_with_vars };
518 let substs = super::infer::unify(&self_ty_with_vars, self_ty); 518 let substs = super::infer::unify(&self_ty_with_vars, self_ty);
519 // we only want the substs for the vars we added, not the ones from self_ty 519 // We only want the substs for the vars we added, not the ones from self_ty.
520 let result = substs.map(|s| s.suffix(vars.len())); 520 // Also, if any of the vars we added are still in there, we replace them by
521 result 521 // Unknown. I think this can only really happen if self_ty contained
522 // Unknown, and in that case we want the result to contain Unknown in those
523 // places again.
524 substs.map(|s| fallback_bound_vars(s.suffix(vars.len()), self_ty.num_vars))
525}
526
527/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past
528/// num_vars_to_keep) by `Ty::Unknown`.
529fn fallback_bound_vars(s: Substs, num_vars_to_keep: usize) -> Substs {
530 s.fold_binders(
531 &mut |ty, binders| {
532 if let Ty::Bound(idx) = &ty {
533 if *idx >= binders as u32 {
534 Ty::Unknown
535 } else {
536 ty
537 }
538 } else {
539 ty
540 }
541 },
542 num_vars_to_keep,
543 )
522} 544}
523 545
524fn transform_receiver_ty( 546fn transform_receiver_ty(
diff --git a/crates/ra_hir_ty/src/test_db.rs b/crates/ra_hir_ty/src/test_db.rs
index c794f7b84..0be2fea4b 100644
--- a/crates/ra_hir_ty/src/test_db.rs
+++ b/crates/ra_hir_ty/src/test_db.rs
@@ -67,6 +67,13 @@ impl FileLoader for TestDB {
67 fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { 67 fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> {
68 FileLoaderDelegate(self).relevant_crates(file_id) 68 FileLoaderDelegate(self).relevant_crates(file_id)
69 } 69 }
70 fn resolve_extern_path(
71 &self,
72 extern_id: ra_db::ExternSourceId,
73 relative_path: &RelativePath,
74 ) -> Option<FileId> {
75 FileLoaderDelegate(self).resolve_extern_path(extern_id, relative_path)
76 }
70} 77}
71 78
72impl TestDB { 79impl TestDB {
diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs
index 42814941f..32457bbf7 100644
--- a/crates/ra_hir_ty/src/tests/macros.rs
+++ b/crates/ra_hir_ty/src/tests/macros.rs
@@ -484,6 +484,51 @@ fn bar() -> u32 {0}
484} 484}
485 485
486#[test] 486#[test]
487fn infer_builtin_macros_include_concat_with_bad_env_should_failed() {
488 let (db, pos) = TestDB::with_position(
489 r#"
490//- /main.rs
491#[rustc_builtin_macro]
492macro_rules! include {() => {}}
493
494#[rustc_builtin_macro]
495macro_rules! concat {() => {}}
496
497#[rustc_builtin_macro]
498macro_rules! env {() => {}}
499
500include!(concat!(env!("OUT_DIR"), "/foo.rs"));
501
502fn main() {
503 bar()<|>;
504}
505
506//- /foo.rs
507fn bar() -> u32 {0}
508"#,
509 );
510 assert_eq!("{unknown}", type_at_pos(&db, pos));
511}
512
513#[test]
514fn infer_builtin_macros_include_itself_should_failed() {
515 let (db, pos) = TestDB::with_position(
516 r#"
517//- /main.rs
518#[rustc_builtin_macro]
519macro_rules! include {() => {}}
520
521include!("main.rs");
522
523fn main() {
524 0<|>
525}
526"#,
527 );
528 assert_eq!("i32", type_at_pos(&db, pos));
529}
530
531#[test]
487fn infer_builtin_macros_concat_with_lazy() { 532fn infer_builtin_macros_concat_with_lazy() {
488 assert_snapshot!( 533 assert_snapshot!(
489 infer(r#" 534 infer(r#"
@@ -505,6 +550,26 @@ fn main() {
505} 550}
506 551
507#[test] 552#[test]
553fn infer_builtin_macros_env() {
554 assert_snapshot!(
555 infer(r#"
556//- /main.rs env:foo=bar
557#[rustc_builtin_macro]
558macro_rules! env {() => {}}
559
560fn main() {
561 let x = env!("foo");
562}
563"#),
564 @r###"
565 ![0; 5) '"bar"': &str
566 [88; 116) '{ ...o"); }': ()
567 [98; 99) 'x': &str
568 "###
569 );
570}
571
572#[test]
508fn infer_derive_clone_simple() { 573fn infer_derive_clone_simple() {
509 let (db, pos) = TestDB::with_position( 574 let (db, pos) = TestDB::with_position(
510 r#" 575 r#"
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs
index 547010b35..f009a708c 100644
--- a/crates/ra_hir_ty/src/tests/traits.rs
+++ b/crates/ra_hir_ty/src/tests/traits.rs
@@ -1803,6 +1803,47 @@ fn test<T, U>() where T::Item: Trait2, T: Trait<U::Item>, U: Trait<()> {
1803} 1803}
1804 1804
1805#[test] 1805#[test]
1806fn unselected_projection_on_trait_self() {
1807 assert_snapshot!(infer(
1808 r#"
1809//- /main.rs
1810trait Trait {
1811 type Item;
1812
1813 fn f(&self, x: Self::Item);
1814}
1815
1816struct S;
1817
1818impl Trait for S {
1819 type Item = u32;
1820 fn f(&self, x: Self::Item) { let y = x; }
1821}
1822
1823struct S2;
1824
1825impl Trait for S2 {
1826 type Item = i32;
1827 fn f(&self, x: <Self>::Item) { let y = x; }
1828}
1829"#,
1830 ), @r###"
1831 [54; 58) 'self': &Self
1832 [60; 61) 'x': {unknown}
1833 [140; 144) 'self': &S
1834 [146; 147) 'x': u32
1835 [161; 175) '{ let y = x; }': ()
1836 [167; 168) 'y': u32
1837 [171; 172) 'x': u32
1838 [242; 246) 'self': &S2
1839 [248; 249) 'x': i32
1840 [265; 279) '{ let y = x; }': ()
1841 [271; 272) 'y': i32
1842 [275; 276) 'x': i32
1843 "###);
1844}
1845
1846#[test]
1806fn trait_impl_self_ty() { 1847fn trait_impl_self_ty() {
1807 let t = type_at( 1848 let t = type_at(
1808 r#" 1849 r#"
diff --git a/crates/ra_hir_ty/src/traits.rs b/crates/ra_hir_ty/src/traits.rs
index bc6ee2600..6e1c8e42a 100644
--- a/crates/ra_hir_ty/src/traits.rs
+++ b/crates/ra_hir_ty/src/traits.rs
@@ -1,12 +1,9 @@
1//! Trait solving using Chalk. 1//! Trait solving using Chalk.
2use std::{ 2use std::{panic, sync::Arc};
3 panic,
4 sync::{Arc, Mutex},
5};
6 3
7use chalk_ir::cast::Cast; 4use chalk_ir::cast::Cast;
8use hir_def::{expr::ExprId, DefWithBodyId, ImplId, TraitId, TypeAliasId}; 5use hir_def::{expr::ExprId, DefWithBodyId, ImplId, TraitId, TypeAliasId};
9use ra_db::{impl_intern_key, salsa, Canceled, CrateId}; 6use ra_db::{impl_intern_key, salsa, CrateId};
10use ra_prof::profile; 7use ra_prof::profile;
11use rustc_hash::FxHashSet; 8use rustc_hash::FxHashSet;
12 9
@@ -19,74 +16,6 @@ use self::chalk::{from_chalk, Interner, ToChalk};
19pub(crate) mod chalk; 16pub(crate) mod chalk;
20mod builtin; 17mod builtin;
21 18
22#[derive(Debug, Clone)]
23pub struct TraitSolver {
24 krate: CrateId,
25 inner: Arc<Mutex<chalk_solve::Solver<Interner>>>,
26}
27
28/// We need eq for salsa
29impl PartialEq for TraitSolver {
30 fn eq(&self, other: &TraitSolver) -> bool {
31 Arc::ptr_eq(&self.inner, &other.inner)
32 }
33}
34
35impl Eq for TraitSolver {}
36
37impl TraitSolver {
38 fn solve(
39 &self,
40 db: &impl HirDatabase,
41 goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal<Interner>>>,
42 ) -> Option<chalk_solve::Solution<Interner>> {
43 let context = ChalkContext { db, krate: self.krate };
44 log::debug!("solve goal: {:?}", goal);
45 let mut solver = match self.inner.lock() {
46 Ok(it) => it,
47 // Our cancellation works via unwinding, but, as chalk is not
48 // panic-safe, we need to make sure to propagate the cancellation.
49 // Ideally, we should also make chalk panic-safe.
50 Err(_) => ra_db::Canceled::throw(),
51 };
52
53 let fuel = std::cell::Cell::new(CHALK_SOLVER_FUEL);
54
55 let solution = panic::catch_unwind({
56 let solver = panic::AssertUnwindSafe(&mut solver);
57 let context = panic::AssertUnwindSafe(&context);
58 move || {
59 solver.0.solve_limited(context.0, goal, || {
60 context.0.db.check_canceled();
61 let remaining = fuel.get();
62 fuel.set(remaining - 1);
63 if remaining == 0 {
64 log::debug!("fuel exhausted");
65 }
66 remaining > 0
67 })
68 }
69 });
70
71 let solution = match solution {
72 Ok(it) => it,
73 Err(err) => {
74 if err.downcast_ref::<Canceled>().is_some() {
75 panic::resume_unwind(err)
76 } else {
77 log::error!("chalk panicked :-(");
78 // Reset the solver, as it is not panic-safe.
79 *solver = create_chalk_solver();
80 None
81 }
82 }
83 };
84
85 log::debug!("solve({:?}) => {:?}", goal, solution);
86 solution
87 }
88}
89
90/// This controls the maximum size of types Chalk considers. If we set this too 19/// This controls the maximum size of types Chalk considers. If we set this too
91/// high, we can run into slow edge cases; if we set it too low, Chalk won't 20/// high, we can run into slow edge cases; if we set it too low, Chalk won't
92/// find some solutions. 21/// find some solutions.
@@ -100,16 +29,6 @@ struct ChalkContext<'a, DB> {
100 krate: CrateId, 29 krate: CrateId,
101} 30}
102 31
103pub(crate) fn trait_solver_query(
104 db: &(impl HirDatabase + salsa::Database),
105 krate: CrateId,
106) -> TraitSolver {
107 db.salsa_runtime().report_untracked_read();
108 // krate parameter is just so we cache a unique solver per crate
109 log::debug!("Creating new solver for crate {:?}", krate);
110 TraitSolver { krate, inner: Arc::new(Mutex::new(create_chalk_solver())) }
111}
112
113fn create_chalk_solver() -> chalk_solve::Solver<Interner> { 32fn create_chalk_solver() -> chalk_solve::Solver<Interner> {
114 let solver_choice = 33 let solver_choice =
115 chalk_solve::SolverChoice::SLG { max_size: CHALK_SOLVER_MAX_SIZE, expected_answers: None }; 34 chalk_solve::SolverChoice::SLG { max_size: CHALK_SOLVER_MAX_SIZE, expected_answers: None };
@@ -128,7 +47,7 @@ pub(crate) fn impls_for_trait_query(
128 // will only ever get called for a few crates near the root of the tree (the 47 // will only ever get called for a few crates near the root of the tree (the
129 // ones the user is editing), so this may actually be a waste of memory. I'm 48 // ones the user is editing), so this may actually be a waste of memory. I'm
130 // doing it like this mainly for simplicity for now. 49 // doing it like this mainly for simplicity for now.
131 for dep in db.crate_graph().dependencies(krate) { 50 for dep in &db.crate_graph()[krate].dependencies {
132 impls.extend(db.impls_for_trait(dep.crate_id, trait_).iter()); 51 impls.extend(db.impls_for_trait(dep.crate_id, trait_).iter());
133 } 52 }
134 let crate_impl_defs = db.impls_in_crate(krate); 53 let crate_impl_defs = db.impls_in_crate(krate);
@@ -221,7 +140,10 @@ pub(crate) fn trait_solve_query(
221 krate: CrateId, 140 krate: CrateId,
222 goal: Canonical<InEnvironment<Obligation>>, 141 goal: Canonical<InEnvironment<Obligation>>,
223) -> Option<Solution> { 142) -> Option<Solution> {
224 let _p = profile("trait_solve_query"); 143 let _p = profile("trait_solve_query").detail(|| match &goal.value.value {
144 Obligation::Trait(it) => db.trait_data(it.trait_).name.to_string(),
145 Obligation::Projection(_) => "projection".to_string(),
146 });
225 log::debug!("trait_solve_query({})", goal.value.value.display(db)); 147 log::debug!("trait_solve_query({})", goal.value.value.display(db));
226 148
227 if let Obligation::Projection(pred) = &goal.value.value { 149 if let Obligation::Projection(pred) = &goal.value.value {
@@ -236,10 +158,35 @@ pub(crate) fn trait_solve_query(
236 // We currently don't deal with universes (I think / hope they're not yet 158 // We currently don't deal with universes (I think / hope they're not yet
237 // relevant for our use cases?) 159 // relevant for our use cases?)
238 let u_canonical = chalk_ir::UCanonical { canonical, universes: 1 }; 160 let u_canonical = chalk_ir::UCanonical { canonical, universes: 1 };
239 let solution = db.trait_solver(krate).solve(db, &u_canonical); 161 let solution = solve(db, krate, &u_canonical);
240 solution.map(|solution| solution_from_chalk(db, solution)) 162 solution.map(|solution| solution_from_chalk(db, solution))
241} 163}
242 164
165fn solve(
166 db: &impl HirDatabase,
167 krate: CrateId,
168 goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal<Interner>>>,
169) -> Option<chalk_solve::Solution<Interner>> {
170 let context = ChalkContext { db, krate };
171 log::debug!("solve goal: {:?}", goal);
172 let mut solver = create_chalk_solver();
173
174 let fuel = std::cell::Cell::new(CHALK_SOLVER_FUEL);
175
176 let solution = solver.solve_limited(&context, goal, || {
177 context.db.check_canceled();
178 let remaining = fuel.get();
179 fuel.set(remaining - 1);
180 if remaining == 0 {
181 log::debug!("fuel exhausted");
182 }
183 remaining > 0
184 });
185
186 log::debug!("solve({:?}) => {:?}", goal, solution);
187 solution
188}
189
243fn solution_from_chalk( 190fn solution_from_chalk(
244 db: &impl HirDatabase, 191 db: &impl HirDatabase,
245 solution: chalk_solve::Solution<Interner>, 192 solution: chalk_solve::Solution<Interner>,