Skip to content

Commit 1318f70

Browse files
committed
Try to do the CoerceUnsized check for object safety
- replaced NonStandardSelfType error with UncoercibleReceiver - add a method to global TyCtxt which does the CoerceUnsized check. This currently results in circular dependencies when compiling libcore ```
1 parent 4783f3d commit 1318f70

File tree

1 file changed

+92
-16
lines changed

1 file changed

+92
-16
lines changed

src/librustc/traits/object_safety.rs

Lines changed: 92 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,13 @@ use super::elaborate_predicates;
2121

2222
use hir::def_id::DefId;
2323
use lint;
24-
use traits;
25-
use ty::{self, Ty, TyCtxt, TypeFoldable};
24+
use traits::{self, Obligation, ObligationCause};
25+
use ty::{self, Ty, TyCtxt, TypeFoldable, Predicate, ToPredicate};
26+
use ty::subst::{Subst, Substs};
2627
use ty::util::ExplicitSelf;
2728
use std::borrow::Cow;
28-
use syntax::ast;
29+
use std::iter::{self};
30+
use syntax::ast::{self, Name};
2931
use syntax_pos::Span;
3032

3133
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
@@ -62,8 +64,8 @@ impl ObjectSafetyViolation {
6264
format!("method `{}` references the `Self` type in where clauses", name).into(),
6365
ObjectSafetyViolation::Method(name, MethodViolationCode::Generic) =>
6466
format!("method `{}` has generic type parameters", name).into(),
65-
ObjectSafetyViolation::Method(name, MethodViolationCode::NonStandardSelfType) =>
66-
format!("method `{}` has a non-standard `self` type", name).into(),
67+
ObjectSafetyViolation::Method(name, MethodViolationCode::UncoercibleReceiver) =>
68+
format!("method `{}` has an uncoercible receiver type", name).into(),
6769
ObjectSafetyViolation::AssociatedConst(name) =>
6870
format!("the trait cannot contain associated consts like `{}`", name).into(),
6971
}
@@ -85,8 +87,8 @@ pub enum MethodViolationCode {
8587
/// e.g., `fn foo<A>()`
8688
Generic,
8789

88-
/// arbitrary `self` type, e.g. `self: Rc<Self>`
89-
NonStandardSelfType,
90+
/// the self argument can't be coerced from Self=dyn Trait to Self=T where T: Trait
91+
UncoercibleReceiver,
9092
}
9193

9294
impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
@@ -280,23 +282,20 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
280282
method: &ty::AssociatedItem)
281283
-> Option<MethodViolationCode>
282284
{
283-
// The method's first parameter must be something that derefs (or
284-
// autorefs) to `&self`. For now, we only accept `self`, `&self`
285-
// and `Box<Self>`.
285+
// The method's first parameter must be named `self`
286286
if !method.method_has_self_argument {
287287
return Some(MethodViolationCode::StaticMethod);
288288
}
289289

290290
let sig = self.fn_sig(method.def_id);
291291

292-
let self_ty = self.mk_self_type();
293-
let self_arg_ty = sig.skip_binder().inputs()[0];
294-
if let ExplicitSelf::Other = ExplicitSelf::determine(self_arg_ty, |ty| ty == self_ty) {
295-
return Some(MethodViolationCode::NonStandardSelfType);
292+
let receiver_ty = sig.skip_binder().inputs()[0];
293+
294+
if !self.receiver_is_coercible(method, receiver_ty) {
295+
return Some(MethodViolationCode::UncoercibleReceiver);
296296
}
297297

298-
// The `Self` type is erased, so it should not appear in list of
299-
// arguments or return type apart from the receiver.
298+
300299
for input_ty in &sig.skip_binder().inputs()[1..] {
301300
if self.contains_illegal_self_type_reference(trait_def_id, input_ty) {
302301
return Some(MethodViolationCode::ReferencesSelf);
@@ -326,6 +325,83 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
326325
None
327326
}
328327

328+
// checks the type of the self argument, and makes sure it implements
329+
// the CoerceUnsized requirement:
330+
// forall (U) {
331+
// if (Self: Unsize<U>) {
332+
// Receiver: CoerceUnsized<Receiver<Self=U>>
333+
// }
334+
// }
335+
#[allow(dead_code)]
336+
fn receiver_is_coercible(
337+
self,
338+
method: &ty::AssociatedItem,
339+
receiver_ty: Ty<'tcx>
340+
) -> bool
341+
{
342+
let traits = (self.lang_items().unsize_trait(),
343+
self.lang_items().coerce_unsized_trait());
344+
let (unsize_did, coerce_unsized_did) = if let (Some(u), Some(cu)) = traits {
345+
(u, cu)
346+
} else {
347+
debug!("receiver_is_coercible: Missing Unsize or CoerceUnsized traits");
348+
return false;
349+
};
350+
351+
// use a bogus type parameter to mimick a forall(U) query
352+
// using u32::MAX for now. This is BAD and will probably break when
353+
// this method is called recursively, or at least if someone does a hacky thing
354+
// like this elsewhere in the compiler
355+
let target_self_ty: Ty<'tcx> = self.mk_ty_param(
356+
::std::u32::MAX,
357+
Name::intern("mikeyhewROCKS").as_interned_str(),
358+
);
359+
360+
// create a modified param env, with
361+
// `Self: Unsize<U>` added to the caller bounds
362+
let param_env = {
363+
let mut param_env = self.param_env(method.def_id);
364+
365+
let predicate = ty::TraitRef {
366+
def_id: unsize_did,
367+
substs: self.mk_substs_trait(self.mk_self_type(), &[target_self_ty.into()]),
368+
}.to_predicate();
369+
370+
let caller_bounds: Vec<Predicate<'tcx>> = param_env.caller_bounds.iter().cloned()
371+
.chain(iter::once(predicate))
372+
.collect();
373+
374+
param_env.caller_bounds = self.intern_predicates(&caller_bounds);
375+
376+
param_env
377+
};
378+
379+
// the type `Receiver<Self=U>` in the query
380+
let target_receiver_ty = receiver_ty.subst(
381+
self,
382+
self.mk_substs_trait(target_self_ty, &[]),
383+
);
384+
385+
// Receiver: CoerceUnsized<Receiver<Self=U>>
386+
let obligation = {
387+
let predicate = ty::TraitRef {
388+
def_id: coerce_unsized_did,
389+
substs: self.mk_substs_trait(self.mk_self_type(), &[target_receiver_ty.into()]),
390+
}.to_predicate();
391+
392+
Obligation::new(
393+
ObligationCause::dummy(),
394+
param_env,
395+
predicate,
396+
)
397+
};
398+
399+
// return whether `Receiver: CoerceUnsized<Receiver<Self=U>>` holds
400+
self.infer_ctxt().enter(|ref infcx| {
401+
infcx.predicate_must_hold(&obligation)
402+
})
403+
}
404+
329405
fn contains_illegal_self_type_reference(self,
330406
trait_def_id: DefId,
331407
ty: Ty<'tcx>)

0 commit comments

Comments
 (0)