aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_ty')
-rw-r--r--crates/ra_hir_ty/src/infer/expr.rs19
-rw-r--r--crates/ra_hir_ty/src/infer/path.rs9
-rw-r--r--crates/ra_hir_ty/src/method_resolution.rs106
-rw-r--r--crates/ra_hir_ty/src/tests/macros.rs4
-rw-r--r--crates/ra_hir_ty/src/traits.rs44
5 files changed, 128 insertions, 54 deletions
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs
index 3af05394c..d6a17e469 100644
--- a/crates/ra_hir_ty/src/infer/expr.rs
+++ b/crates/ra_hir_ty/src/infer/expr.rs
@@ -569,12 +569,19 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
569 ) -> Ty { 569 ) -> Ty {
570 let receiver_ty = self.infer_expr(receiver, &Expectation::none()); 570 let receiver_ty = self.infer_expr(receiver, &Expectation::none());
571 let canonicalized_receiver = self.canonicalizer().canonicalize_ty(receiver_ty.clone()); 571 let canonicalized_receiver = self.canonicalizer().canonicalize_ty(receiver_ty.clone());
572 let resolved = method_resolution::lookup_method( 572
573 &canonicalized_receiver.value, 573 let traits_in_scope = self.resolver.traits_in_scope(self.db);
574 self.db, 574
575 method_name, 575 let resolved = self.resolver.krate().and_then(|krate| {
576 &self.resolver, 576 method_resolution::lookup_method(
577 ); 577 &canonicalized_receiver.value,
578 self.db,
579 self.trait_env.clone(),
580 krate,
581 &traits_in_scope,
582 method_name,
583 )
584 });
578 let (derefed_receiver_ty, method_ty, def_generics) = match resolved { 585 let (derefed_receiver_ty, method_ty, def_generics) = match resolved {
579 Some((ty, func)) => { 586 Some((ty, func)) => {
580 let ty = canonicalized_receiver.decanonicalize_ty(ty); 587 let ty = canonicalized_receiver.decanonicalize_ty(ty);
diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs
index ffd358367..2c1d4831d 100644
--- a/crates/ra_hir_ty/src/infer/path.rs
+++ b/crates/ra_hir_ty/src/infer/path.rs
@@ -11,7 +11,7 @@ use hir_expand::name::Name;
11 11
12use crate::{db::HirDatabase, method_resolution, Substs, Ty, TypeWalk, ValueTyDefId}; 12use crate::{db::HirDatabase, method_resolution, Substs, Ty, TypeWalk, ValueTyDefId};
13 13
14use super::{ExprOrPatId, InferenceContext, TraitRef}; 14use super::{ExprOrPatId, InferenceContext, TraitEnvironment, TraitRef};
15 15
16impl<'a, D: HirDatabase> InferenceContext<'a, D> { 16impl<'a, D: HirDatabase> InferenceContext<'a, D> {
17 pub(super) fn infer_path( 17 pub(super) fn infer_path(
@@ -193,11 +193,16 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
193 } 193 }
194 194
195 let canonical_ty = self.canonicalizer().canonicalize_ty(ty.clone()); 195 let canonical_ty = self.canonicalizer().canonicalize_ty(ty.clone());
196 let env = TraitEnvironment::lower(self.db, &self.resolver);
197 let krate = self.resolver.krate()?;
198 let traits_in_scope = self.resolver.traits_in_scope(self.db);
196 199
197 method_resolution::iterate_method_candidates( 200 method_resolution::iterate_method_candidates(
198 &canonical_ty.value, 201 &canonical_ty.value,
199 self.db, 202 self.db,
200 &self.resolver.clone(), 203 env,
204 krate,
205 &traits_in_scope,
201 Some(name), 206 Some(name),
202 method_resolution::LookupMode::Path, 207 method_resolution::LookupMode::Path,
203 move |_ty, item| { 208 move |_ty, item| {
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs
index 888dc3116..5bacbbd7c 100644
--- a/crates/ra_hir_ty/src/method_resolution.rs
+++ b/crates/ra_hir_ty/src/method_resolution.rs
@@ -6,13 +6,13 @@ use std::sync::Arc;
6 6
7use arrayvec::ArrayVec; 7use arrayvec::ArrayVec;
8use hir_def::{ 8use hir_def::{
9 lang_item::LangItemTarget, resolver::Resolver, type_ref::Mutability, AssocContainerId, 9 lang_item::LangItemTarget, type_ref::Mutability, AssocContainerId, AssocItemId, FunctionId,
10 AssocItemId, FunctionId, HasModule, ImplId, Lookup, TraitId, 10 HasModule, ImplId, Lookup, TraitId,
11}; 11};
12use hir_expand::name::Name; 12use hir_expand::name::Name;
13use ra_db::CrateId; 13use ra_db::CrateId;
14use ra_prof::profile; 14use ra_prof::profile;
15use rustc_hash::FxHashMap; 15use rustc_hash::{FxHashMap, FxHashSet};
16 16
17use super::Substs; 17use super::Substs;
18use crate::{ 18use crate::{
@@ -144,14 +144,24 @@ impl Ty {
144pub(crate) fn lookup_method( 144pub(crate) fn lookup_method(
145 ty: &Canonical<Ty>, 145 ty: &Canonical<Ty>,
146 db: &impl HirDatabase, 146 db: &impl HirDatabase,
147 env: Arc<TraitEnvironment>,
148 krate: CrateId,
149 traits_in_scope: &FxHashSet<TraitId>,
147 name: &Name, 150 name: &Name,
148 resolver: &Resolver,
149) -> Option<(Ty, FunctionId)> { 151) -> Option<(Ty, FunctionId)> {
150 iterate_method_candidates(ty, db, resolver, Some(name), LookupMode::MethodCall, |ty, f| match f 152 iterate_method_candidates(
151 { 153 ty,
152 AssocItemId::FunctionId(f) => Some((ty.clone(), f)), 154 db,
153 _ => None, 155 env,
154 }) 156 krate,
157 &traits_in_scope,
158 Some(name),
159 LookupMode::MethodCall,
160 |ty, f| match f {
161 AssocItemId::FunctionId(f) => Some((ty.clone(), f)),
162 _ => None,
163 },
164 )
155} 165}
156 166
157/// Whether we're looking up a dotted method call (like `v.len()`) or a path 167/// Whether we're looking up a dotted method call (like `v.len()`) or a path
@@ -172,7 +182,9 @@ pub enum LookupMode {
172pub fn iterate_method_candidates<T>( 182pub fn iterate_method_candidates<T>(
173 ty: &Canonical<Ty>, 183 ty: &Canonical<Ty>,
174 db: &impl HirDatabase, 184 db: &impl HirDatabase,
175 resolver: &Resolver, 185 env: Arc<TraitEnvironment>,
186 krate: CrateId,
187 traits_in_scope: &FxHashSet<TraitId>,
176 name: Option<&Name>, 188 name: Option<&Name>,
177 mode: LookupMode, 189 mode: LookupMode,
178 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, 190 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
@@ -187,9 +199,7 @@ pub fn iterate_method_candidates<T>(
187 // Also note that when we've got a receiver like &S, even if the method we 199 // Also note that when we've got a receiver like &S, even if the method we
188 // find in the end takes &self, we still do the autoderef step (just as 200 // find in the end takes &self, we still do the autoderef step (just as
189 // rustc does an autoderef and then autoref again). 201 // rustc does an autoderef and then autoref again).
190 let environment = TraitEnvironment::lower(db, resolver); 202 let ty = InEnvironment { value: ty.clone(), environment: env.clone() };
191 let ty = InEnvironment { value: ty.clone(), environment };
192 let krate = resolver.krate()?;
193 203
194 // We have to be careful about the order we're looking at candidates 204 // We have to be careful about the order we're looking at candidates
195 // in here. Consider the case where we're resolving `x.clone()` 205 // in here. Consider the case where we're resolving `x.clone()`
@@ -209,7 +219,9 @@ pub fn iterate_method_candidates<T>(
209 if let Some(result) = iterate_method_candidates_with_autoref( 219 if let Some(result) = iterate_method_candidates_with_autoref(
210 &deref_chain[i..], 220 &deref_chain[i..],
211 db, 221 db,
212 resolver, 222 env.clone(),
223 krate,
224 traits_in_scope,
213 name, 225 name,
214 &mut callback, 226 &mut callback,
215 ) { 227 ) {
@@ -220,7 +232,15 @@ pub fn iterate_method_candidates<T>(
220 } 232 }
221 LookupMode::Path => { 233 LookupMode::Path => {
222 // No autoderef for path lookups 234 // No autoderef for path lookups
223 iterate_method_candidates_for_self_ty(&ty, db, resolver, name, &mut callback) 235 iterate_method_candidates_for_self_ty(
236 &ty,
237 db,
238 env,
239 krate,
240 traits_in_scope,
241 name,
242 &mut callback,
243 )
224 } 244 }
225 } 245 }
226} 246}
@@ -228,7 +248,9 @@ pub fn iterate_method_candidates<T>(
228fn iterate_method_candidates_with_autoref<T>( 248fn iterate_method_candidates_with_autoref<T>(
229 deref_chain: &[Canonical<Ty>], 249 deref_chain: &[Canonical<Ty>],
230 db: &impl HirDatabase, 250 db: &impl HirDatabase,
231 resolver: &Resolver, 251 env: Arc<TraitEnvironment>,
252 krate: CrateId,
253 traits_in_scope: &FxHashSet<TraitId>,
232 name: Option<&Name>, 254 name: Option<&Name>,
233 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, 255 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
234) -> Option<T> { 256) -> Option<T> {
@@ -236,7 +258,9 @@ fn iterate_method_candidates_with_autoref<T>(
236 &deref_chain[0], 258 &deref_chain[0],
237 &deref_chain[1..], 259 &deref_chain[1..],
238 db, 260 db,
239 resolver, 261 env.clone(),
262 krate,
263 &traits_in_scope,
240 name, 264 name,
241 &mut callback, 265 &mut callback,
242 ) { 266 ) {
@@ -250,7 +274,9 @@ fn iterate_method_candidates_with_autoref<T>(
250 &refed, 274 &refed,
251 deref_chain, 275 deref_chain,
252 db, 276 db,
253 resolver, 277 env.clone(),
278 krate,
279 &traits_in_scope,
254 name, 280 name,
255 &mut callback, 281 &mut callback,
256 ) { 282 ) {
@@ -264,7 +290,9 @@ fn iterate_method_candidates_with_autoref<T>(
264 &ref_muted, 290 &ref_muted,
265 deref_chain, 291 deref_chain,
266 db, 292 db,
267 resolver, 293 env.clone(),
294 krate,
295 &traits_in_scope,
268 name, 296 name,
269 &mut callback, 297 &mut callback,
270 ) { 298 ) {
@@ -277,14 +305,15 @@ fn iterate_method_candidates_by_receiver<T>(
277 receiver_ty: &Canonical<Ty>, 305 receiver_ty: &Canonical<Ty>,
278 rest_of_deref_chain: &[Canonical<Ty>], 306 rest_of_deref_chain: &[Canonical<Ty>],
279 db: &impl HirDatabase, 307 db: &impl HirDatabase,
280 resolver: &Resolver, 308 env: Arc<TraitEnvironment>,
309 krate: CrateId,
310 traits_in_scope: &FxHashSet<TraitId>,
281 name: Option<&Name>, 311 name: Option<&Name>,
282 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, 312 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
283) -> Option<T> { 313) -> Option<T> {
284 // We're looking for methods with *receiver* type receiver_ty. These could 314 // We're looking for methods with *receiver* type receiver_ty. These could
285 // be found in any of the derefs of receiver_ty, so we have to go through 315 // be found in any of the derefs of receiver_ty, so we have to go through
286 // that. 316 // that.
287 let krate = resolver.krate()?;
288 for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) { 317 for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) {
289 if let Some(result) = 318 if let Some(result) =
290 iterate_inherent_methods(self_ty, db, name, Some(receiver_ty), krate, &mut callback) 319 iterate_inherent_methods(self_ty, db, name, Some(receiver_ty), krate, &mut callback)
@@ -296,7 +325,9 @@ fn iterate_method_candidates_by_receiver<T>(
296 if let Some(result) = iterate_trait_method_candidates( 325 if let Some(result) = iterate_trait_method_candidates(
297 self_ty, 326 self_ty,
298 db, 327 db,
299 resolver, 328 env.clone(),
329 krate,
330 &traits_in_scope,
300 name, 331 name,
301 Some(receiver_ty), 332 Some(receiver_ty),
302 &mut callback, 333 &mut callback,
@@ -310,17 +341,25 @@ fn iterate_method_candidates_by_receiver<T>(
310fn iterate_method_candidates_for_self_ty<T>( 341fn iterate_method_candidates_for_self_ty<T>(
311 self_ty: &Canonical<Ty>, 342 self_ty: &Canonical<Ty>,
312 db: &impl HirDatabase, 343 db: &impl HirDatabase,
313 resolver: &Resolver, 344 env: Arc<TraitEnvironment>,
345 krate: CrateId,
346 traits_in_scope: &FxHashSet<TraitId>,
314 name: Option<&Name>, 347 name: Option<&Name>,
315 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, 348 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
316) -> Option<T> { 349) -> Option<T> {
317 let krate = resolver.krate()?;
318 if let Some(result) = iterate_inherent_methods(self_ty, db, name, None, krate, &mut callback) { 350 if let Some(result) = iterate_inherent_methods(self_ty, db, name, None, krate, &mut callback) {
319 return Some(result); 351 return Some(result);
320 } 352 }
321 if let Some(result) = 353 if let Some(result) = iterate_trait_method_candidates(
322 iterate_trait_method_candidates(self_ty, db, resolver, name, None, &mut callback) 354 self_ty,
323 { 355 db,
356 env,
357 krate,
358 traits_in_scope,
359 name,
360 None,
361 &mut callback,
362 ) {
324 return Some(result); 363 return Some(result);
325 } 364 }
326 None 365 None
@@ -329,14 +368,13 @@ fn iterate_method_candidates_for_self_ty<T>(
329fn iterate_trait_method_candidates<T>( 368fn iterate_trait_method_candidates<T>(
330 self_ty: &Canonical<Ty>, 369 self_ty: &Canonical<Ty>,
331 db: &impl HirDatabase, 370 db: &impl HirDatabase,
332 resolver: &Resolver, 371 env: Arc<TraitEnvironment>,
372 krate: CrateId,
373 traits_in_scope: &FxHashSet<TraitId>,
333 name: Option<&Name>, 374 name: Option<&Name>,
334 receiver_ty: Option<&Canonical<Ty>>, 375 receiver_ty: Option<&Canonical<Ty>>,
335 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, 376 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
336) -> Option<T> { 377) -> Option<T> {
337 let krate = resolver.krate()?;
338 // FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that)
339 let env = TraitEnvironment::lower(db, resolver);
340 // if ty is `impl Trait` or `dyn Trait`, the trait doesn't need to be in scope 378 // if ty is `impl Trait` or `dyn Trait`, the trait doesn't need to be in scope
341 let inherent_trait = self_ty.value.inherent_trait().into_iter(); 379 let inherent_trait = self_ty.value.inherent_trait().into_iter();
342 // if we have `T: Trait` in the param env, the trait doesn't need to be in scope 380 // if we have `T: Trait` in the param env, the trait doesn't need to be in scope
@@ -344,8 +382,7 @@ fn iterate_trait_method_candidates<T>(
344 .trait_predicates_for_self_ty(&self_ty.value) 382 .trait_predicates_for_self_ty(&self_ty.value)
345 .map(|tr| tr.trait_) 383 .map(|tr| tr.trait_)
346 .flat_map(|t| all_super_traits(db, t)); 384 .flat_map(|t| all_super_traits(db, t));
347 let traits = 385 let traits = inherent_trait.chain(traits_from_env).chain(traits_in_scope.iter().copied());
348 inherent_trait.chain(traits_from_env).chain(resolver.traits_in_scope(db).into_iter());
349 'traits: for t in traits { 386 'traits: for t in traits {
350 let data = db.trait_data(t); 387 let data = db.trait_data(t);
351 388
@@ -465,7 +502,7 @@ fn transform_receiver_ty(
465pub fn implements_trait( 502pub fn implements_trait(
466 ty: &Canonical<Ty>, 503 ty: &Canonical<Ty>,
467 db: &impl HirDatabase, 504 db: &impl HirDatabase,
468 resolver: &Resolver, 505 env: Arc<TraitEnvironment>,
469 krate: CrateId, 506 krate: CrateId,
470 trait_: TraitId, 507 trait_: TraitId,
471) -> bool { 508) -> bool {
@@ -474,7 +511,6 @@ pub fn implements_trait(
474 // anyway, but currently Chalk doesn't implement `dyn/impl Trait` yet 511 // anyway, but currently Chalk doesn't implement `dyn/impl Trait` yet
475 return true; 512 return true;
476 } 513 }
477 let env = TraitEnvironment::lower(db, resolver);
478 let goal = generic_implements_goal(db, env, trait_, ty.clone()); 514 let goal = generic_implements_goal(db, env, trait_, ty.clone());
479 let solution = db.trait_solve(krate.into(), goal); 515 let solution = db.trait_solve(krate.into(), goal);
480 516
diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs
index 9d09d93a7..652420ea8 100644
--- a/crates/ra_hir_ty/src/tests/macros.rs
+++ b/crates/ra_hir_ty/src/tests/macros.rs
@@ -374,7 +374,7 @@ fn main() {
374} 374}
375"#), 375"#),
376 @r###" 376 @r###"
377 ![0; 1) '6': i32 377 ![0; 1) '0': i32
378 [64; 88) '{ ...!(); }': () 378 [64; 88) '{ ...!(); }': ()
379 [74; 75) 'x': i32 379 [74; 75) 'x': i32
380 "### 380 "###
@@ -412,7 +412,7 @@ fn main() {
412} 412}
413"#), 413"#),
414 @r###" 414 @r###"
415 ![0; 2) '13': i32 415 ![0; 1) '0': i32
416 [66; 92) '{ ...!(); }': () 416 [66; 92) '{ ...!(); }': ()
417 [76; 77) 'x': i32 417 [76; 77) 'x': i32
418 "### 418 "###
diff --git a/crates/ra_hir_ty/src/traits.rs b/crates/ra_hir_ty/src/traits.rs
index c4dc857bc..4aabd66dc 100644
--- a/crates/ra_hir_ty/src/traits.rs
+++ b/crates/ra_hir_ty/src/traits.rs
@@ -1,10 +1,12 @@
1//! Trait solving using Chalk. 1//! Trait solving using Chalk.
2use std::sync::{Arc, Mutex}; 2use std::{
3 panic,
4 sync::{Arc, Mutex},
5};
3 6
4use chalk_ir::cast::Cast; 7use chalk_ir::cast::Cast;
5use hir_def::{expr::ExprId, DefWithBodyId, ImplId, TraitId, TypeAliasId}; 8use hir_def::{expr::ExprId, DefWithBodyId, ImplId, TraitId, TypeAliasId};
6use log::debug; 9use ra_db::{impl_intern_key, salsa, Canceled, CrateId};
7use ra_db::{impl_intern_key, salsa, CrateId};
8use ra_prof::profile; 10use ra_prof::profile;
9use rustc_hash::FxHashSet; 11use rustc_hash::FxHashSet;
10 12
@@ -39,7 +41,7 @@ impl TraitSolver {
39 goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal<TypeFamily>>>, 41 goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal<TypeFamily>>>,
40 ) -> Option<chalk_solve::Solution<TypeFamily>> { 42 ) -> Option<chalk_solve::Solution<TypeFamily>> {
41 let context = ChalkContext { db, krate: self.krate }; 43 let context = ChalkContext { db, krate: self.krate };
42 debug!("solve goal: {:?}", goal); 44 log::debug!("solve goal: {:?}", goal);
43 let mut solver = match self.inner.lock() { 45 let mut solver = match self.inner.lock() {
44 Ok(it) => it, 46 Ok(it) => it,
45 // Our cancellation works via unwinding, but, as chalk is not 47 // Our cancellation works via unwinding, but, as chalk is not
@@ -47,8 +49,28 @@ impl TraitSolver {
47 // Ideally, we should also make chalk panic-safe. 49 // Ideally, we should also make chalk panic-safe.
48 Err(_) => ra_db::Canceled::throw(), 50 Err(_) => ra_db::Canceled::throw(),
49 }; 51 };
50 let solution = solver.solve(&context, goal); 52
51 debug!("solve({:?}) => {:?}", goal, solution); 53 let solution = panic::catch_unwind({
54 let solver = panic::AssertUnwindSafe(&mut solver);
55 let context = panic::AssertUnwindSafe(&context);
56 move || solver.0.solve(context.0, goal)
57 });
58
59 let solution = match solution {
60 Ok(it) => it,
61 Err(err) => {
62 if err.downcast_ref::<Canceled>().is_some() {
63 panic::resume_unwind(err)
64 } else {
65 log::error!("chalk panicked :-(");
66 // Reset the solver, as it is not panic-safe.
67 *solver = create_chalk_solver();
68 None
69 }
70 }
71 };
72
73 log::debug!("solve({:?}) => {:?}", goal, solution);
52 solution 74 solution
53 } 75 }
54} 76}
@@ -70,9 +92,13 @@ pub(crate) fn trait_solver_query(
70) -> TraitSolver { 92) -> TraitSolver {
71 db.salsa_runtime().report_untracked_read(); 93 db.salsa_runtime().report_untracked_read();
72 // krate parameter is just so we cache a unique solver per crate 94 // krate parameter is just so we cache a unique solver per crate
95 log::debug!("Creating new solver for crate {:?}", krate);
96 TraitSolver { krate, inner: Arc::new(Mutex::new(create_chalk_solver())) }
97}
98
99fn create_chalk_solver() -> chalk_solve::Solver<TypeFamily> {
73 let solver_choice = chalk_solve::SolverChoice::SLG { max_size: CHALK_SOLVER_MAX_SIZE }; 100 let solver_choice = chalk_solve::SolverChoice::SLG { max_size: CHALK_SOLVER_MAX_SIZE };
74 debug!("Creating new solver for crate {:?}", krate); 101 solver_choice.into_solver()
75 TraitSolver { krate, inner: Arc::new(Mutex::new(solver_choice.into_solver())) }
76} 102}
77 103
78/// Collects impls for the given trait in the whole dependency tree of `krate`. 104/// Collects impls for the given trait in the whole dependency tree of `krate`.
@@ -181,7 +207,7 @@ pub(crate) fn trait_solve_query(
181 goal: Canonical<InEnvironment<Obligation>>, 207 goal: Canonical<InEnvironment<Obligation>>,
182) -> Option<Solution> { 208) -> Option<Solution> {
183 let _p = profile("trait_solve_query"); 209 let _p = profile("trait_solve_query");
184 debug!("trait_solve_query({})", goal.value.value.display(db)); 210 log::debug!("trait_solve_query({})", goal.value.value.display(db));
185 211
186 if let Obligation::Projection(pred) = &goal.value.value { 212 if let Obligation::Projection(pred) = &goal.value.value {
187 if let Ty::Bound(_) = &pred.projection_ty.parameters[0] { 213 if let Ty::Bound(_) = &pred.projection_ty.parameters[0] {