diff options
Diffstat (limited to 'crates/ra_hir_ty/src')
-rw-r--r-- | crates/ra_hir_ty/src/db.rs | 29 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/path.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/lib.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/lower.rs | 86 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/method_resolution.rs | 28 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/test_db.rs | 7 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/macros.rs | 65 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/traits.rs | 41 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/traits.rs | 119 |
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 | }; |
19 | use 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)] |
22 | pub trait HirDatabase: DefDatabase { | 23 | pub 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 | ||
113 | fn infer(db: &impl HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> { | 106 | fn 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; | |||
63 | mod coerce; | 63 | mod coerce; |
64 | 64 | ||
65 | /// The entry point of type inference. | 65 | /// The entry point of type inference. |
66 | pub fn do_infer_query(db: &impl HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> { | 66 | pub(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; | |||
26 | pub mod method_resolution; | 26 | pub mod method_resolution; |
27 | mod op; | 27 | mod op; |
28 | mod lower; | 28 | mod lower; |
29 | mod infer; | 29 | pub(crate) mod infer; |
30 | pub mod display; | 30 | pub mod display; |
31 | pub(crate) mod utils; | 31 | pub(crate) mod utils; |
32 | pub mod db; | 32 | pub mod db; |
@@ -57,7 +57,7 @@ use crate::{ | |||
57 | use display::HirDisplay; | 57 | use display::HirDisplay; |
58 | 58 | ||
59 | pub use autoderef::autoderef; | 59 | pub use autoderef::autoderef; |
60 | pub use infer::{do_infer_query, InferTy, InferenceResult}; | 60 | pub use infer::{InferTy, InferenceResult}; |
61 | pub use lower::CallableDef; | 61 | pub use lower::CallableDef; |
62 | pub use lower::{ | 62 | pub 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 | ||
92 | impl Ty { | 92 | impl 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`. | ||
529 | fn 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 | ||
524 | fn transform_receiver_ty( | 546 | fn 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 | ||
72 | impl TestDB { | 79 | impl 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] |
487 | fn 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] | ||
492 | macro_rules! include {() => {}} | ||
493 | |||
494 | #[rustc_builtin_macro] | ||
495 | macro_rules! concat {() => {}} | ||
496 | |||
497 | #[rustc_builtin_macro] | ||
498 | macro_rules! env {() => {}} | ||
499 | |||
500 | include!(concat!(env!("OUT_DIR"), "/foo.rs")); | ||
501 | |||
502 | fn main() { | ||
503 | bar()<|>; | ||
504 | } | ||
505 | |||
506 | //- /foo.rs | ||
507 | fn bar() -> u32 {0} | ||
508 | "#, | ||
509 | ); | ||
510 | assert_eq!("{unknown}", type_at_pos(&db, pos)); | ||
511 | } | ||
512 | |||
513 | #[test] | ||
514 | fn infer_builtin_macros_include_itself_should_failed() { | ||
515 | let (db, pos) = TestDB::with_position( | ||
516 | r#" | ||
517 | //- /main.rs | ||
518 | #[rustc_builtin_macro] | ||
519 | macro_rules! include {() => {}} | ||
520 | |||
521 | include!("main.rs"); | ||
522 | |||
523 | fn main() { | ||
524 | 0<|> | ||
525 | } | ||
526 | "#, | ||
527 | ); | ||
528 | assert_eq!("i32", type_at_pos(&db, pos)); | ||
529 | } | ||
530 | |||
531 | #[test] | ||
487 | fn infer_builtin_macros_concat_with_lazy() { | 532 | fn 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] |
553 | fn infer_builtin_macros_env() { | ||
554 | assert_snapshot!( | ||
555 | infer(r#" | ||
556 | //- /main.rs env:foo=bar | ||
557 | #[rustc_builtin_macro] | ||
558 | macro_rules! env {() => {}} | ||
559 | |||
560 | fn 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] | ||
508 | fn infer_derive_clone_simple() { | 573 | fn 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] |
1806 | fn unselected_projection_on_trait_self() { | ||
1807 | assert_snapshot!(infer( | ||
1808 | r#" | ||
1809 | //- /main.rs | ||
1810 | trait Trait { | ||
1811 | type Item; | ||
1812 | |||
1813 | fn f(&self, x: Self::Item); | ||
1814 | } | ||
1815 | |||
1816 | struct S; | ||
1817 | |||
1818 | impl Trait for S { | ||
1819 | type Item = u32; | ||
1820 | fn f(&self, x: Self::Item) { let y = x; } | ||
1821 | } | ||
1822 | |||
1823 | struct S2; | ||
1824 | |||
1825 | impl 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] | ||
1806 | fn trait_impl_self_ty() { | 1847 | fn 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. |
2 | use std::{ | 2 | use std::{panic, sync::Arc}; |
3 | panic, | ||
4 | sync::{Arc, Mutex}, | ||
5 | }; | ||
6 | 3 | ||
7 | use chalk_ir::cast::Cast; | 4 | use chalk_ir::cast::Cast; |
8 | use hir_def::{expr::ExprId, DefWithBodyId, ImplId, TraitId, TypeAliasId}; | 5 | use hir_def::{expr::ExprId, DefWithBodyId, ImplId, TraitId, TypeAliasId}; |
9 | use ra_db::{impl_intern_key, salsa, Canceled, CrateId}; | 6 | use ra_db::{impl_intern_key, salsa, CrateId}; |
10 | use ra_prof::profile; | 7 | use ra_prof::profile; |
11 | use rustc_hash::FxHashSet; | 8 | use rustc_hash::FxHashSet; |
12 | 9 | ||
@@ -19,74 +16,6 @@ use self::chalk::{from_chalk, Interner, ToChalk}; | |||
19 | pub(crate) mod chalk; | 16 | pub(crate) mod chalk; |
20 | mod builtin; | 17 | mod builtin; |
21 | 18 | ||
22 | #[derive(Debug, Clone)] | ||
23 | pub struct TraitSolver { | ||
24 | krate: CrateId, | ||
25 | inner: Arc<Mutex<chalk_solve::Solver<Interner>>>, | ||
26 | } | ||
27 | |||
28 | /// We need eq for salsa | ||
29 | impl PartialEq for TraitSolver { | ||
30 | fn eq(&self, other: &TraitSolver) -> bool { | ||
31 | Arc::ptr_eq(&self.inner, &other.inner) | ||
32 | } | ||
33 | } | ||
34 | |||
35 | impl Eq for TraitSolver {} | ||
36 | |||
37 | impl 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 | ||
103 | pub(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 | |||
113 | fn create_chalk_solver() -> chalk_solve::Solver<Interner> { | 32 | fn 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 | ||
165 | fn 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 | |||
243 | fn solution_from_chalk( | 190 | fn solution_from_chalk( |
244 | db: &impl HirDatabase, | 191 | db: &impl HirDatabase, |
245 | solution: chalk_solve::Solution<Interner>, | 192 | solution: chalk_solve::Solution<Interner>, |