]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2014 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
e9174d1e | 11 | use middle::def_id::DefId; |
1a4d82fc | 12 | use middle::infer::InferCtxt; |
e9174d1e | 13 | use middle::subst::Substs; |
c1a9b12d | 14 | use middle::ty::{self, Ty, ToPredicate, ToPolyTraitRef}; |
1a4d82fc JJ |
15 | use syntax::codemap::Span; |
16 | use util::common::ErrorReported; | |
85aaf69f | 17 | use util::nodemap::FnvHashSet; |
1a4d82fc | 18 | |
e9174d1e | 19 | use super::{Obligation, ObligationCause, PredicateObligation}; |
1a4d82fc | 20 | |
85aaf69f SL |
21 | struct PredicateSet<'a,'tcx:'a> { |
22 | tcx: &'a ty::ctxt<'tcx>, | |
23 | set: FnvHashSet<ty::Predicate<'tcx>>, | |
24 | } | |
25 | ||
26 | impl<'a,'tcx> PredicateSet<'a,'tcx> { | |
27 | fn new(tcx: &'a ty::ctxt<'tcx>) -> PredicateSet<'a,'tcx> { | |
28 | PredicateSet { tcx: tcx, set: FnvHashSet() } | |
29 | } | |
30 | ||
31 | fn insert(&mut self, pred: &ty::Predicate<'tcx>) -> bool { | |
32 | // We have to be careful here because we want | |
33 | // | |
34 | // for<'a> Foo<&'a int> | |
35 | // | |
36 | // and | |
37 | // | |
38 | // for<'b> Foo<&'b int> | |
39 | // | |
40 | // to be considered equivalent. So normalize all late-bound | |
41 | // regions before we throw things into the underlying set. | |
42 | let normalized_pred = match *pred { | |
43 | ty::Predicate::Trait(ref data) => | |
c1a9b12d | 44 | ty::Predicate::Trait(self.tcx.anonymize_late_bound_regions(data)), |
85aaf69f SL |
45 | |
46 | ty::Predicate::Equate(ref data) => | |
c1a9b12d | 47 | ty::Predicate::Equate(self.tcx.anonymize_late_bound_regions(data)), |
85aaf69f SL |
48 | |
49 | ty::Predicate::RegionOutlives(ref data) => | |
c1a9b12d | 50 | ty::Predicate::RegionOutlives(self.tcx.anonymize_late_bound_regions(data)), |
85aaf69f SL |
51 | |
52 | ty::Predicate::TypeOutlives(ref data) => | |
c1a9b12d | 53 | ty::Predicate::TypeOutlives(self.tcx.anonymize_late_bound_regions(data)), |
85aaf69f SL |
54 | |
55 | ty::Predicate::Projection(ref data) => | |
c1a9b12d | 56 | ty::Predicate::Projection(self.tcx.anonymize_late_bound_regions(data)), |
e9174d1e SL |
57 | |
58 | ty::Predicate::WellFormed(data) => | |
59 | ty::Predicate::WellFormed(data), | |
60 | ||
61 | ty::Predicate::ObjectSafe(data) => | |
62 | ty::Predicate::ObjectSafe(data), | |
85aaf69f SL |
63 | }; |
64 | self.set.insert(normalized_pred) | |
65 | } | |
66 | } | |
67 | ||
1a4d82fc JJ |
68 | /////////////////////////////////////////////////////////////////////////// |
69 | // `Elaboration` iterator | |
70 | /////////////////////////////////////////////////////////////////////////// | |
71 | ||
72 | /// "Elaboration" is the process of identifying all the predicates that | |
73 | /// are implied by a source predicate. Currently this basically means | |
74 | /// walking the "supertraits" and other similar assumptions. For | |
75 | /// example, if we know that `T : Ord`, the elaborator would deduce | |
76 | /// that `T : PartialOrd` holds as well. Similarly, if we have `trait | |
77 | /// Foo : 'static`, and we know that `T : Foo`, then we know that `T : | |
78 | /// 'static`. | |
79 | pub struct Elaborator<'cx, 'tcx:'cx> { | |
80 | tcx: &'cx ty::ctxt<'tcx>, | |
c34b1796 | 81 | stack: Vec<ty::Predicate<'tcx>>, |
85aaf69f | 82 | visited: PredicateSet<'cx,'tcx>, |
1a4d82fc JJ |
83 | } |
84 | ||
1a4d82fc JJ |
85 | pub fn elaborate_trait_ref<'cx, 'tcx>( |
86 | tcx: &'cx ty::ctxt<'tcx>, | |
87 | trait_ref: ty::PolyTraitRef<'tcx>) | |
88 | -> Elaborator<'cx, 'tcx> | |
89 | { | |
c1a9b12d | 90 | elaborate_predicates(tcx, vec![trait_ref.to_predicate()]) |
1a4d82fc JJ |
91 | } |
92 | ||
93 | pub fn elaborate_trait_refs<'cx, 'tcx>( | |
94 | tcx: &'cx ty::ctxt<'tcx>, | |
95 | trait_refs: &[ty::PolyTraitRef<'tcx>]) | |
96 | -> Elaborator<'cx, 'tcx> | |
97 | { | |
98 | let predicates = trait_refs.iter() | |
c1a9b12d | 99 | .map(|trait_ref| trait_ref.to_predicate()) |
1a4d82fc JJ |
100 | .collect(); |
101 | elaborate_predicates(tcx, predicates) | |
102 | } | |
103 | ||
104 | pub fn elaborate_predicates<'cx, 'tcx>( | |
105 | tcx: &'cx ty::ctxt<'tcx>, | |
85aaf69f | 106 | mut predicates: Vec<ty::Predicate<'tcx>>) |
1a4d82fc JJ |
107 | -> Elaborator<'cx, 'tcx> |
108 | { | |
85aaf69f SL |
109 | let mut visited = PredicateSet::new(tcx); |
110 | predicates.retain(|pred| visited.insert(pred)); | |
c34b1796 | 111 | Elaborator { tcx: tcx, stack: predicates, visited: visited } |
1a4d82fc JJ |
112 | } |
113 | ||
114 | impl<'cx, 'tcx> Elaborator<'cx, 'tcx> { | |
c34b1796 AL |
115 | pub fn filter_to_traits(self) -> FilterToTraits<Elaborator<'cx, 'tcx>> { |
116 | FilterToTraits::new(self) | |
1a4d82fc JJ |
117 | } |
118 | ||
119 | fn push(&mut self, predicate: &ty::Predicate<'tcx>) { | |
120 | match *predicate { | |
121 | ty::Predicate::Trait(ref data) => { | |
c34b1796 | 122 | // Predicates declared on the trait. |
c1a9b12d | 123 | let predicates = self.tcx.lookup_super_predicates(data.def_id()); |
c34b1796 AL |
124 | |
125 | let mut predicates: Vec<_> = | |
126 | predicates.predicates | |
127 | .iter() | |
128 | .map(|p| p.subst_supertrait(self.tcx, &data.to_poly_trait_ref())) | |
129 | .collect(); | |
130 | ||
62682a34 SL |
131 | debug!("super_predicates: data={:?} predicates={:?}", |
132 | data, predicates); | |
1a4d82fc JJ |
133 | |
134 | // Only keep those bounds that we haven't already | |
135 | // seen. This is necessary to prevent infinite | |
136 | // recursion in some cases. One common case is when | |
137 | // people define `trait Sized: Sized { }` rather than `trait | |
138 | // Sized { }`. | |
85aaf69f | 139 | predicates.retain(|r| self.visited.insert(r)); |
1a4d82fc | 140 | |
62682a34 | 141 | self.stack.extend(predicates); |
1a4d82fc | 142 | } |
e9174d1e SL |
143 | ty::Predicate::WellFormed(..) => { |
144 | // Currently, we do not elaborate WF predicates, | |
145 | // although we easily could. | |
146 | } | |
147 | ty::Predicate::ObjectSafe(..) => { | |
148 | // Currently, we do not elaborate object-safe | |
149 | // predicates. | |
150 | } | |
1a4d82fc JJ |
151 | ty::Predicate::Equate(..) => { |
152 | // Currently, we do not "elaborate" predicates like | |
153 | // `X == Y`, though conceivably we might. For example, | |
154 | // `&X == &Y` implies that `X == Y`. | |
155 | } | |
156 | ty::Predicate::Projection(..) => { | |
157 | // Nothing to elaborate in a projection predicate. | |
158 | } | |
159 | ty::Predicate::RegionOutlives(..) | | |
160 | ty::Predicate::TypeOutlives(..) => { | |
161 | // Currently, we do not "elaborate" predicates like | |
162 | // `'a : 'b` or `T : 'a`. We could conceivably do | |
163 | // more here. For example, | |
164 | // | |
165 | // &'a int : 'b | |
166 | // | |
167 | // implies that | |
168 | // | |
169 | // 'a : 'b | |
170 | // | |
171 | // and we could get even more if we took WF | |
172 | // constraints into account. For example, | |
173 | // | |
174 | // &'a &'b int : 'c | |
175 | // | |
176 | // implies that | |
177 | // | |
178 | // 'b : 'a | |
179 | // 'a : 'c | |
180 | } | |
181 | } | |
182 | } | |
183 | } | |
184 | ||
185 | impl<'cx, 'tcx> Iterator for Elaborator<'cx, 'tcx> { | |
186 | type Item = ty::Predicate<'tcx>; | |
187 | ||
188 | fn next(&mut self) -> Option<ty::Predicate<'tcx>> { | |
c34b1796 AL |
189 | // Extract next item from top-most stack frame, if any. |
190 | let next_predicate = match self.stack.pop() { | |
191 | Some(predicate) => predicate, | |
192 | None => { | |
193 | // No more stack frames. Done. | |
194 | return None; | |
1a4d82fc | 195 | } |
c34b1796 AL |
196 | }; |
197 | self.push(&next_predicate); | |
198 | return Some(next_predicate); | |
1a4d82fc JJ |
199 | } |
200 | } | |
201 | ||
202 | /////////////////////////////////////////////////////////////////////////// | |
203 | // Supertrait iterator | |
204 | /////////////////////////////////////////////////////////////////////////// | |
205 | ||
c34b1796 | 206 | pub type Supertraits<'cx, 'tcx> = FilterToTraits<Elaborator<'cx, 'tcx>>; |
1a4d82fc JJ |
207 | |
208 | pub fn supertraits<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>, | |
209 | trait_ref: ty::PolyTraitRef<'tcx>) | |
210 | -> Supertraits<'cx, 'tcx> | |
211 | { | |
212 | elaborate_trait_ref(tcx, trait_ref).filter_to_traits() | |
213 | } | |
214 | ||
215 | pub fn transitive_bounds<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>, | |
216 | bounds: &[ty::PolyTraitRef<'tcx>]) | |
217 | -> Supertraits<'cx, 'tcx> | |
218 | { | |
219 | elaborate_trait_refs(tcx, bounds).filter_to_traits() | |
220 | } | |
221 | ||
c34b1796 AL |
222 | /////////////////////////////////////////////////////////////////////////// |
223 | // Iterator over def-ids of supertraits | |
224 | ||
225 | pub struct SupertraitDefIds<'cx, 'tcx:'cx> { | |
226 | tcx: &'cx ty::ctxt<'tcx>, | |
e9174d1e SL |
227 | stack: Vec<DefId>, |
228 | visited: FnvHashSet<DefId>, | |
c34b1796 AL |
229 | } |
230 | ||
231 | pub fn supertrait_def_ids<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>, | |
e9174d1e | 232 | trait_def_id: DefId) |
c34b1796 AL |
233 | -> SupertraitDefIds<'cx, 'tcx> |
234 | { | |
235 | SupertraitDefIds { | |
236 | tcx: tcx, | |
237 | stack: vec![trait_def_id], | |
238 | visited: Some(trait_def_id).into_iter().collect(), | |
239 | } | |
240 | } | |
241 | ||
242 | impl<'cx, 'tcx> Iterator for SupertraitDefIds<'cx, 'tcx> { | |
e9174d1e | 243 | type Item = DefId; |
c34b1796 | 244 | |
e9174d1e | 245 | fn next(&mut self) -> Option<DefId> { |
c34b1796 AL |
246 | let def_id = match self.stack.pop() { |
247 | Some(def_id) => def_id, | |
248 | None => { return None; } | |
249 | }; | |
250 | ||
c1a9b12d | 251 | let predicates = self.tcx.lookup_super_predicates(def_id); |
c34b1796 AL |
252 | let visited = &mut self.visited; |
253 | self.stack.extend( | |
254 | predicates.predicates | |
255 | .iter() | |
256 | .filter_map(|p| p.to_opt_poly_trait_ref()) | |
257 | .map(|t| t.def_id()) | |
258 | .filter(|&super_def_id| visited.insert(super_def_id))); | |
259 | Some(def_id) | |
260 | } | |
261 | } | |
262 | ||
263 | /////////////////////////////////////////////////////////////////////////// | |
264 | // Other | |
265 | /////////////////////////////////////////////////////////////////////////// | |
266 | ||
267 | /// A filter around an iterator of predicates that makes it yield up | |
268 | /// just trait references. | |
269 | pub struct FilterToTraits<I> { | |
270 | base_iterator: I | |
271 | } | |
272 | ||
273 | impl<I> FilterToTraits<I> { | |
274 | fn new(base: I) -> FilterToTraits<I> { | |
275 | FilterToTraits { base_iterator: base } | |
276 | } | |
277 | } | |
278 | ||
279 | impl<'tcx,I:Iterator<Item=ty::Predicate<'tcx>>> Iterator for FilterToTraits<I> { | |
1a4d82fc JJ |
280 | type Item = ty::PolyTraitRef<'tcx>; |
281 | ||
282 | fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> { | |
283 | loop { | |
c34b1796 | 284 | match self.base_iterator.next() { |
1a4d82fc JJ |
285 | None => { |
286 | return None; | |
287 | } | |
288 | Some(ty::Predicate::Trait(data)) => { | |
289 | return Some(data.to_poly_trait_ref()); | |
290 | } | |
291 | Some(_) => { | |
292 | } | |
293 | } | |
294 | } | |
295 | } | |
296 | } | |
297 | ||
298 | /////////////////////////////////////////////////////////////////////////// | |
299 | // Other | |
300 | /////////////////////////////////////////////////////////////////////////// | |
301 | ||
302 | // determine the `self` type, using fresh variables for all variables | |
303 | // declared on the impl declaration e.g., `impl<A,B> for Box<[(A,B)]>` | |
304 | // would return ($0, $1) where $0 and $1 are freshly instantiated type | |
305 | // variables. | |
c34b1796 AL |
306 | pub fn fresh_type_vars_for_impl<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, |
307 | span: Span, | |
e9174d1e | 308 | impl_def_id: DefId) |
c34b1796 | 309 | -> Substs<'tcx> |
1a4d82fc JJ |
310 | { |
311 | let tcx = infcx.tcx; | |
c1a9b12d | 312 | let impl_generics = tcx.lookup_item_type(impl_def_id).generics; |
1a4d82fc JJ |
313 | infcx.fresh_substs_for_generics(span, &impl_generics) |
314 | } | |
315 | ||
1a4d82fc | 316 | /// See `super::obligations_for_generics` |
62682a34 | 317 | pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>, |
c34b1796 | 318 | recursion_depth: usize, |
85aaf69f | 319 | generic_bounds: &ty::InstantiatedPredicates<'tcx>) |
62682a34 | 320 | -> Vec<PredicateObligation<'tcx>> |
1a4d82fc | 321 | { |
62682a34 SL |
322 | debug!("predicates_for_generics(generic_bounds={:?})", |
323 | generic_bounds); | |
1a4d82fc | 324 | |
62682a34 | 325 | generic_bounds.predicates.iter().map(|predicate| { |
1a4d82fc JJ |
326 | Obligation { cause: cause.clone(), |
327 | recursion_depth: recursion_depth, | |
328 | predicate: predicate.clone() } | |
62682a34 | 329 | }).collect() |
1a4d82fc JJ |
330 | } |
331 | ||
332 | pub fn trait_ref_for_builtin_bound<'tcx>( | |
333 | tcx: &ty::ctxt<'tcx>, | |
334 | builtin_bound: ty::BuiltinBound, | |
335 | param_ty: Ty<'tcx>) | |
d9579d0f | 336 | -> Result<ty::TraitRef<'tcx>, ErrorReported> |
1a4d82fc JJ |
337 | { |
338 | match tcx.lang_items.from_builtin_kind(builtin_bound) { | |
339 | Ok(def_id) => { | |
d9579d0f | 340 | Ok(ty::TraitRef { |
1a4d82fc JJ |
341 | def_id: def_id, |
342 | substs: tcx.mk_substs(Substs::empty().with_self_ty(param_ty)) | |
d9579d0f | 343 | }) |
1a4d82fc JJ |
344 | } |
345 | Err(e) => { | |
85aaf69f | 346 | tcx.sess.err(&e); |
1a4d82fc JJ |
347 | Err(ErrorReported) |
348 | } | |
349 | } | |
350 | } | |
351 | ||
c34b1796 AL |
352 | |
353 | pub fn predicate_for_trait_ref<'tcx>( | |
1a4d82fc | 354 | cause: ObligationCause<'tcx>, |
d9579d0f | 355 | trait_ref: ty::TraitRef<'tcx>, |
c34b1796 | 356 | recursion_depth: usize) |
d9579d0f | 357 | -> PredicateObligation<'tcx> |
1a4d82fc | 358 | { |
d9579d0f | 359 | Obligation { |
1a4d82fc JJ |
360 | cause: cause, |
361 | recursion_depth: recursion_depth, | |
c1a9b12d | 362 | predicate: trait_ref.to_predicate(), |
d9579d0f | 363 | } |
1a4d82fc JJ |
364 | } |
365 | ||
c34b1796 AL |
366 | pub fn predicate_for_trait_def<'tcx>( |
367 | tcx: &ty::ctxt<'tcx>, | |
368 | cause: ObligationCause<'tcx>, | |
e9174d1e | 369 | trait_def_id: DefId, |
c34b1796 | 370 | recursion_depth: usize, |
d9579d0f AL |
371 | param_ty: Ty<'tcx>, |
372 | ty_params: Vec<Ty<'tcx>>) | |
373 | -> PredicateObligation<'tcx> | |
c34b1796 | 374 | { |
d9579d0f | 375 | let trait_ref = ty::TraitRef { |
c34b1796 | 376 | def_id: trait_def_id, |
d9579d0f AL |
377 | substs: tcx.mk_substs(Substs::new_trait(ty_params, vec![], param_ty)) |
378 | }; | |
c34b1796 AL |
379 | predicate_for_trait_ref(cause, trait_ref, recursion_depth) |
380 | } | |
381 | ||
382 | pub fn predicate_for_builtin_bound<'tcx>( | |
383 | tcx: &ty::ctxt<'tcx>, | |
384 | cause: ObligationCause<'tcx>, | |
385 | builtin_bound: ty::BuiltinBound, | |
386 | recursion_depth: usize, | |
387 | param_ty: Ty<'tcx>) | |
388 | -> Result<PredicateObligation<'tcx>, ErrorReported> | |
389 | { | |
390 | let trait_ref = try!(trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty)); | |
d9579d0f | 391 | Ok(predicate_for_trait_ref(cause, trait_ref, recursion_depth)) |
c34b1796 AL |
392 | } |
393 | ||
1a4d82fc JJ |
394 | /// Cast a trait reference into a reference to one of its super |
395 | /// traits; returns `None` if `target_trait_def_id` is not a | |
396 | /// supertrait. | |
397 | pub fn upcast<'tcx>(tcx: &ty::ctxt<'tcx>, | |
398 | source_trait_ref: ty::PolyTraitRef<'tcx>, | |
e9174d1e | 399 | target_trait_def_id: DefId) |
c34b1796 | 400 | -> Vec<ty::PolyTraitRef<'tcx>> |
1a4d82fc JJ |
401 | { |
402 | if source_trait_ref.def_id() == target_trait_def_id { | |
c34b1796 | 403 | return vec![source_trait_ref]; // shorcut the most common case |
1a4d82fc JJ |
404 | } |
405 | ||
c34b1796 AL |
406 | supertraits(tcx, source_trait_ref) |
407 | .filter(|r| r.def_id() == target_trait_def_id) | |
408 | .collect() | |
1a4d82fc JJ |
409 | } |
410 | ||
b039eaaf | 411 | /// Given a trait `trait_ref`, returns the number of vtable entries |
c1a9b12d SL |
412 | /// that come from `trait_ref`, excluding its supertraits. Used in |
413 | /// computing the vtable base for an upcast trait of a trait object. | |
414 | pub fn count_own_vtable_entries<'tcx>(tcx: &ty::ctxt<'tcx>, | |
415 | trait_ref: ty::PolyTraitRef<'tcx>) | |
416 | -> usize { | |
417 | let mut entries = 0; | |
418 | // Count number of methods and add them to the total offset. | |
419 | // Skip over associated types and constants. | |
420 | for trait_item in &tcx.trait_items(trait_ref.def_id())[..] { | |
421 | if let ty::MethodTraitItem(_) = *trait_item { | |
422 | entries += 1; | |
1a4d82fc | 423 | } |
85aaf69f | 424 | } |
c1a9b12d SL |
425 | entries |
426 | } | |
85aaf69f | 427 | |
c1a9b12d SL |
428 | /// Given an upcast trait object described by `object`, returns the |
429 | /// index of the method `method_def_id` (which should be part of | |
430 | /// `object.upcast_trait_ref`) within the vtable for `object`. | |
431 | pub fn get_vtable_index_of_object_method<'tcx>(tcx: &ty::ctxt<'tcx>, | |
432 | object: &super::VtableObjectData<'tcx>, | |
e9174d1e | 433 | method_def_id: DefId) -> usize { |
c1a9b12d SL |
434 | // Count number of methods preceding the one we are selecting and |
435 | // add them to the total offset. | |
436 | // Skip over associated types and constants. | |
437 | let mut entries = object.vtable_base; | |
438 | for trait_item in &tcx.trait_items(object.upcast_trait_ref.def_id())[..] { | |
439 | if trait_item.def_id() == method_def_id { | |
440 | // The item with the ID we were given really ought to be a method. | |
441 | assert!(match *trait_item { | |
442 | ty::MethodTraitItem(_) => true, | |
443 | _ => false | |
444 | }); | |
445 | ||
446 | return entries; | |
447 | } | |
448 | if let ty::MethodTraitItem(_) = *trait_item { | |
449 | entries += 1; | |
85aaf69f SL |
450 | } |
451 | } | |
452 | ||
c1a9b12d SL |
453 | tcx.sess.bug(&format!("get_vtable_index_of_object_method: {:?} was not found", |
454 | method_def_id)); | |
85aaf69f SL |
455 | } |
456 | ||
457 | pub enum TupleArgumentsFlag { Yes, No } | |
458 | ||
459 | pub fn closure_trait_ref_and_return_type<'tcx>( | |
460 | tcx: &ty::ctxt<'tcx>, | |
e9174d1e | 461 | fn_trait_def_id: DefId, |
85aaf69f SL |
462 | self_ty: Ty<'tcx>, |
463 | sig: &ty::PolyFnSig<'tcx>, | |
464 | tuple_arguments: TupleArgumentsFlag) | |
d9579d0f | 465 | -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>)> |
85aaf69f SL |
466 | { |
467 | let arguments_tuple = match tuple_arguments { | |
468 | TupleArgumentsFlag::No => sig.0.inputs[0], | |
c1a9b12d | 469 | TupleArgumentsFlag::Yes => tcx.mk_tup(sig.0.inputs.to_vec()), |
85aaf69f SL |
470 | }; |
471 | let trait_substs = Substs::new_trait(vec![arguments_tuple], vec![], self_ty); | |
d9579d0f | 472 | let trait_ref = ty::TraitRef { |
85aaf69f SL |
473 | def_id: fn_trait_def_id, |
474 | substs: tcx.mk_substs(trait_substs), | |
d9579d0f | 475 | }; |
c1a9b12d | 476 | ty::Binder((trait_ref, sig.0.output.unwrap_or(tcx.mk_nil()))) |
1a4d82fc | 477 | } |