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:
commit
c64d671671
21 changed files with 248 additions and 122 deletions
|
|
@ -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")
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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(..) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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()));
|
||||
|
|
|
|||
|
|
@ -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)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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("+")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue