Skip to content

Commit c64d671

Browse files
committed
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 <#18737 (comment)>. r? @nrc
2 parents 31ba212 + 277b4f0 commit c64d671

File tree

21 files changed

+248
-122
lines changed

21 files changed

+248
-122
lines changed

src/liballoc/boxed.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ pub trait BoxAny {
241241
/// Returns the boxed value if it is of type `T`, or
242242
/// `Err(Self)` if it isn't.
243243
#[stable(feature = "rust1", since = "1.0.0")]
244-
fn downcast<T: 'static>(self) -> Result<Box<T>, Self>;
244+
fn downcast<T: 'static>(self) -> Result<Box<T>, Box<Any>>;
245245
}
246246

247247
#[stable(feature = "rust1", since = "1.0.0")]
@@ -264,6 +264,15 @@ impl BoxAny for Box<Any> {
264264
}
265265
}
266266

267+
#[cfg(not(stage0))]
268+
#[stable(feature = "rust1", since = "1.0.0")]
269+
impl BoxAny for Box<Any+Send> {
270+
#[inline]
271+
fn downcast<T: 'static>(self) -> Result<Box<T>, Box<Any>> {
272+
<Box<Any>>::downcast(self)
273+
}
274+
}
275+
267276
#[stable(feature = "rust1", since = "1.0.0")]
268277
impl<T: fmt::Display + ?Sized> fmt::Display for Box<T> {
269278
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

src/libcore/any.rs

+26
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
7272
#![stable(feature = "rust1", since = "1.0.0")]
7373

74+
use marker::Send;
7475
use mem::transmute;
7576
use option::Option::{self, Some, None};
7677
use raw::TraitObject;
@@ -154,6 +155,31 @@ impl Any {
154155
}
155156
}
156157

158+
#[cfg(not(stage0))]
159+
impl Any+Send {
160+
/// Forwards to the method defined on the type `Any`.
161+
#[stable(feature = "rust1", since = "1.0.0")]
162+
#[inline]
163+
pub fn is<T: 'static>(&self) -> bool {
164+
Any::is::<T>(self)
165+
}
166+
167+
/// Forwards to the method defined on the type `Any`.
168+
#[stable(feature = "rust1", since = "1.0.0")]
169+
#[inline]
170+
pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {
171+
Any::downcast_ref::<T>(self)
172+
}
173+
174+
/// Forwards to the method defined on the type `Any`.
175+
#[stable(feature = "rust1", since = "1.0.0")]
176+
#[inline]
177+
pub fn downcast_mut<T: 'static>(&mut self) -> Option<&mut T> {
178+
Any::downcast_mut::<T>(self)
179+
}
180+
}
181+
182+
157183
///////////////////////////////////////////////////////////////////////////////
158184
// TypeID and its methods
159185
///////////////////////////////////////////////////////////////////////////////

src/librustc/middle/astencode.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -1102,6 +1102,11 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
11021102
this.emit_enum_variant_arg(1, |this| Ok(this.emit_ty(ecx, self_ty)))
11031103
})
11041104
}
1105+
ty::UnsizeUpcast(target_ty) => {
1106+
this.emit_enum_variant("UnsizeUpcast", 3, 1, |this| {
1107+
this.emit_enum_variant_arg(0, |this| Ok(this.emit_ty(ecx, target_ty)))
1108+
})
1109+
}
11051110
}
11061111
});
11071112
}
@@ -1707,7 +1712,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
17071712
fn read_unsize_kind<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
17081713
-> ty::UnsizeKind<'tcx> {
17091714
self.read_enum("UnsizeKind", |this| {
1710-
let variants = &["UnsizeLength", "UnsizeStruct", "UnsizeVtable"];
1715+
let variants = &["UnsizeLength", "UnsizeStruct", "UnsizeVtable", "UnsizeUpcast"];
17111716
this.read_enum_variant(variants, |this, i| {
17121717
Ok(match i {
17131718
0 => {
@@ -1741,6 +1746,11 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
17411746
this.read_enum_variant_arg(1, |this| Ok(this.read_ty(dcx))).unwrap();
17421747
ty::UnsizeVtable(ty_trait, self_ty)
17431748
}
1749+
3 => {
1750+
let target_ty =
1751+
this.read_enum_variant_arg(0, |this| Ok(this.read_ty(dcx))).unwrap();
1752+
ty::UnsizeUpcast(target_ty)
1753+
}
17441754
_ => panic!("bad enum variant for ty::UnsizeKind")
17451755
})
17461756
})

src/librustc/middle/expr_use_visitor.rs

+15-21
Original file line numberDiff line numberDiff line change
@@ -857,36 +857,30 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
857857
n: uint) {
858858
debug!("walk_autoref expr={}", expr.repr(self.tcx()));
859859

860-
// Match for unique trait coercions first, since we don't need the
861-
// call to cat_expr_autoderefd.
862-
match *autoref {
863-
ty::AutoUnsizeUniq(ty::UnsizeVtable(..)) |
864-
ty::AutoUnsize(ty::UnsizeVtable(..)) => {
865-
assert!(n == 1, format!("Expected exactly 1 deref with Uniq \
866-
AutoRefs, found: {}", n));
867-
let cmt_unadjusted =
868-
return_if_err!(self.mc.cat_expr_unadjusted(expr));
869-
self.delegate_consume(expr.id, expr.span, cmt_unadjusted);
870-
return;
871-
}
872-
_ => {}
873-
}
874-
875-
let cmt_derefd = return_if_err!(
876-
self.mc.cat_expr_autoderefd(expr, n));
877-
debug!("walk_adjustment: cmt_derefd={}",
878-
cmt_derefd.repr(self.tcx()));
879-
880860
match *autoref {
881861
ty::AutoPtr(r, m, _) => {
862+
let cmt_derefd = return_if_err!(
863+
self.mc.cat_expr_autoderefd(expr, n));
864+
debug!("walk_adjustment: cmt_derefd={}",
865+
cmt_derefd.repr(self.tcx()));
866+
882867
self.delegate.borrow(expr.id,
883868
expr.span,
884869
cmt_derefd,
885870
r,
886871
ty::BorrowKind::from_mutbl(m),
887872
AutoRef);
888873
}
889-
ty::AutoUnsizeUniq(_) | ty::AutoUnsize(_) | ty::AutoUnsafe(..) => {}
874+
ty::AutoUnsize(_) |
875+
ty::AutoUnsizeUniq(_) => {
876+
assert!(n == 1, format!("Expected exactly 1 deref with Uniq \
877+
AutoRefs, found: {}", n));
878+
let cmt_unadjusted =
879+
return_if_err!(self.mc.cat_expr_unadjusted(expr));
880+
self.delegate_consume(expr.id, expr.span, cmt_unadjusted);
881+
}
882+
ty::AutoUnsafe(..) => {
883+
}
890884
}
891885
}
892886

src/librustc/middle/infer/combine.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -314,9 +314,18 @@ pub trait Combine<'tcx> : Sized {
314314
}
315315

316316
fn builtin_bounds(&self,
317-
a: ty::BuiltinBounds,
318-
b: ty::BuiltinBounds)
319-
-> cres<'tcx, ty::BuiltinBounds>;
317+
a: BuiltinBounds,
318+
b: BuiltinBounds)
319+
-> cres<'tcx, BuiltinBounds>
320+
{
321+
// Two sets of builtin bounds are only relatable if they are
322+
// precisely the same (but see the coercion code).
323+
if a != b {
324+
Err(ty::terr_builtin_bounds(expected_found(self, a, b)))
325+
} else {
326+
Ok(a)
327+
}
328+
}
320329

321330
fn trait_refs(&self,
322331
a: &ty::TraitRef<'tcx>,

src/librustc/middle/infer/equate.rs

-18
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use middle::ty::{BuiltinBounds};
1211
use middle::ty::{self, Ty};
1312
use middle::ty::TyVar;
1413
use middle::infer::combine::*;
@@ -73,23 +72,6 @@ impl<'f, 'tcx> Combine<'tcx> for Equate<'f, 'tcx> {
7372
}
7473
}
7574

76-
fn builtin_bounds(&self,
77-
a: BuiltinBounds,
78-
b: BuiltinBounds)
79-
-> cres<'tcx, BuiltinBounds>
80-
{
81-
// More bounds is a subtype of fewer bounds.
82-
//
83-
// e.g., fn:Copy() <: fn(), because the former is a function
84-
// that only closes over copyable things, but the latter is
85-
// any function at all.
86-
if a != b {
87-
Err(ty::terr_builtin_bounds(expected_found(self, a, b)))
88-
} else {
89-
Ok(a)
90-
}
91-
}
92-
9375
fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
9476
debug!("{}.tys({}, {})", self.tag(),
9577
a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx));

src/librustc/middle/infer/glb.rs

-10
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ use super::higher_ranked::HigherRankedRelations;
1414
use super::{cres};
1515
use super::Subtype;
1616

17-
use middle::ty::{BuiltinBounds};
1817
use middle::ty::{self, Ty};
1918
use syntax::ast::{MutImmutable, MutMutable, Unsafety};
2019
use util::ppaux::mt_to_string;
@@ -94,15 +93,6 @@ impl<'f, 'tcx> Combine<'tcx> for Glb<'f, 'tcx> {
9493
}
9594
}
9695

