aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src/infer
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-02-09 11:35:08 +0000
committerGitHub <[email protected]>2020-02-09 11:35:08 +0000
commit01836a0f35fa163025c64cabe1d0c34bb4f69c92 (patch)
treeaa1a3cf97173b2885f8b6d23002c73196f9a0b61 /crates/ra_hir_ty/src/infer
parent961a69b88f923d4477ca4f746a793217a0cc8576 (diff)
parenteefe02ce6e1750b771cf99125429358e87485745 (diff)
Merge #3050
3050: Refactor type parameters, implement argument position impl trait r=matklad a=flodiebold I wanted to implement APIT by lowering to type parameters because we need to do that anyway for correctness and don't need Chalk support for it; this grew into some more wide-ranging refactoring of how type parameters are handled :sweat_smile: - use Ty::Bound instead of Ty::Param to represent polymorphism, and explicitly count binders. This gets us closer to Chalk's way of doing things, and means that we now only use Param as a placeholder for an unknown type, e.g. within a generic function. I.e. we're never using Param in a situation where we want to substitute it, and the method to do that is gone; `subst` now always works on bound variables. (This changes how the types of generic functions print; previously, you'd get something like `fn identity<i32>(T) -> T`, but now we display the substituted signature `fn identity<i32>(i32) -> i32`, which I think makes more sense.) - once we do this, it's more natural to represent `Param` by a globally unique ID; the use of indices was mostly to make substituting easier. This also means we fix the bug where `Param` loses its name when going through Chalk. - I would actually like to rename `Param` to `Placeholder` to better reflect its use and get closer to Chalk, but I'll leave that to a follow-up. - introduce a context for type lowering, to allow lowering `impl Trait` to different things depending on where we are. And since we have that, we can also lower type parameters directly to variables instead of placeholders. Also, we'll be able to use this later to collect diagnostics. - implement argument position impl trait by lowering it to type parameters. I've realized that this is necessary to correctly implement it; e.g. consider `fn foo(impl Display) -> impl Something`. It's observable that the return type of e.g. `foo(1u32)` unifies with itself, but doesn't unify with e.g. `foo(1i32)`; so the return type needs to be parameterized by the argument type. This fixes a few bugs as well: - type parameters 'losing' their name when they go through Chalk, as mentioned above (i.e. getting `[missing name]` somewhere) - impl trait not being considered as implementing the super traits (very noticeable for the `db` in RA) - the fact that argument impl trait was only turned into variables when the function got called caused type mismatches when the function was used as a value (fixes a few type mismatches in RA) The one thing I'm not so happy with here is how we're lowering `impl Trait` types to variables; since `TypeRef`s don't have an identity currently, we just count how many of them we have seen while going through the function signature. That's quite fragile though, since we have to do it while desugaring generics and while lowering the type signature, and in the exact same order in both cases. We could consider either giving only `TypeRef::ImplTrait` a local id, or maybe just giving all `TypeRef`s an identity after all (we talked about this before)... Follow-up tasks: - handle return position impl trait; we basically need to create a variable and some trait obligations for that variable - rename `Param` to `Placeholder` Co-authored-by: Florian Diebold <[email protected]> Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_hir_ty/src/infer')
-rw-r--r--crates/ra_hir_ty/src/infer/coerce.rs18
-rw-r--r--crates/ra_hir_ty/src/infer/expr.rs24
-rw-r--r--crates/ra_hir_ty/src/infer/pat.rs7
-rw-r--r--crates/ra_hir_ty/src/infer/path.rs60
4 files changed, 46 insertions, 63 deletions
diff --git a/crates/ra_hir_ty/src/infer/coerce.rs b/crates/ra_hir_ty/src/infer/coerce.rs
index 83c0c2c3f..f68a1439f 100644
--- a/crates/ra_hir_ty/src/infer/coerce.rs
+++ b/crates/ra_hir_ty/src/infer/coerce.rs
@@ -57,8 +57,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
57 let trait_ref = db.impl_trait(impl_id)?; 57 let trait_ref = db.impl_trait(impl_id)?;
58 58
59 // `CoerseUnsized` has one generic parameter for the target type. 59 // `CoerseUnsized` has one generic parameter for the target type.
60 let cur_from_ty = trait_ref.substs.0.get(0)?; 60 let cur_from_ty = trait_ref.value.substs.0.get(0)?;
61 let cur_to_ty = trait_ref.substs.0.get(1)?; 61 let cur_to_ty = trait_ref.value.substs.0.get(1)?;
62 62
63 match (&cur_from_ty, cur_to_ty) { 63 match (&cur_from_ty, cur_to_ty) {
64 (ty_app!(ctor1, st1), ty_app!(ctor2, st2)) => { 64 (ty_app!(ctor1, st1), ty_app!(ctor2, st2)) => {
@@ -66,9 +66,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
66 // This works for smart-pointer-like coercion, which covers all impls from std. 66 // This works for smart-pointer-like coercion, which covers all impls from std.
67 st1.iter().zip(st2.iter()).enumerate().find_map(|(i, (ty1, ty2))| { 67 st1.iter().zip(st2.iter()).enumerate().find_map(|(i, (ty1, ty2))| {
68 match (ty1, ty2) { 68 match (ty1, ty2) {
69 (Ty::Param { idx: p1, .. }, Ty::Param { idx: p2, .. }) 69 (Ty::Bound(idx1), Ty::Bound(idx2)) if idx1 != idx2 => {
70 if p1 != p2 =>
71 {
72 Some(((*ctor1, *ctor2), i)) 70 Some(((*ctor1, *ctor2), i))
73 } 71 }
74 _ => None, 72 _ => None,
@@ -256,8 +254,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
256 let unsize_generic_index = { 254 let unsize_generic_index = {
257 let mut index = None; 255 let mut index = None;
258 let mut multiple_param = false; 256 let mut multiple_param = false;
259 field_tys[last_field_id].walk(&mut |ty| match ty { 257 field_tys[last_field_id].value.walk(&mut |ty| match ty {
260 &Ty::Param { idx, .. } => { 258 &Ty::Bound(idx) => {
261 if index.is_none() { 259 if index.is_none() {
262 index = Some(idx); 260 index = Some(idx);
263 } else if Some(idx) != index { 261 } else if Some(idx) != index {
@@ -276,10 +274,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
276 // Check other fields do not involve it. 274 // Check other fields do not involve it.
277 let mut multiple_used = false; 275 let mut multiple_used = false;
278 fields.for_each(|(field_id, _data)| { 276 fields.for_each(|(field_id, _data)| {
279 field_tys[field_id].walk(&mut |ty| match ty { 277 field_tys[field_id].value.walk(&mut |ty| match ty {
280 &Ty::Param { idx, .. } if idx == unsize_generic_index => { 278 &Ty::Bound(idx) if idx == unsize_generic_index => multiple_used = true,
281 multiple_used = true
282 }
283 _ => {} 279 _ => {}
284 }) 280 })
285 }); 281 });
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs
index 31259a01d..3c9c02d03 100644
--- a/crates/ra_hir_ty/src/infer/expr.rs
+++ b/crates/ra_hir_ty/src/infer/expr.rs
@@ -10,7 +10,7 @@ use hir_def::{
10 resolver::resolver_for_expr, 10 resolver::resolver_for_expr,
11 AdtId, AssocContainerId, Lookup, StructFieldId, 11 AdtId, AssocContainerId, Lookup, StructFieldId,
12}; 12};
13use hir_expand::name::{name, Name}; 13use hir_expand::name::Name;
14use ra_syntax::ast::RangeOp; 14use ra_syntax::ast::RangeOp;
15 15
16use crate::{ 16use crate::{
@@ -19,8 +19,8 @@ use crate::{
19 method_resolution, op, 19 method_resolution, op,
20 traits::InEnvironment, 20 traits::InEnvironment,
21 utils::{generics, variant_data, Generics}, 21 utils::{generics, variant_data, Generics},
22 ApplicationTy, CallableDef, InferTy, IntTy, Mutability, Obligation, Substs, TraitRef, Ty, 22 ApplicationTy, Binders, CallableDef, InferTy, IntTy, Mutability, Obligation, Substs, TraitRef,
23 TypeCtor, TypeWalk, Uncertain, 23 Ty, TypeCtor, Uncertain,
24}; 24};
25 25
26use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch}; 26use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch};
@@ -236,8 +236,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
236 self.result.record_field_resolutions.insert(field.expr, field_def); 236 self.result.record_field_resolutions.insert(field.expr, field_def);
237 } 237 }
238 let field_ty = field_def 238 let field_ty = field_def
239 .map_or(Ty::Unknown, |it| field_types[it.local_id].clone()) 239 .map_or(Ty::Unknown, |it| field_types[it.local_id].clone().subst(&substs));
240 .subst(&substs);
241 self.infer_expr_coerce(field.expr, &Expectation::has_type(field_ty)); 240 self.infer_expr_coerce(field.expr, &Expectation::has_type(field_ty));
242 } 241 }
243 if let Some(expr) = spread { 242 if let Some(expr) = spread {
@@ -588,10 +587,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
588 self.write_method_resolution(tgt_expr, func); 587 self.write_method_resolution(tgt_expr, func);
589 (ty, self.db.value_ty(func.into()), Some(generics(self.db, func.into()))) 588 (ty, self.db.value_ty(func.into()), Some(generics(self.db, func.into())))
590 } 589 }
591 None => (receiver_ty, Ty::Unknown, None), 590 None => (receiver_ty, Binders::new(0, Ty::Unknown), None),
592 }; 591 };
593 let substs = self.substs_for_method_call(def_generics, generic_args, &derefed_receiver_ty); 592 let substs = self.substs_for_method_call(def_generics, generic_args, &derefed_receiver_ty);
594 let method_ty = method_ty.apply_substs(substs); 593 let method_ty = method_ty.subst(&substs);
595 let method_ty = self.insert_type_vars(method_ty); 594 let method_ty = self.insert_type_vars(method_ty);
596 self.register_obligations_for_call(&method_ty); 595 self.register_obligations_for_call(&method_ty);
597 let (expected_receiver_ty, param_tys, ret_ty) = match method_ty.callable_sig(self.db) { 596 let (expected_receiver_ty, param_tys, ret_ty) = match method_ty.callable_sig(self.db) {
@@ -635,7 +634,6 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
635 continue; 634 continue;
636 } 635 }
637 636
638 let param_ty = self.insert_vars_for_impl_trait(param_ty);
639 let param_ty = self.normalize_associated_types_in(param_ty); 637 let param_ty = self.normalize_associated_types_in(param_ty);
640 self.infer_expr_coerce(arg, &Expectation::has_type(param_ty.clone())); 638 self.infer_expr_coerce(arg, &Expectation::has_type(param_ty.clone()));
641 } 639 }
@@ -648,13 +646,15 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
648 generic_args: Option<&GenericArgs>, 646 generic_args: Option<&GenericArgs>,
649 receiver_ty: &Ty, 647 receiver_ty: &Ty,
650 ) -> Substs { 648 ) -> Substs {
651 let (total_len, _parent_len, child_len) = 649 let (parent_params, self_params, type_params, impl_trait_params) =
652 def_generics.as_ref().map_or((0, 0, 0), |g| g.len_split()); 650 def_generics.as_ref().map_or((0, 0, 0, 0), |g| g.provenance_split());
651 assert_eq!(self_params, 0); // method shouldn't have another Self param
652 let total_len = parent_params + type_params + impl_trait_params;
653 let mut substs = Vec::with_capacity(total_len); 653 let mut substs = Vec::with_capacity(total_len);
654 // Parent arguments are unknown, except for the receiver type 654 // Parent arguments are unknown, except for the receiver type
655 if let Some(parent_generics) = def_generics.as_ref().map(|p| p.iter_parent()) { 655 if let Some(parent_generics) = def_generics.as_ref().map(|p| p.iter_parent()) {
656 for (_id, param) in parent_generics { 656 for (_id, param) in parent_generics {
657 if param.name == name![Self] { 657 if param.provenance == hir_def::generics::TypeParamProvenance::TraitSelf {
658 substs.push(receiver_ty.clone()); 658 substs.push(receiver_ty.clone());
659 } else { 659 } else {
660 substs.push(Ty::Unknown); 660 substs.push(Ty::Unknown);
@@ -664,7 +664,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
664 // handle provided type arguments 664 // handle provided type arguments
665 if let Some(generic_args) = generic_args { 665 if let Some(generic_args) = generic_args {
666 // if args are provided, it should be all of them, but we can't rely on that 666 // if args are provided, it should be all of them, but we can't rely on that
667 for arg in generic_args.args.iter().take(child_len) { 667 for arg in generic_args.args.iter().take(type_params) {
668 match arg { 668 match arg {
669 GenericArg::Type(type_ref) => { 669 GenericArg::Type(type_ref) => {
670 let ty = self.make_ty(type_ref); 670 let ty = self.make_ty(type_ref);
diff --git a/crates/ra_hir_ty/src/infer/pat.rs b/crates/ra_hir_ty/src/infer/pat.rs
index a14662884..e7283f24c 100644
--- a/crates/ra_hir_ty/src/infer/pat.rs
+++ b/crates/ra_hir_ty/src/infer/pat.rs
@@ -12,7 +12,7 @@ use hir_expand::name::Name;
12use test_utils::tested_by; 12use test_utils::tested_by;
13 13
14use super::{BindingMode, InferenceContext}; 14use super::{BindingMode, InferenceContext};
15use crate::{db::HirDatabase, utils::variant_data, Substs, Ty, TypeCtor, TypeWalk}; 15use crate::{db::HirDatabase, utils::variant_data, Substs, Ty, TypeCtor};
16 16
17impl<'a, D: HirDatabase> InferenceContext<'a, D> { 17impl<'a, D: HirDatabase> InferenceContext<'a, D> {
18 fn infer_tuple_struct_pat( 18 fn infer_tuple_struct_pat(
@@ -34,8 +34,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
34 let expected_ty = var_data 34 let expected_ty = var_data
35 .as_ref() 35 .as_ref()
36 .and_then(|d| d.field(&Name::new_tuple_field(i))) 36 .and_then(|d| d.field(&Name::new_tuple_field(i)))
37 .map_or(Ty::Unknown, |field| field_tys[field].clone()) 37 .map_or(Ty::Unknown, |field| field_tys[field].clone().subst(&substs));
38 .subst(&substs);
39 let expected_ty = self.normalize_associated_types_in(expected_ty); 38 let expected_ty = self.normalize_associated_types_in(expected_ty);
40 self.infer_pat(subpat, &expected_ty, default_bm); 39 self.infer_pat(subpat, &expected_ty, default_bm);
41 } 40 }
@@ -65,7 +64,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
65 for subpat in subpats { 64 for subpat in subpats {
66 let matching_field = var_data.as_ref().and_then(|it| it.field(&subpat.name)); 65 let matching_field = var_data.as_ref().and_then(|it| it.field(&subpat.name));
67 let expected_ty = 66 let expected_ty =
68 matching_field.map_or(Ty::Unknown, |field| field_tys[field].clone()).subst(&substs); 67 matching_field.map_or(Ty::Unknown, |field| field_tys[field].clone().subst(&substs));
69 let expected_ty = self.normalize_associated_types_in(expected_ty); 68 let expected_ty = self.normalize_associated_types_in(expected_ty);
70 self.infer_pat(subpat.pat, &expected_ty, default_bm); 69 self.infer_pat(subpat.pat, &expected_ty, default_bm);
71 } 70 }
diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs
index 2c1d4831d..686ce7a21 100644
--- a/crates/ra_hir_ty/src/infer/path.rs
+++ b/crates/ra_hir_ty/src/infer/path.rs
@@ -9,9 +9,9 @@ use hir_def::{
9}; 9};
10use hir_expand::name::Name; 10use hir_expand::name::Name;
11 11
12use crate::{db::HirDatabase, method_resolution, Substs, Ty, TypeWalk, ValueTyDefId}; 12use crate::{db::HirDatabase, method_resolution, Substs, Ty, ValueTyDefId};
13 13
14use super::{ExprOrPatId, InferenceContext, TraitEnvironment, TraitRef}; 14use super::{ExprOrPatId, InferenceContext, 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(
@@ -39,7 +39,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
39 } 39 }
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 ty = Ty::from_type_relative_path(self.db, resolver, ty, remaining_segments_for_ty); 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 self.resolve_ty_assoc_item( 44 self.resolve_ty_assoc_item(
44 ty, 45 ty,
45 &path.segments().last().expect("path had at least one segment").name, 46 &path.segments().last().expect("path had at least one segment").name,
@@ -69,12 +70,16 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
69 ValueNs::EnumVariantId(it) => it.into(), 70 ValueNs::EnumVariantId(it) => it.into(),
70 }; 71 };
71 72
72 let mut ty = self.db.value_ty(typable); 73 let ty = self.db.value_ty(typable);
73 if let Some(self_subst) = self_subst { 74 // self_subst is just for the parent
74 ty = ty.subst(&self_subst); 75 let parent_substs = self_subst.unwrap_or_else(Substs::empty);
75 } 76 let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
76 let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable); 77 let substs = Ty::substs_from_path(&ctx, path, typable);
77 let ty = ty.subst(&substs); 78 let full_substs = Substs::builder(substs.len())
79 .use_parent_substs(&parent_substs)
80 .fill(substs.0[parent_substs.len()..].iter().cloned())
81 .build();
82 let ty = ty.subst(&full_substs);
78 Some(ty) 83 Some(ty)
79 } 84 }
80 85
@@ -98,13 +103,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
98 (TypeNs::TraitId(trait_), true) => { 103 (TypeNs::TraitId(trait_), true) => {
99 let segment = 104 let segment =
100 remaining_segments.last().expect("there should be at least one segment here"); 105 remaining_segments.last().expect("there should be at least one segment here");
101 let trait_ref = TraitRef::from_resolved_path( 106 let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
102 self.db, 107 let trait_ref =
103 &self.resolver, 108 TraitRef::from_resolved_path(&ctx, trait_.into(), resolved_segment, None);
104 trait_.into(),
105 resolved_segment,
106 None,
107 );
108 self.resolve_trait_assoc_item(trait_ref, segment, id) 109 self.resolve_trait_assoc_item(trait_ref, segment, id)
109 } 110 }
110 (def, _) => { 111 (def, _) => {
@@ -114,9 +115,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
114 // as Iterator>::Item::default`) 115 // as Iterator>::Item::default`)
115 let remaining_segments_for_ty = 116 let remaining_segments_for_ty =
116 remaining_segments.take(remaining_segments.len() - 1); 117 remaining_segments.take(remaining_segments.len() - 1);
118 let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
117 let ty = Ty::from_partly_resolved_hir_path( 119 let ty = Ty::from_partly_resolved_hir_path(
118 self.db, 120 &ctx,
119 &self.resolver,
120 def, 121 def,
121 resolved_segment, 122 resolved_segment,
122 remaining_segments_for_ty, 123 remaining_segments_for_ty,
@@ -173,13 +174,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
173 AssocItemId::ConstId(c) => ValueNs::ConstId(c), 174 AssocItemId::ConstId(c) => ValueNs::ConstId(c),
174 AssocItemId::TypeAliasId(_) => unreachable!(), 175 AssocItemId::TypeAliasId(_) => unreachable!(),
175 }; 176 };
176 let substs = Substs::build_for_def(self.db, item)
177 .use_parent_substs(&trait_ref.substs)
178 .fill_with_params()
179 .build();
180 177
181 self.write_assoc_resolution(id, item); 178 self.write_assoc_resolution(id, item);
182 Some((def, Some(substs))) 179 Some((def, Some(trait_ref.substs)))
183 } 180 }
184 181
185 fn resolve_ty_assoc_item( 182 fn resolve_ty_assoc_item(
@@ -193,14 +190,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
193 } 190 }
194 191
195 let canonical_ty = self.canonicalizer().canonicalize_ty(ty.clone()); 192 let canonical_ty = self.canonicalizer().canonicalize_ty(ty.clone());
196 let env = TraitEnvironment::lower(self.db, &self.resolver);
197 let krate = self.resolver.krate()?; 193 let krate = self.resolver.krate()?;
198 let traits_in_scope = self.resolver.traits_in_scope(self.db); 194 let traits_in_scope = self.resolver.traits_in_scope(self.db);
199 195
200 method_resolution::iterate_method_candidates( 196 method_resolution::iterate_method_candidates(
201 &canonical_ty.value, 197 &canonical_ty.value,
202 self.db, 198 self.db,
203 env, 199 self.trait_env.clone(),
204 krate, 200 krate,
205 &traits_in_scope, 201 &traits_in_scope,
206 Some(name), 202 Some(name),
@@ -219,12 +215,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
219 .fill(iter::repeat_with(|| self.table.new_type_var())) 215 .fill(iter::repeat_with(|| self.table.new_type_var()))
220 .build(); 216 .build();
221 let impl_self_ty = self.db.impl_self_ty(impl_id).subst(&impl_substs); 217 let impl_self_ty = self.db.impl_self_ty(impl_id).subst(&impl_substs);
222 let substs = Substs::build_for_def(self.db, item)
223 .use_parent_substs(&impl_substs)
224 .fill_with_params()
225 .build();
226 self.unify(&impl_self_ty, &ty); 218 self.unify(&impl_self_ty, &ty);
227 Some(substs) 219 Some(impl_substs)
228 } 220 }
229 AssocContainerId::TraitId(trait_) => { 221 AssocContainerId::TraitId(trait_) => {
230 // we're picking this method 222 // we're picking this method
@@ -232,15 +224,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
232 .push(ty.clone()) 224 .push(ty.clone())
233 .fill(std::iter::repeat_with(|| self.table.new_type_var())) 225 .fill(std::iter::repeat_with(|| self.table.new_type_var()))
234 .build(); 226 .build();
235 let substs = Substs::build_for_def(self.db, item)
236 .use_parent_substs(&trait_substs)
237 .fill_with_params()
238 .build();
239 self.obligations.push(super::Obligation::Trait(TraitRef { 227 self.obligations.push(super::Obligation::Trait(TraitRef {
240 trait_, 228 trait_,
241 substs: trait_substs, 229 substs: trait_substs.clone(),
242 })); 230 }));
243 Some(substs) 231 Some(trait_substs)
244 } 232 }
245 AssocContainerId::ContainerId(_) => None, 233 AssocContainerId::ContainerId(_) => None,
246 }; 234 };