Auto merge of #23423 - nikomatsakis:issue-18737-trait-subtyping, r=nrc

This upcast coercion currently never requires vtable changes. It should be generalized. 

This is a [breaking-change] -- if you have an impl on an object type like `impl SomeTrait`, then this will no longer be applicable to object types like `SomeTrait+Send`. In the standard library, this primarily affected `Any`, and this PR adds impls for `Any+Send` as to keep the API the same in practice. An alternate workaround is to use UFCS form or standalone fns. For more details, see <https://github.com/rust-lang/rust/issues/18737#issuecomment-78450798>.

r? @nrc
This commit is contained in:
bors 2015-03-17 13:29:48 +00:00
commit c64d671671
21 changed files with 248 additions and 122 deletions

View file

@ -1102,6 +1102,11 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
this.emit_enum_variant_arg(1, |this| Ok(this.emit_ty(ecx, self_ty)))
})
}
ty::UnsizeUpcast(target_ty) => {
this.emit_enum_variant("UnsizeUpcast", 3, 1, |this| {
this.emit_enum_variant_arg(0, |this| Ok(this.emit_ty(ecx, target_ty)))
})
}
}
});
}
@ -1707,7 +1712,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
fn read_unsize_kind<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
-> ty::UnsizeKind<'tcx> {
self.read_enum("UnsizeKind", |this| {
let variants = &["UnsizeLength", "UnsizeStruct", "UnsizeVtable"];
let variants = &["UnsizeLength", "UnsizeStruct", "UnsizeVtable", "UnsizeUpcast"];
this.read_enum_variant(variants, |this, i| {
Ok(match i {
0 => {
@ -1741,6 +1746,11 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
this.read_enum_variant_arg(1, |this| Ok(this.read_ty(dcx))).unwrap();
ty::UnsizeVtable(ty_trait, self_ty)
}
3 => {
let target_ty =
this.read_enum_variant_arg(0, |this| Ok(this.read_ty(dcx))).unwrap();
ty::UnsizeUpcast(target_ty)
}
_ => panic!("bad enum variant for ty::UnsizeKind")
})
})

View file

@ -857,28 +857,13 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
n: uint) {
debug!("walk_autoref expr={}", expr.repr(self.tcx()));
// Match for unique trait coercions first, since we don't need the
// call to cat_expr_autoderefd.
match *autoref {
ty::AutoUnsizeUniq(ty::UnsizeVtable(..)) |
ty::AutoUnsize(ty::UnsizeVtable(..)) => {
assert!(n == 1, format!("Expected exactly 1 deref with Uniq \
AutoRefs, found: {}", n));
let cmt_unadjusted =
return_if_err!(self.mc.cat_expr_unadjusted(expr));
self.delegate_consume(expr.id, expr.span, cmt_unadjusted);
return;
}
_ => {}
}
let cmt_derefd = return_if_err!(
self.mc.cat_expr_autoderefd(expr, n));
debug!("walk_adjustment: cmt_derefd={}",
cmt_derefd.repr(self.tcx()));
match *autoref {
ty::AutoPtr(r, m, _) => {
let cmt_derefd = return_if_err!(
self.mc.cat_expr_autoderefd(expr, n));
debug!("walk_adjustment: cmt_derefd={}",
cmt_derefd.repr(self.tcx()));
self.delegate.borrow(expr.id,
expr.span,
cmt_derefd,
@ -886,7 +871,16 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
ty::BorrowKind::from_mutbl(m),
AutoRef);
}
ty::AutoUnsizeUniq(_) | ty::AutoUnsize(_) | ty::AutoUnsafe(..) => {}
ty::AutoUnsize(_) |
ty::AutoUnsizeUniq(_) => {
assert!(n == 1, format!("Expected exactly 1 deref with Uniq \
AutoRefs, found: {}", n));
let cmt_unadjusted =
return_if_err!(self.mc.cat_expr_unadjusted(expr));
self.delegate_consume(expr.id, expr.span, cmt_unadjusted);
}
ty::AutoUnsafe(..) => {
}
}
}

View file

@ -314,9 +314,18 @@ pub trait Combine<'tcx> : Sized {
}
fn builtin_bounds(&self,
a: ty::BuiltinBounds,
b: ty::BuiltinBounds)
-> cres<'tcx, ty::BuiltinBounds>;
a: BuiltinBounds,
b: BuiltinBounds)
-> cres<'tcx, BuiltinBounds>
{
// Two sets of builtin bounds are only relatable if they are
// precisely the same (but see the coercion code).
if a != b {
Err(ty::terr_builtin_bounds(expected_found(self, a, b)))
} else {
Ok(a)
}
}
fn trait_refs(&self,
a: &ty::TraitRef<'tcx>,

View file

@ -8,7 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use middle::ty::{BuiltinBounds};
use middle::ty::{self, Ty};
use middle::ty::TyVar;
use middle::infer::combine::*;
@ -73,23 +72,6 @@ impl<'f, 'tcx> Combine<'tcx> for Equate<'f, 'tcx> {
}
}
fn builtin_bounds(&self,
a: BuiltinBounds,
b: BuiltinBounds)
-> cres<'tcx, BuiltinBounds>
{
// More bounds is a subtype of fewer bounds.
//
// e.g., fn:Copy() <: fn(), because the former is a function
// that only closes over copyable things, but the latter is
// any function at all.
if a != b {
Err(ty::terr_builtin_bounds(expected_found(self, a, b)))
} else {
Ok(a)
}
}
fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
debug!("{}.tys({}, {})", self.tag(),
a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx));