97-
fn builtin_bounds(&self,
98-
a: ty::BuiltinBounds,
99-
b: ty::BuiltinBounds)
100-
-> cres<'tcx, ty::BuiltinBounds> {
101-
// More bounds is a subtype of fewer bounds, so
102-
// the GLB (mutual subtype) is the union.
103-
Ok(a.union(b))
104-
}
105-
10696
fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> {
10797
debug!("{}.regions({}, {})",
10898
self.tag(),

src/librustc/middle/infer/lub.rs

-10
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ use super::lattice::*;
1414
use super::{cres};
1515
use super::{Subtype};
1616

17-
use middle::ty::{BuiltinBounds};
1817
use middle::ty::{self, Ty};
1918
use syntax::ast::{MutMutable, MutImmutable, Unsafety};
2019
use util::ppaux::mt_to_string;
@@ -89,15 +88,6 @@ impl<'f, 'tcx> Combine<'tcx> for Lub<'f, 'tcx> {
8988
}
9089
}
9190

92-
fn builtin_bounds(&self,
93-
a: ty::BuiltinBounds,
94-
b: ty::BuiltinBounds)
95-
-> cres<'tcx, ty::BuiltinBounds> {
96-
// More bounds is a subtype of fewer bounds, so
97-
// the LUB (mutual supertype) is the intersection.
98-
Ok(a.intersection(b))
99-
}
100-
10191
fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> {
10292
debug!("{}.regions({}, {})",
10393
self.tag(),

src/librustc/middle/infer/sub.rs

-15
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ use super::higher_ranked::HigherRankedRelations;
1414
use super::{Subtype};
1515
use super::type_variable::{SubtypeOf, SupertypeOf};
1616

17-
use middle::ty::{BuiltinBounds};
1817
use middle::ty::{self, Ty};
1918
use middle::ty::TyVar;
2019
use util::ppaux::{Repr};
@@ -97,20 +96,6 @@ impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> {
9796
})
9897
}
9998

100-
fn builtin_bounds(&self, a: BuiltinBounds, b: BuiltinBounds)
101-
-> cres<'tcx, BuiltinBounds> {
102-
// More bounds is a subtype of fewer bounds.
103-
//
104-
// e.g., fn:Copy() <: fn(), because the former is a function
105-
// that only closes over copyable things, but the latter is
106-
// any function at all.
107-
if a.is_superset(&b) {
108-
Ok(a)
109-
} else {
110-
Err(ty::terr_builtin_bounds(expected_found(self, a, b)))
111-
}
112-
}
113-
11499
fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
115100
debug!("{}.tys({}, {})", self.tag(),
116101
a.repr(self.tcx()), b.repr(self.tcx()));

