diff options
-rw-r--r-- | crates/ra_hir/src/source_binder.rs | 10 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/autoderef.rs | 45 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 3 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer/coerce.rs | 13 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer/expr.rs | 40 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 21 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 11 |
7 files changed, 85 insertions, 58 deletions
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 31390bb7f..b4f0e81d3 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -26,7 +26,10 @@ use ra_syntax::{ | |||
26 | use crate::{ | 26 | use crate::{ |
27 | db::HirDatabase, | 27 | db::HirDatabase, |
28 | expr::{BodySourceMap, ExprScopes, ScopeId}, | 28 | expr::{BodySourceMap, ExprScopes, ScopeId}, |
29 | ty::method_resolution::{self, implements_trait}, | 29 | ty::{ |
30 | method_resolution::{self, implements_trait}, | ||
31 | TraitEnvironment, | ||
32 | }, | ||
30 | Adt, AssocItem, Const, DefWithBody, Either, Enum, EnumVariant, FromSource, Function, | 33 | Adt, AssocItem, Const, DefWithBody, Either, Enum, EnumVariant, FromSource, Function, |
31 | GenericParam, Local, MacroDef, Name, Path, ScopeDef, Static, Struct, Trait, Ty, TypeAlias, | 34 | GenericParam, Local, MacroDef, Name, Path, ScopeDef, Static, Struct, Trait, Ty, TypeAlias, |
32 | }; | 35 | }; |
@@ -408,7 +411,10 @@ impl SourceAnalyzer { | |||
408 | // There should be no inference vars in types passed here | 411 | // There should be no inference vars in types passed here |
409 | // FIXME check that? | 412 | // FIXME check that? |
410 | let canonical = crate::ty::Canonical { value: ty, num_vars: 0 }; | 413 | let canonical = crate::ty::Canonical { value: ty, num_vars: 0 }; |
411 | crate::ty::autoderef(db, &self.resolver, canonical).map(|canonical| canonical.value) | 414 | let krate = self.resolver.krate(); |
415 | let environment = TraitEnvironment::lower(db, &self.resolver); | ||
416 | let ty = crate::ty::InEnvironment { value: canonical, environment }; | ||
417 | crate::ty::autoderef(db, krate, ty).map(|canonical| canonical.value) | ||
412 | } | 418 | } |
413 | 419 | ||
414 | /// Checks that particular type `ty` implements `std::future::Future`. | 420 | /// Checks that particular type `ty` implements `std::future::Future`. |
diff --git a/crates/ra_hir/src/ty/autoderef.rs b/crates/ra_hir/src/ty/autoderef.rs index 41c99d227..44547197c 100644 --- a/crates/ra_hir/src/ty/autoderef.rs +++ b/crates/ra_hir/src/ty/autoderef.rs | |||
@@ -5,42 +5,49 @@ | |||
5 | 5 | ||
6 | use std::iter::successors; | 6 | use std::iter::successors; |
7 | 7 | ||
8 | use hir_def::{lang_item::LangItemTarget, resolver::Resolver}; | 8 | use hir_def::lang_item::LangItemTarget; |
9 | use hir_expand::name; | 9 | use hir_expand::name; |
10 | use log::{info, warn}; | 10 | use log::{info, warn}; |
11 | use ra_db::CrateId; | ||
11 | 12 | ||
12 | use crate::{db::HirDatabase, Trait}; | 13 | use crate::{db::HirDatabase, Trait}; |
13 | 14 | ||
14 | use super::{traits::Solution, Canonical, Substs, Ty, TypeWalk}; | 15 | use super::{ |
16 | traits::{InEnvironment, Solution}, | ||
17 | Canonical, Substs, Ty, TypeWalk, | ||
18 | }; | ||
15 | 19 | ||
16 | const AUTODEREF_RECURSION_LIMIT: usize = 10; | 20 | const AUTODEREF_RECURSION_LIMIT: usize = 10; |
17 | 21 | ||
18 | pub(crate) fn autoderef<'a>( | 22 | pub(crate) fn autoderef<'a>( |
19 | db: &'a impl HirDatabase, | 23 | db: &'a impl HirDatabase, |
20 | resolver: &'a Resolver, | 24 | krate: Option<CrateId>, |
21 | ty: Canonical<Ty>, | 25 | ty: InEnvironment<Canonical<Ty>>, |
22 | ) -> impl Iterator<Item = Canonical<Ty>> + 'a { | 26 | ) -> impl Iterator<Item = Canonical<Ty>> + 'a { |
23 | successors(Some(ty), move |ty| deref(db, resolver, ty)).take(AUTODEREF_RECURSION_LIMIT) | 27 | let InEnvironment { value: ty, environment } = ty; |
28 | successors(Some(ty), move |ty| { | ||
29 | deref(db, krate?, InEnvironment { value: ty, environment: environment.clone() }) | ||
30 | }) | ||
31 | .take(AUTODEREF_RECURSION_LIMIT) | ||
24 | } | 32 | } |
25 | 33 | ||
26 | pub(crate) fn deref( | 34 | pub(crate) fn deref( |
27 | db: &impl HirDatabase, | 35 | db: &impl HirDatabase, |
28 | resolver: &Resolver, | 36 | krate: CrateId, |
29 | ty: &Canonical<Ty>, | 37 | ty: InEnvironment<&Canonical<Ty>>, |
30 | ) -> Option<Canonical<Ty>> { | 38 | ) -> Option<Canonical<Ty>> { |
31 | if let Some(derefed) = ty.value.builtin_deref() { | 39 | if let Some(derefed) = ty.value.value.builtin_deref() { |
32 | Some(Canonical { value: derefed, num_vars: ty.num_vars }) | 40 | Some(Canonical { value: derefed, num_vars: ty.value.num_vars }) |
33 | } else { | 41 | } else { |
34 | deref_by_trait(db, resolver, ty) | 42 | deref_by_trait(db, krate, ty) |
35 | } | 43 | } |
36 | } | 44 | } |
37 | 45 | ||
38 | fn deref_by_trait( | 46 | fn deref_by_trait( |
39 | db: &impl HirDatabase, | 47 | db: &impl HirDatabase, |
40 | resolver: &Resolver, | 48 | krate: CrateId, |
41 | ty: &Canonical<Ty>, | 49 | ty: InEnvironment<&Canonical<Ty>>, |
42 | ) -> Option<Canonical<Ty>> { | 50 | ) -> Option<Canonical<Ty>> { |
43 | let krate = resolver.krate()?; | ||
44 | let deref_trait = match db.lang_item(krate.into(), "deref".into())? { | 51 | let deref_trait = match db.lang_item(krate.into(), "deref".into())? { |
45 | LangItemTarget::TraitId(t) => Trait::from(t), | 52 | LangItemTarget::TraitId(t) => Trait::from(t), |
46 | _ => return None, | 53 | _ => return None, |
@@ -56,10 +63,8 @@ fn deref_by_trait( | |||
56 | 63 | ||
57 | // FIXME make the Canonical handling nicer | 64 | // FIXME make the Canonical handling nicer |
58 | 65 | ||
59 | let env = super::lower::trait_env(db, resolver); | ||
60 | |||
61 | let parameters = Substs::build_for_generics(&generic_params) | 66 | let parameters = Substs::build_for_generics(&generic_params) |
62 | .push(ty.value.clone().shift_bound_vars(1)) | 67 | .push(ty.value.value.clone().shift_bound_vars(1)) |
63 | .build(); | 68 | .build(); |
64 | 69 | ||
65 | let projection = super::traits::ProjectionPredicate { | 70 | let projection = super::traits::ProjectionPredicate { |
@@ -69,9 +74,9 @@ fn deref_by_trait( | |||
69 | 74 | ||
70 | let obligation = super::Obligation::Projection(projection); | 75 | let obligation = super::Obligation::Projection(projection); |
71 | 76 | ||
72 | let in_env = super::traits::InEnvironment { value: obligation, environment: env }; | 77 | let in_env = InEnvironment { value: obligation, environment: ty.environment }; |
73 | 78 | ||
74 | let canonical = super::Canonical { num_vars: 1 + ty.num_vars, value: in_env }; | 79 | let canonical = super::Canonical { num_vars: 1 + ty.value.num_vars, value: in_env }; |
75 | 80 | ||
76 | let solution = db.trait_solve(krate.into(), canonical)?; | 81 | let solution = db.trait_solve(krate.into(), canonical)?; |
77 | 82 | ||
@@ -89,14 +94,14 @@ fn deref_by_trait( | |||
89 | // the case. | 94 | // the case. |
90 | for i in 1..vars.0.num_vars { | 95 | for i in 1..vars.0.num_vars { |
91 | if vars.0.value[i] != Ty::Bound((i - 1) as u32) { | 96 | if vars.0.value[i] != Ty::Bound((i - 1) as u32) { |
92 | warn!("complex solution for derefing {:?}: {:?}, ignoring", ty, solution); | 97 | warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.value, solution); |
93 | return None; | 98 | return None; |
94 | } | 99 | } |
95 | } | 100 | } |
96 | Some(Canonical { value: vars.0.value[0].clone(), num_vars: vars.0.num_vars }) | 101 | Some(Canonical { value: vars.0.value[0].clone(), num_vars: vars.0.num_vars }) |
97 | } | 102 | } |
98 | Solution::Ambig(_) => { | 103 | Solution::Ambig(_) => { |
99 | info!("Ambiguous solution for derefing {:?}: {:?}", ty, solution); | 104 | info!("Ambiguous solution for derefing {:?}: {:?}", ty.value, solution); |
100 | None | 105 | None |
101 | } | 106 | } |
102 | } | 107 | } |
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index ddc7d262a..6fd00d457 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -34,7 +34,6 @@ use ra_prof::profile; | |||
34 | use test_utils::tested_by; | 34 | use test_utils::tested_by; |
35 | 35 | ||
36 | use super::{ | 36 | use super::{ |
37 | lower, | ||
38 | traits::{Guidance, Obligation, ProjectionPredicate, Solution}, | 37 | traits::{Guidance, Obligation, ProjectionPredicate, Solution}, |
39 | ApplicationTy, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypableDef, | 38 | ApplicationTy, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypableDef, |
40 | TypeCtor, TypeWalk, Uncertain, | 39 | TypeCtor, TypeWalk, Uncertain, |
@@ -216,7 +215,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
216 | var_unification_table: InPlaceUnificationTable::new(), | 215 | var_unification_table: InPlaceUnificationTable::new(), |
217 | obligations: Vec::default(), | 216 | obligations: Vec::default(), |
218 | return_ty: Ty::Unknown, // set in collect_fn_signature | 217 | return_ty: Ty::Unknown, // set in collect_fn_signature |
219 | trait_env: lower::trait_env(db, &resolver), | 218 | trait_env: TraitEnvironment::lower(db, &resolver), |
220 | coerce_unsized_map: Self::init_coerce_unsized_map(db, &resolver), | 219 | coerce_unsized_map: Self::init_coerce_unsized_map(db, &resolver), |
221 | db, | 220 | db, |
222 | owner, | 221 | owner, |
diff --git a/crates/ra_hir/src/ty/infer/coerce.rs b/crates/ra_hir/src/ty/infer/coerce.rs index 54765da35..4b53bba73 100644 --- a/crates/ra_hir/src/ty/infer/coerce.rs +++ b/crates/ra_hir/src/ty/infer/coerce.rs | |||
@@ -14,7 +14,7 @@ use crate::{ | |||
14 | Adt, Mutability, | 14 | Adt, Mutability, |
15 | }; | 15 | }; |
16 | 16 | ||
17 | use super::{InferTy, InferenceContext, TypeVarValue}; | 17 | use super::{InEnvironment, InferTy, InferenceContext, TypeVarValue}; |
18 | 18 | ||
19 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { | 19 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { |
20 | /// Unify two types, but may coerce the first one to the second one | 20 | /// Unify two types, but may coerce the first one to the second one |
@@ -320,9 +320,14 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
320 | let canonicalized = self.canonicalizer().canonicalize_ty(from_ty.clone()); | 320 | let canonicalized = self.canonicalizer().canonicalize_ty(from_ty.clone()); |
321 | let to_ty = self.resolve_ty_shallow(&to_ty); | 321 | let to_ty = self.resolve_ty_shallow(&to_ty); |
322 | // FIXME: Auto DerefMut | 322 | // FIXME: Auto DerefMut |
323 | for derefed_ty in | 323 | for derefed_ty in autoderef::autoderef( |
324 | autoderef::autoderef(self.db, &self.resolver.clone(), canonicalized.value.clone()) | 324 | self.db, |
325 | { | 325 | self.resolver.krate(), |
326 | InEnvironment { | ||
327 | value: canonicalized.value.clone(), | ||
328 | environment: self.trait_env.clone(), | ||
329 | }, | ||
330 | ) { | ||
326 | let derefed_ty = canonicalized.decanonicalize_ty(derefed_ty.value); | 331 | let derefed_ty = canonicalized.decanonicalize_ty(derefed_ty.value); |
327 | match (&*self.resolve_ty_shallow(&derefed_ty), &*to_ty) { | 332 | match (&*self.resolve_ty_shallow(&derefed_ty), &*to_ty) { |
328 | // Stop when constructor matches. | 333 | // Stop when constructor matches. |
diff --git a/crates/ra_hir/src/ty/infer/expr.rs b/crates/ra_hir/src/ty/infer/expr.rs index 663ff9435..194e55819 100644 --- a/crates/ra_hir/src/ty/infer/expr.rs +++ b/crates/ra_hir/src/ty/infer/expr.rs | |||
@@ -15,9 +15,9 @@ use crate::{ | |||
15 | db::HirDatabase, | 15 | db::HirDatabase, |
16 | expr::{Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp}, | 16 | expr::{Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp}, |
17 | ty::{ | 17 | ty::{ |
18 | autoderef, method_resolution, op, CallableDef, InferTy, IntTy, Mutability, Namespace, | 18 | autoderef, method_resolution, op, traits::InEnvironment, CallableDef, InferTy, IntTy, |
19 | Obligation, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk, | 19 | Mutability, Namespace, Obligation, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, |
20 | Uncertain, | 20 | TypeCtor, TypeWalk, Uncertain, |
21 | }, | 21 | }, |
22 | Adt, Name, | 22 | Adt, Name, |
23 | }; | 23 | }; |
@@ -245,8 +245,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
245 | let canonicalized = self.canonicalizer().canonicalize_ty(receiver_ty); | 245 | let canonicalized = self.canonicalizer().canonicalize_ty(receiver_ty); |
246 | let ty = autoderef::autoderef( | 246 | let ty = autoderef::autoderef( |
247 | self.db, | 247 | self.db, |
248 | &self.resolver.clone(), | 248 | self.resolver.krate(), |
249 | canonicalized.value.clone(), | 249 | InEnvironment { |
250 | value: canonicalized.value.clone(), | ||
251 | environment: self.trait_env.clone(), | ||
252 | }, | ||
250 | ) | 253 | ) |
251 | .find_map(|derefed_ty| match canonicalized.decanonicalize_ty(derefed_ty.value) { | 254 | .find_map(|derefed_ty| match canonicalized.decanonicalize_ty(derefed_ty.value) { |
252 | Ty::Apply(a_ty) => match a_ty.ctor { | 255 | Ty::Apply(a_ty) => match a_ty.ctor { |
@@ -337,16 +340,25 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
337 | Expr::UnaryOp { expr, op } => { | 340 | Expr::UnaryOp { expr, op } => { |
338 | let inner_ty = self.infer_expr(*expr, &Expectation::none()); | 341 | let inner_ty = self.infer_expr(*expr, &Expectation::none()); |
339 | match op { | 342 | match op { |
340 | UnaryOp::Deref => { | 343 | UnaryOp::Deref => match self.resolver.krate() { |
341 | let canonicalized = self.canonicalizer().canonicalize_ty(inner_ty); | 344 | Some(krate) => { |
342 | if let Some(derefed_ty) = | 345 | let canonicalized = self.canonicalizer().canonicalize_ty(inner_ty); |
343 | autoderef::deref(self.db, &self.resolver, &canonicalized.value) | 346 | match autoderef::deref( |
344 | { | 347 | self.db, |
345 | canonicalized.decanonicalize_ty(derefed_ty.value) | 348 | krate, |
346 | } else { | 349 | InEnvironment { |
347 | Ty::Unknown | 350 | value: &canonicalized.value, |
351 | environment: self.trait_env.clone(), | ||
352 | }, | ||
353 | ) { | ||
354 | Some(derefed_ty) => { | ||
355 | canonicalized.decanonicalize_ty(derefed_ty.value) | ||
356 | } | ||
357 | None => Ty::Unknown, | ||
358 | } | ||
348 | } | 359 | } |
349 | } | 360 | None => Ty::Unknown, |
361 | }, | ||
350 | UnaryOp::Neg => { | 362 | UnaryOp::Neg => { |
351 | match &inner_ty { | 363 | match &inner_ty { |
352 | Ty::Apply(a_ty) => match a_ty.ctor { | 364 | Ty::Apply(a_ty) => match a_ty.ctor { |
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index a39beb2a0..b76929501 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs | |||
@@ -19,8 +19,8 @@ use hir_def::{ | |||
19 | use ra_arena::map::ArenaMap; | 19 | use ra_arena::map::ArenaMap; |
20 | 20 | ||
21 | use super::{ | 21 | use super::{ |
22 | FnSig, GenericPredicate, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, | 22 | FnSig, GenericPredicate, ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef, |
23 | TypeWalk, | 23 | Ty, TypeCtor, TypeWalk, |
24 | }; | 24 | }; |
25 | use crate::{ | 25 | use crate::{ |
26 | db::HirDatabase, | 26 | db::HirDatabase, |
@@ -591,16 +591,15 @@ pub(crate) fn generic_predicates_for_param_query( | |||
591 | .collect() | 591 | .collect() |
592 | } | 592 | } |
593 | 593 | ||
594 | pub(crate) fn trait_env( | 594 | impl TraitEnvironment { |
595 | db: &impl HirDatabase, | 595 | pub(crate) fn lower(db: &impl HirDatabase, resolver: &Resolver) -> Arc<TraitEnvironment> { |
596 | resolver: &Resolver, | 596 | let predicates = resolver |
597 | ) -> Arc<super::TraitEnvironment> { | 597 | .where_predicates_in_scope() |
598 | let predicates = resolver | 598 | .flat_map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred)) |
599 | .where_predicates_in_scope() | 599 | .collect::<Vec<_>>(); |
600 | .flat_map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred)) | ||
601 | .collect::<Vec<_>>(); | ||
602 | 600 | ||
603 | Arc::new(super::TraitEnvironment { predicates }) | 601 | Arc::new(TraitEnvironment { predicates }) |
602 | } | ||
604 | } | 603 | } |
605 | 604 | ||
606 | /// Resolve the where clause(s) of an item with generics. | 605 | /// Resolve the where clause(s) of an item with generics. |
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index caa5f5f74..f7905b5ff 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs | |||
@@ -15,7 +15,7 @@ use crate::{ | |||
15 | AssocItem, Crate, Function, ImplBlock, Module, Mutability, Name, Trait, | 15 | AssocItem, Crate, Function, ImplBlock, Module, Mutability, Name, Trait, |
16 | }; | 16 | }; |
17 | 17 | ||
18 | use super::{autoderef, lower, Canonical, InEnvironment, TraitEnvironment, TraitRef}; | 18 | use super::{autoderef, Canonical, InEnvironment, TraitEnvironment, TraitRef}; |
19 | 19 | ||
20 | /// This is used as a key for indexing impls. | 20 | /// This is used as a key for indexing impls. |
21 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | 21 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] |
@@ -179,8 +179,9 @@ pub(crate) fn iterate_method_candidates<T>( | |||
179 | // Also note that when we've got a receiver like &S, even if the method we | 179 | // Also note that when we've got a receiver like &S, even if the method we |
180 | // find in the end takes &self, we still do the autoderef step (just as | 180 | // find in the end takes &self, we still do the autoderef step (just as |
181 | // rustc does an autoderef and then autoref again). | 181 | // rustc does an autoderef and then autoref again). |
182 | 182 | let environment = TraitEnvironment::lower(db, resolver); | |
183 | for derefed_ty in autoderef::autoderef(db, resolver, ty.clone()) { | 183 | let ty = InEnvironment { value: ty.clone(), environment }; |
184 | for derefed_ty in autoderef::autoderef(db, resolver.krate(), ty) { | ||
184 | if let Some(result) = iterate_inherent_methods( | 185 | if let Some(result) = iterate_inherent_methods( |
185 | &derefed_ty, | 186 | &derefed_ty, |
186 | db, | 187 | db, |
@@ -230,7 +231,7 @@ fn iterate_trait_method_candidates<T>( | |||
230 | ) -> Option<T> { | 231 | ) -> Option<T> { |
231 | let krate = resolver.krate()?; | 232 | let krate = resolver.krate()?; |
232 | // FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that) | 233 | // FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that) |
233 | let env = lower::trait_env(db, resolver); | 234 | let env = TraitEnvironment::lower(db, resolver); |
234 | // if ty is `impl Trait` or `dyn Trait`, the trait doesn't need to be in scope | 235 | // if ty is `impl Trait` or `dyn Trait`, the trait doesn't need to be in scope |
235 | let inherent_trait = ty.value.inherent_trait().into_iter(); | 236 | let inherent_trait = ty.value.inherent_trait().into_iter(); |
236 | // if we have `T: Trait` in the param env, the trait doesn't need to be in scope | 237 | // if we have `T: Trait` in the param env, the trait doesn't need to be in scope |
@@ -324,7 +325,7 @@ pub(crate) fn implements_trait( | |||
324 | // anyway, but currently Chalk doesn't implement `dyn/impl Trait` yet | 325 | // anyway, but currently Chalk doesn't implement `dyn/impl Trait` yet |
325 | return true; | 326 | return true; |
326 | } | 327 | } |
327 | let env = lower::trait_env(db, resolver); | 328 | let env = TraitEnvironment::lower(db, resolver); |
328 | let goal = generic_implements_goal(db, env, trait_, ty.clone()); | 329 | let goal = generic_implements_goal(db, env, trait_, ty.clone()); |
329 | let solution = db.trait_solve(krate, goal); | 330 | let solution = db.trait_solve(krate, goal); |
330 | 331 | ||