View file

@ -14,7 +14,6 @@ use super::higher_ranked::HigherRankedRelations;
use super::{cres};
use super::Subtype;
use middle::ty::{BuiltinBounds};
use middle::ty::{self, Ty};
use syntax::ast::{MutImmutable, MutMutable, Unsafety};
use util::ppaux::mt_to_string;
@ -94,15 +93,6 @@ impl<'f, 'tcx> Combine<'tcx> for Glb<'f, 'tcx> {
}
}
fn builtin_bounds(&self,
a: ty::BuiltinBounds,
b: ty::BuiltinBounds)
-> cres<'tcx, ty::BuiltinBounds> {
// More bounds is a subtype of fewer bounds, so
// the GLB (mutual subtype) is the union.
Ok(a.union(b))
}
fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> {
debug!("{}.regions({}, {})",
self.tag(),

View file

@ -14,7 +14,6 @@ use super::lattice::*;
use super::{cres};
use super::{Subtype};
use middle::ty::{BuiltinBounds};
use middle::ty::{self, Ty};
use syntax::ast::{MutMutable, MutImmutable, Unsafety};
use util::ppaux::mt_to_string;
@ -89,15 +88,6 @@ impl<'f, 'tcx> Combine<'tcx> for Lub<'f, 'tcx> {
}
}
fn builtin_bounds(&self,
a: ty::BuiltinBounds,
b: ty::BuiltinBounds)
-> cres<'tcx, ty::BuiltinBounds> {
// More bounds is a subtype of fewer bounds, so
// the LUB (mutual supertype) is the intersection.
Ok(a.intersection(b))
}
fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> {
debug!("{}.regions({}, {})",
self.tag(),

View file

@ -14,7 +14,6 @@ use super::higher_ranked::HigherRankedRelations;
use super::{Subtype};
use super::type_variable::{SubtypeOf, SupertypeOf};
use middle::ty::{BuiltinBounds};
use middle::ty::{self, Ty};
use middle::ty::TyVar;
use util::ppaux::{Repr};
@ -97,20 +96,6 @@ impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> {
})
}
fn builtin_bounds(&self, a: BuiltinBounds, b: BuiltinBounds)
-> cres<'tcx, BuiltinBounds> {
// More bounds is a subtype of fewer bounds.
//
// e.g., fn:Copy() <: fn(), because the former is a function
// that only closes over copyable things, but the latter is
// any function at all.
if a.is_superset(&b) {
Ok(a)
} else {
Err(ty::terr_builtin_bounds(expected_found(self, a, b)))
}
}
fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
debug!("{}.tys({}, {})", self.tag(),
a.repr(self.tcx()), b.repr(self.tcx()));

View file

@ -292,7 +292,8 @@ pub enum UnsizeKind<'tcx> {
// An unsize coercion applied to the tail field of a struct.
// The uint is the index of the type parameter which is unsized.
UnsizeStruct(Box<UnsizeKind<'tcx>>, uint),
UnsizeVtable(TyTrait<'tcx>, /* the self type of the trait */ Ty<'tcx>)
UnsizeVtable(TyTrait<'tcx>, /* the self type of the trait */ Ty<'tcx>),
UnsizeUpcast(Ty<'tcx>),
}
#[derive(Clone, Debug)]
@ -4631,6 +4632,9 @@ pub fn unsize_ty<'tcx>(cx: &ctxt<'tcx>,
&UnsizeVtable(TyTrait { ref principal, ref bounds }, _) => {
mk_trait(cx, principal.clone(), bounds.clone())
}
&UnsizeUpcast(target_ty) => {
target_ty
}
}
}
@ -6853,6 +6857,7 @@ impl<'tcx> Repr<'tcx> for UnsizeKind<'tcx> {
UnsizeLength(n) => format!("UnsizeLength({})", n),
UnsizeStruct(ref k, n) => format!("UnsizeStruct({},{})", k.repr(tcx), n),
UnsizeVtable(ref a, ref b) => format!("UnsizeVtable({},{})", a.repr(tcx), b.repr(tcx)),
UnsizeUpcast(ref a) => format!("UnsizeUpcast({})", a.repr(tcx)),
}
}
}

View file

@ -480,6 +480,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::UnsizeKind<'tcx> {
},
self_ty.fold_with(folder))
}
ty::UnsizeUpcast(t) => ty::UnsizeUpcast(t.fold_with(folder)),
}
}
}

View file

@ -1214,17 +1214,17 @@ impl<'tcx> Repr<'tcx> for ty::ExistentialBounds<'tcx> {
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
let mut res = Vec::new();
let region_str = self.region_bound.user_string(tcx);
let region_str = self.region_bound.repr(tcx);
if !region_str.is_empty() {
res.push(region_str);
}
for bound in &self.builtin_bounds {
res.push(bound.user_string(tcx));
res.push(bound.repr(tcx));
}
for projection_bound in &self.projection_bounds {
res.push(projection_bound.user_string(tcx));
res.push(projection_bound.repr(tcx));
}
res.connect("+")