src/librustc/middle/ty.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,8 @@ pub enum UnsizeKind<'tcx> {
292292
// An unsize coercion applied to the tail field of a struct.
293293
// The uint is the index of the type parameter which is unsized.
294294
UnsizeStruct(Box<UnsizeKind<'tcx>>, uint),
295-
UnsizeVtable(TyTrait<'tcx>, /* the self type of the trait */ Ty<'tcx>)
295+
UnsizeVtable(TyTrait<'tcx>, /* the self type of the trait */ Ty<'tcx>),
296+
UnsizeUpcast(Ty<'tcx>),
296297
}
297298

298299
#[derive(Clone, Debug)]
@@ -4631,6 +4632,9 @@ pub fn unsize_ty<'tcx>(cx: &ctxt<'tcx>,
46314632
&UnsizeVtable(TyTrait { ref principal, ref bounds }, _) => {
46324633
mk_trait(cx, principal.clone(), bounds.clone())
46334634
}
4635+
&UnsizeUpcast(target_ty) => {
4636+
target_ty
4637+
}
46344638
}
46354639
}
46364640

@@ -6853,6 +6857,7 @@ impl<'tcx> Repr<'tcx> for UnsizeKind<'tcx> {
68536857
UnsizeLength(n) => format!("UnsizeLength({})", n),
68546858
UnsizeStruct(ref k, n) => format!("UnsizeStruct({},{})", k.repr(tcx), n),
68556859
UnsizeVtable(ref a, ref b) => format!("UnsizeVtable({},{})", a.repr(tcx), b.repr(tcx)),
6860+
UnsizeUpcast(ref a) => format!("UnsizeUpcast({})", a.repr(tcx)),
68566861
}
68576862
}
68586863
}

src/librustc/middle/ty_fold.rs

+1
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::UnsizeKind<'tcx> {
480480
},
481481
self_ty.fold_with(folder))
482482
}
483+
ty::UnsizeUpcast(t) => ty::UnsizeUpcast(t.fold_with(folder)),
483484
}
484485
}
485486
}

src/librustc/util/ppaux.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1214,17 +1214,17 @@ impl<'tcx> Repr<'tcx> for ty::ExistentialBounds<'tcx> {
12141214
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
12151215
let mut res = Vec::new();
12161216

1217-
let region_str = self.region_bound.user_string(tcx);
1217+
let region_str = self.region_bound.repr(tcx);
12181218
if !region_str.is_empty() {
12191219
res.push(region_str);
12201220
}
12211221

12221222
for bound in &self.builtin_bounds {
1223-
res.push(bound.user_string(tcx));
1223+
res.push(bound.repr(tcx));
12241224
}
12251225

12261226
for projection_bound in &self.projection_bounds {
1227-
res.push(projection_bound.user_string(tcx));
1227+
res.push(projection_bound.repr(tcx));
12281228
}
12291229

12301230
res.connect("+")

src/librustc_trans/trans/consts.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -311,12 +311,16 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
311311
llconst = addr_of(cx, llconst, "autoref", e.id);
312312
}
313313
Some(box ty::AutoUnsize(ref k)) => {
314-
let info = expr::unsized_info(cx, k, e.id, ty, param_substs,
315-
|t| ty::mk_imm_rptr(cx.tcx(), cx.tcx().mk_region(ty::ReStatic), t));
314+
let info =
315+
expr::unsized_info(
316+
cx, k, e.id, ty, param_substs,
317+
|t| ty::mk_imm_rptr(cx.tcx(), cx.tcx().mk_region(ty::ReStatic), t),
318+
|| const_get_elt(cx, llconst, &[abi::FAT_PTR_EXTRA as u32]));
316319

317320
let unsized_ty = ty::unsize_ty(cx.tcx(), ty, k, e.span);
318321
let ptr_ty = type_of::in_memory_type_of(cx, unsized_ty).ptr_to();
319322
let base = ptrcast(llconst, ptr_ty);
323+
320324
let prev_const = cx.const_unsized().borrow_mut()
321325
.insert(base, llconst);
322326
assert!(prev_const.is_none() || prev_const == Some(llconst));

0 commit comments

Comments
 (0)