diff options
| author | Michael Hewson <michael@michaelhewson.ca> | 2018-10-12 00:12:56 -0400 |
|---|---|---|
| committer | Michael Hewson <michael@michaelhewson.ca> | 2018-11-01 18:16:59 -0400 |
| commit | eb997d76d5a1c0ed933ab76459233e3650d2771d (patch) | |
| tree | 003c64c93418097eee6c7de52d62b4a785ca171a /src | |
| parent | b5b25f8196567b5a86eb0f805852e11889d80075 (diff) | |
| download | rust-eb997d76d5a1c0ed933ab76459233e3650d2771d.tar.gz rust-eb997d76d5a1c0ed933ab76459233e3650d2771d.zip | |
add `U: Trait` to the param env during DispatchFromDyn check
also updated the doc on `receiver_is_dispatchable` to reflect current state of the implementation
Diffstat (limited to 'src')
| -rw-r--r-- | src/librustc/traits/object_safety.rs | 67 |
1 files changed, 40 insertions, 27 deletions
diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 7e2b5637952..1d76ccdca31 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -437,16 +437,16 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { /// in the following way: /// - let `Receiver` be the type of the `self` argument, i.e `Self`, `&Self`, `Rc<Self>` /// - require the following bound: - /// forall(T: Trait) { - /// Receiver[Self => T]: DispatchFromDyn<Receiver[Self => dyn Trait]> - /// } - /// where `Foo[X => Y]` means "the same type as `Foo`, but with `X` replaced with `Y`" + /// + /// Receiver[Self => T]: DispatchFromDyn<Receiver[Self => dyn Trait]> + /// + /// where `Foo[X => Y]` means "the same type as `Foo`, but with `X` replaced with `Y`" /// (substitution notation). /// /// some examples of receiver types and their required obligation - /// - `&'a mut self` requires `&'a mut T: DispatchFromDyn<&'a mut dyn Trait>` - /// - `self: Rc<Self>` requires `Rc<T>: DispatchFromDyn<Rc<dyn Trait>>` - /// - `self: Pin<Box<Self>>` requires `Pin<Box<T>>: DispatchFromDyn<Pin<Box<dyn Trait>>>` + /// - `&'a mut self` requires `&'a mut Self: DispatchFromDyn<&'a mut dyn Trait>` + /// - `self: Rc<Self>` requires `Rc<Self>: DispatchFromDyn<Rc<dyn Trait>>` + /// - `self: Pin<Box<Self>>` requires `Pin<Box<Self>>: DispatchFromDyn<Pin<Box<dyn Trait>>>` /// /// The only case where the receiver is not dispatchable, but is still a valid receiver /// type (just not object-safe), is when there is more than one level of pointer indirection. @@ -456,14 +456,12 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { /// contained by the trait object, because the object that needs to be coerced is behind /// a pointer. /// - /// In practice, there are issues with the above bound: `where` clauses that apply to `Self` - /// would have to apply to `T`, trait object types have a lot of parameters that need to - /// be filled in (lifetime and type parameters, and the lifetime of the actual object), and - /// I'm pretty sure using `dyn Trait` in the query causes another object-safety query for - /// `Trait`, resulting in cyclic queries. So in the implementation, we use the following, - /// more general bound: + /// In practice, we cannot use `dyn Trait` explicitly in the obligation because it would result + /// in a new check that `Trait` is object safe, creating a cycle. So instead, we fudge a little + /// by introducing a new type parameter `U` such that `Self: Unsize<U>` and `U: Trait + ?Sized`, + /// and use `U` in place of `dyn Trait`. Written as a chalk-style query: /// - /// forall (U: ?Sized) { + /// forall (U: Trait + ?Sized) { /// if (Self: Unsize<U>) { /// Receiver: DispatchFromDyn<Receiver[Self => U]> /// } @@ -493,6 +491,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { return false; }; + // the type `U` in the query // use a bogus type parameter to mimick a forall(U) query using u32::MAX for now. // FIXME(mikeyhew) this is a total hack, and we should replace it when real forall queries // are implemented @@ -501,17 +500,41 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { Name::intern("RustaceansAreAwesome").as_interned_str(), ); - // create a modified param env, with `Self: Unsize<U>` added to the caller bounds + // `Receiver[Self => U]` + let unsized_receiver_ty = self.receiver_for_self_ty( + receiver_ty, unsized_self_ty, method.def_id + ); + + // create a modified param env, with `Self: Unsize<U>` and `U: Trait` added to caller bounds + // `U: ?Sized` is already implied here let param_env = { let mut param_env = self.param_env(method.def_id); - let predicate = ty::TraitRef { + // Self: Unsize<U> + let unsize_predicate = ty::TraitRef { def_id: unsize_did, substs: self.mk_substs_trait(self.mk_self_type(), &[unsized_self_ty.into()]), }.to_predicate(); + // U: Trait<Arg1, ..., ArgN> + let trait_predicate = { + let substs = Substs::for_item(self, method.container.assert_trait(), |param, _| { + if param.index == 0 { + unsized_self_ty.into() + } else { + self.mk_param_from_def(param) + } + }); + + ty::TraitRef { + def_id: unsize_did, + substs, + }.to_predicate() + }; + let caller_bounds: Vec<Predicate<'tcx>> = param_env.caller_bounds.iter().cloned() - .chain(iter::once(predicate)) + .chain(iter::once(unsize_predicate)) + .chain(iter::once(trait_predicate)) .collect(); param_env.caller_bounds = self.intern_predicates(&caller_bounds); @@ -519,16 +542,6 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { param_env }; - let receiver_substs = Substs::for_item(self, method.def_id, |param, _| { - if param.index == 0 { - unsized_self_ty.into() - } else { - self.mk_param_from_def(param) - } - }); - // the type `Receiver[Self => U]` in the query - let unsized_receiver_ty = receiver_ty.subst(self, receiver_substs); - // Receiver: DispatchFromDyn<Receiver[Self => U]> let obligation = { let predicate = ty::TraitRef { |
