提交 4e8e6414 编写于 作者: E Eduard Burtescu 提交者: Nick Cameron

eddyb's refactoring of coercions/adjustments

上级 a4eb5a66
此差异已折叠。
......@@ -787,23 +787,30 @@ fn contains_field_named(field: &ty::field,
// process.
fn walk_adjustment(&mut self, expr: &ast::Expr) {
let typer = self.typer;
match typer.adjustments().borrow().get(&expr.id) {
None => { }
Some(adjustment) => {
match *adjustment {
ty::AdjustReifyFnPointer(..) |
ty::AdjustUnsafeFnPointer(..) => {
// Creating a closure/fn-pointer consumes the
// input and stores it into the resulting
// rvalue.
debug!("walk_adjustment(AutoAddEnv|AdjustReifyFnPointer)");
if let Some(adjustment) = typer.adjustments().borrow().get(&expr.id) {
match *adjustment {
ty::AdjustReifyFnPointer |
ty::AdjustUnsafeFnPointer => {
// Creating a closure/fn-pointer or unsizing consumes
// the input and stores it into the resulting rvalue.
debug!("walk_adjustment(AdjustReifyFnPointer|AdjustUnsafeFnPointer)");
let cmt_unadjusted =
return_if_err!(self.mc.cat_expr_unadjusted(expr));
self.delegate_consume(expr.id, expr.span, cmt_unadjusted);
}
ty::AdjustDerefRef(ref adj) => {
self.walk_autoderefs(expr, adj.autoderefs);
if let Some(ref r) = adj.autoref {
self.walk_autoref(expr, r, adj.autoderefs);
} else if adj.unsize.is_some() {
assert!(adj.autoderefs == 0,
format!("Expected no derefs with \
unsize AutoRefs, found: {}",
adj.repr(self.tcx())));
let cmt_unadjusted =
return_if_err!(self.mc.cat_expr_unadjusted(expr));
self.delegate_consume(expr.id, expr.span, cmt_unadjusted);
}
ty::AdjustDerefRef(ref adj) => {
self.walk_autoderefref(expr, adj);
}
}
}
}
......@@ -818,7 +825,7 @@ fn walk_autoderefs(&mut self,
debug!("walk_autoderefs expr={} autoderefs={}", expr.repr(self.tcx()), autoderefs);
for i in 0..autoderefs {
let deref_id = ty::MethodCall::autoderef(expr.id, i);
let deref_id = ty::MethodCall::autoderef(expr.id, i as u32);
match self.typer.node_method_ty(deref_id) {
None => {}
Some(method_ty) => {
......@@ -903,59 +910,22 @@ fn walk_autoref(&mut self,
}
};
match *autoref {
ty::AutoPtr(r, m, ref baseref) => {
let cmt_base = self.walk_autoref_recursively(expr, cmt_derefd, baseref);
let cmt_base = self.walk_autoref_recursively(expr, cmt_derefd, baseref);
debug!("walk_autoref: expr.id={} cmt_base={}",
expr.id,
cmt_base.repr(self.tcx()));
debug!("walk_autoref: expr.id={} cmt_base={}",
expr.id,
cmt_base.repr(self.tcx()));
match *autoref {
ty::AutoPtr(r, m) => {
self.delegate.borrow(expr.id,
expr.span,
cmt_base,
r,
cmt_derefd,
*r,
ty::BorrowKind::from_mutbl(m),
AutoRef);
}
ty::AutoUnsize(_) => {
// Converting a `[T; N]` to `[T]` or `T` to `Trait`
// isn't really a borrow, move, etc, in and of itself.
// Also, no recursive step here, this is a base case.
// It may seem a bit odd to return the cmt_derefd
// unmodified here, but in fact I think it's the right
// thing to do. Essentially the unsize transformation
// isn't really relevant to the borrowing rules --
// it's best thought of as a kind of side-modifier to
// the autoref, adding additional data that is
// attached to the pointer that is produced, but not
// affecting the data being borrowed in any other
// way. To see what I mean, consider this example:
//
// fn foo<'a>(&'a self) -> &'a Trait { self }
//
// This is valid because the underlying `self` value
// lives for the lifetime 'a. If we were to treat the
// "unsizing" as e.g. producing an rvalue, that would
// only be valid for the temporary scope, which isn't
// enough to justify the return value, which have the
// lifetime 'a.
//
// Another option would be to add a variant for
// categorization (like downcast) that wraps
// cmt_derefd and represents the unsizing operation.
// But I don't think there is any particular use for
// this (yet). -nmatsakis
return cmt_derefd.clone();
}
ty::AutoUnsizeUniq(_) => {
// these are handled via special case above
self.tcx().sess.span_bug(expr.span, "nexpected AutoUnsizeUniq");
}
ty::AutoUnsafe(m, ref baseref) => {
let cmt_base = self.walk_autoref_recursively(expr, cmt_derefd, baseref);
......
......@@ -451,33 +451,23 @@ pub fn cat_expr(&self, expr: &ast::Expr) -> McResult<cmt<'tcx>> {
Some(adjustment) => {
match *adjustment {
ty::AdjustReifyFnPointer(..) |
ty::AdjustUnsafeFnPointer(..) => {
debug!("cat_expr(AdjustReifyFnPointer): {}",
expr.repr(self.tcx()));
// Convert a bare fn to a closure by adding NULL env.
// Result is an rvalue.
let expr_ty = try!(self.expr_ty_adjusted(expr));
Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty))
}
ty::AdjustDerefRef(
ty::AutoDerefRef {
autoref: Some(_), ..}) => {
debug!("cat_expr(AdjustDerefRef): {}",
autoref: None, unsize: None, autoderefs, ..}) => {
// Equivalent to *expr or something similar.
self.cat_expr_autoderefd(expr, autoderefs)
}
ty::AdjustReifyFnPointer |
ty::AdjustUnsafeFnPointer |
ty::AdjustDerefRef(_) => {
debug!("cat_expr({}): {}",
adjustment.repr(self.tcx()),
expr.repr(self.tcx()));
// Equivalent to &*expr or something similar.
// Result is an rvalue.
let expr_ty = try!(self.expr_ty_adjusted(expr));
Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty))
}
ty::AdjustDerefRef(
ty::AutoDerefRef {
autoref: None, autoderefs}) => {
// Equivalent to *expr or something similar.
self.cat_expr_autoderefd(expr, autoderefs)
}
}
}
}
......@@ -928,15 +918,9 @@ fn cat_deref<N:ast_node>(&self,
deref_cnt: usize,
deref_context: DerefKindContext)
-> McResult<cmt<'tcx>> {
let adjustment = match self.typer.adjustments().borrow().get(&node.id()) {
Some(adj) if ty::adjust_is_object(adj) => ty::AutoObject,
_ if deref_cnt != 0 => ty::AutoDeref(deref_cnt),
_ => ty::NoAdjustment
};
let method_call = ty::MethodCall {
expr_id: node.id(),
adjustment: adjustment
autoderef: deref_cnt as u32
};
let method_ty = self.typer.node_method_ty(method_call);
......
......@@ -20,7 +20,6 @@
pub use self::Variance::*;
pub use self::AutoAdjustment::*;
pub use self::Representability::*;
pub use self::UnsizeKind::*;
pub use self::AutoRef::*;
pub use self::ExprKind::*;
pub use self::DtorKind::*;
......@@ -33,7 +32,6 @@
pub use self::BoundRegion::*;
pub use self::sty::*;
pub use self::IntVarValue::*;
pub use self::ExprAdjustment::*;
pub use self::vtable_origin::*;
pub use self::MethodOrigin::*;
pub use self::CopyImplementationError::*;
......@@ -283,145 +281,34 @@ pub enum Variance {
Bivariant, // T<A> <: T<B> -- e.g., unused type parameter
}
#[derive(Clone, Debug)]
#[derive(Copy, Clone, Debug)]
pub enum AutoAdjustment<'tcx> {
AdjustReifyFnPointer(ast::DefId), // go from a fn-item type to a fn-pointer type
AdjustReifyFnPointer, // go from a fn-item type to a fn-pointer type
AdjustUnsafeFnPointer, // go from a safe fn pointer to an unsafe fn pointer
AdjustDerefRef(AutoDerefRef<'tcx>)
}
#[derive(Clone, PartialEq, Debug)]
pub enum UnsizeKind<'tcx> {
// [T, ..n] -> [T], the usize field is n.
UnsizeLength(usize),
// An unsize coercion applied to the tail field of a struct.
// The usize is the index of the type parameter which is unsized.
UnsizeStruct(Box<UnsizeKind<'tcx>>, usize),
UnsizeVtable(TyTrait<'tcx>, /* the self type of the trait */ Ty<'tcx>),
UnsizeUpcast(Ty<'tcx>),
AdjustDerefRef(AutoDerefRef<'tcx>),
}
#[derive(Clone, Debug)]
#[derive(Copy, Clone, Debug)]
pub struct AutoDerefRef<'tcx> {
/// Apply a number of dereferences, producing an lvalue.
pub autoderefs: usize,
pub autoref: Option<AutoRef<'tcx>>
/// Produce a pointer/reference from the value.
pub autoref: Option<AutoRef<'tcx>>,
/// Unsize a pointer/reference value, e.g. &[T; n] to &[T].
/// The stored type is the target pointer type.
pub unsize: Option<Ty<'tcx>>,
}
#[derive(Clone, PartialEq, Debug)]
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum AutoRef<'tcx> {
/// Convert from T to &T
/// The third field allows us to wrap other AutoRef adjustments.
AutoPtr(Region, ast::Mutability, Option<Box<AutoRef<'tcx>>>),
/// Convert [T, ..n] to [T] (or similar, depending on the kind)
AutoUnsize(UnsizeKind<'tcx>),
/// Convert Box<[T, ..n]> to Box<[T]> or something similar in a Box.
/// With DST and Box a library type, this should be replaced by UnsizeStruct.
AutoUnsizeUniq(UnsizeKind<'tcx>),
AutoPtr(&'tcx Region, ast::Mutability),
/// Convert from T to *T
/// Value to thin pointer
/// The second field allows us to wrap other AutoRef adjustments.
AutoUnsafe(ast::Mutability, Option<Box<AutoRef<'tcx>>>),
}
// Ugly little helper function. The first bool in the returned tuple is true if
// there is an 'unsize to trait object' adjustment at the bottom of the
// adjustment. If that is surrounded by an AutoPtr, then we also return the
// region of the AutoPtr (in the third argument). The second bool is true if the
// adjustment is unique.
fn autoref_object_region(autoref: &AutoRef) -> (bool, bool, Option<Region>) {
fn unsize_kind_is_object(k: &UnsizeKind) -> bool {
match k {
&UnsizeVtable(..) => true,
&UnsizeStruct(box ref k, _) => unsize_kind_is_object(k),
_ => false
}
}
match autoref {
&AutoUnsize(ref k) => (unsize_kind_is_object(k), false, None),
&AutoUnsizeUniq(ref k) => (unsize_kind_is_object(k), true, None),
&AutoPtr(adj_r, _, Some(box ref autoref)) => {
let (b, u, r) = autoref_object_region(autoref);
if r.is_some() || u {
(b, u, r)
} else {
(b, u, Some(adj_r))
}
}
&AutoUnsafe(_, Some(box ref autoref)) => autoref_object_region(autoref),
_ => (false, false, None)
}
}
// If the adjustment introduces a borrowed reference to a trait object, then
// returns the region of the borrowed reference.
pub fn adjusted_object_region(adj: &AutoAdjustment) -> Option<Region> {
match adj {
&AdjustDerefRef(AutoDerefRef{autoref: Some(ref autoref), ..}) => {
let (b, _, r) = autoref_object_region(autoref);
if b {
r
} else {
None
}
}
_ => None
}
}
// Returns true if there is a trait cast at the bottom of the adjustment.
pub fn adjust_is_object(adj: &AutoAdjustment) -> bool {
match adj {
&AdjustDerefRef(AutoDerefRef{autoref: Some(ref autoref), ..}) => {
let (b, _, _) = autoref_object_region(autoref);
b
}
_ => false
}
}
// If possible, returns the type expected from the given adjustment. This is not
// possible if the adjustment depends on the type of the adjusted expression.
pub fn type_of_adjust<'tcx>(cx: &ctxt<'tcx>, adj: &AutoAdjustment<'tcx>) -> Option<Ty<'tcx>> {
fn type_of_autoref<'tcx>(cx: &ctxt<'tcx>, autoref: &AutoRef<'tcx>) -> Option<Ty<'tcx>> {
match autoref {
&AutoUnsize(ref k) => match k {
&UnsizeVtable(TyTrait { ref principal, ref bounds }, _) => {
Some(mk_trait(cx, principal.clone(), bounds.clone()))
}
_ => None
},
&AutoUnsizeUniq(ref k) => match k {
&UnsizeVtable(TyTrait { ref principal, ref bounds }, _) => {
Some(mk_uniq(cx, mk_trait(cx, principal.clone(), bounds.clone())))
}
_ => None
},
&AutoPtr(r, m, Some(box ref autoref)) => {
match type_of_autoref(cx, autoref) {
Some(ty) => Some(mk_rptr(cx, cx.mk_region(r), mt {mutbl: m, ty: ty})),
None => None
}
}
&AutoUnsafe(m, Some(box ref autoref)) => {
match type_of_autoref(cx, autoref) {
Some(ty) => Some(mk_ptr(cx, mt {mutbl: m, ty: ty})),
None => None
}
}
_ => None
}
}
match adj {
&AdjustDerefRef(AutoDerefRef{autoref: Some(ref autoref), ..}) => {
type_of_autoref(cx, autoref)
}
_ => None
}
AutoUnsafe(ast::Mutability),
}
#[derive(Clone, Copy, RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Debug)]
......@@ -509,35 +396,21 @@ pub struct MethodCallee<'tcx> {
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct MethodCall {
pub expr_id: ast::NodeId,
pub adjustment: ExprAdjustment
}
#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable, Copy)]
pub enum ExprAdjustment {
NoAdjustment,
AutoDeref(usize),
AutoObject
pub autoderef: u32
}
impl MethodCall {
pub fn expr(id: ast::NodeId) -> MethodCall {
MethodCall {
expr_id: id,
adjustment: NoAdjustment
}
}
pub fn autoobject(id: ast::NodeId) -> MethodCall {
MethodCall {
expr_id: id,
adjustment: AutoObject
autoderef: 0
}
}
pub fn autoderef(expr_id: ast::NodeId, autoderef: usize) -> MethodCall {
MethodCall {
expr_id: expr_id,
adjustment: AutoDeref(1 + autoderef)
autoderef: 1 + autoderef
}
}
}
......@@ -4581,16 +4454,15 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>,
return match adjustment {
Some(adjustment) => {
match *adjustment {
AdjustReifyFnPointer(_) => {
AdjustReifyFnPointer => {
match unadjusted_ty.sty {
ty::ty_bare_fn(Some(_), b) => {
ty::mk_bare_fn(cx, None, b)
}
ref b => {
_ => {
cx.sess.bug(
&format!("AdjustReifyFnPointer adjustment on non-fn-item: \
{:?}",
b));
{}", unadjusted_ty.repr(cx)));
}
}
}
......@@ -4612,7 +4484,7 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>,
if !ty::type_is_error(adjusted_ty) {
for i in 0..adj.autoderefs {
let method_call = MethodCall::autoderef(expr_id, i);
let method_call = MethodCall::autoderef(expr_id, i as u32);
match method_type(method_call) {
Some(method_ty) => {
// overloaded deref operators have all late-bound
......@@ -4639,7 +4511,11 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>,
}
}
adjust_ty_for_autoref(cx, span, adjusted_ty, adj.autoref.as_ref())
if let Some(target) = adj.unsize {
target
} else {
adjust_ty_for_autoref(cx, adjusted_ty, adj.autoref)
}
}
}
}
......@@ -4648,73 +4524,16 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>,
}
pub fn adjust_ty_for_autoref<'tcx>(cx: &ctxt<'tcx>,
span: Span,
ty: Ty<'tcx>,
autoref: Option<&AutoRef<'tcx>>)
-> Ty<'tcx>
{
autoref: Option<AutoRef<'tcx>>)
-> Ty<'tcx> {
match autoref {
None => ty,
Some(&AutoPtr(r, m, ref a)) => {
let adjusted_ty = match a {
&Some(box ref a) => adjust_ty_for_autoref(cx, span, ty, Some(a)),
&None => ty
};
mk_rptr(cx, cx.mk_region(r), mt {
ty: adjusted_ty,
mutbl: m
})
Some(AutoPtr(r, m)) => {
mk_rptr(cx, r, mt { ty: ty, mutbl: m })
}
Some(&AutoUnsafe(m, ref a)) => {
let adjusted_ty = match a {
&Some(box ref a) => adjust_ty_for_autoref(cx, span, ty, Some(a)),
&None => ty
};
mk_ptr(cx, mt {ty: adjusted_ty, mutbl: m})
}
Some(&AutoUnsize(ref k)) => unsize_ty(cx, ty, k, span),
Some(&AutoUnsizeUniq(ref k)) => ty::mk_uniq(cx, unsize_ty(cx, ty, k, span)),
}
}
// Take a sized type and a sizing adjustment and produce an unsized version of
// the type.
pub fn unsize_ty<'tcx>(cx: &ctxt<'tcx>,
ty: Ty<'tcx>,
kind: &UnsizeKind<'tcx>,
span: Span)
-> Ty<'tcx> {
match kind {
&UnsizeLength(len) => match ty.sty {
ty_vec(ty, Some(n)) => {
assert!(len == n);
mk_vec(cx, ty, None)
}
_ => cx.sess.span_bug(span,
&format!("UnsizeLength with bad sty: {:?}",
ty_to_string(cx, ty)))
},
&UnsizeStruct(box ref k, tp_index) => match ty.sty {
ty_struct(did, substs) => {
let ty_substs = substs.types.get_slice(subst::TypeSpace);
let new_ty = unsize_ty(cx, ty_substs[tp_index], k, span);
let mut unsized_substs = substs.clone();
unsized_substs.types.get_mut_slice(subst::TypeSpace)[tp_index] = new_ty;
mk_struct(cx, did, cx.mk_substs(unsized_substs))
}
_ => cx.sess.span_bug(span,
&format!("UnsizeStruct with bad sty: {:?}",
ty_to_string(cx, ty)))
},
&UnsizeVtable(TyTrait { ref principal, ref bounds }, _) => {
mk_trait(cx, principal.clone(), bounds.clone())
}
&UnsizeUpcast(target_ty) => {
target_ty
Some(AutoUnsafe(m)) => {
mk_ptr(cx, mt { ty: ty, mutbl: m })
}
}
}
......@@ -5971,6 +5790,47 @@ pub fn tup_fields<'tcx>(v: &[Ty<'tcx>]) -> Vec<field<'tcx>> {
}).collect()
}
/// Returns the deeply last field of nested structures, or the same type,
/// if not a structure at all. Corresponds to the only possible unsized
/// field, and its type can be used to determine unsizing strategy.
pub fn struct_tail<'tcx>(cx: &ctxt<'tcx>, mut ty: Ty<'tcx>) -> Ty<'tcx> {
while let ty_struct(def_id, substs) = ty.sty {
match struct_fields(cx, def_id, substs).last() {
Some(f) => ty = f.mt.ty,
None => break
}
}
ty
}
/// Same as applying struct_tail on `source` and `target`, but only
/// keeps going as long as the two types are instances of the same
/// structure definitions.
/// For `(Foo<Foo<T>>, Foo<Trait>)`, the result will be `(Foo<T>, Trait)`,
/// whereas struct_tail produces `T`, and `Trait`, respectively.
pub fn struct_lockstep_tails<'tcx>(cx: &ctxt<'tcx>,
source: Ty<'tcx>,
target: Ty<'tcx>)
-> (Ty<'tcx>, Ty<'tcx>) {
let (mut a, mut b) = (source, target);
while let (&ty_struct(a_did, a_substs), &ty_struct(b_did, b_substs)) = (&a.sty, &b.sty) {
if a_did != b_did {
continue;
}
if let Some(a_f) = struct_fields(cx, a_did, a_substs).last() {
if let Some(b_f) = struct_fields(cx, b_did, b_substs).last() {
a = a_f.mt.ty;
b = b_f.mt.ty;
} else {
break;
}
} else {
break;
}
}
(a, b)
}
#[derive(Copy, Clone)]
pub struct ClosureUpvar<'tcx> {
pub def: def::Def,
......@@ -6881,8 +6741,8 @@ pub fn with_freevars<T, F>(tcx: &ty::ctxt, fid: ast::NodeId, f: F) -> T where
impl<'tcx> AutoAdjustment<'tcx> {
pub fn is_identity(&self) -> bool {
match *self {
AdjustReifyFnPointer(..) => false,
AdjustUnsafeFnPointer(..) => false,
AdjustReifyFnPointer |
AdjustUnsafeFnPointer => false,
AdjustDerefRef(ref r) => r.is_identity(),
}
}
......@@ -6890,7 +6750,7 @@ pub fn is_identity(&self) -> bool {
impl<'tcx> AutoDerefRef<'tcx> {
pub fn is_identity(&self) -> bool {
self.autoderefs == 0 && self.autoref.is_none()
self.autoderefs == 0 && self.unsize.is_none() && self.autoref.is_none()
}
}
......@@ -7051,8 +6911,8 @@ pub fn shifted(&self, amount: u32) -> DebruijnIndex {
impl<'tcx> Repr<'tcx> for AutoAdjustment<'tcx> {
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
match *self {
AdjustReifyFnPointer(def_id) => {
format!("AdjustReifyFnPointer({})", def_id.repr(tcx))
AdjustReifyFnPointer => {
format!("AdjustReifyFnPointer")
}
AdjustUnsafeFnPointer => {
format!("AdjustUnsafeFnPointer")
......@@ -7064,37 +6924,21 @@ fn repr(&self, tcx: &ctxt<'tcx>) -> String {
}
}
impl<'tcx> Repr<'tcx> for UnsizeKind<'tcx> {
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
match *self {
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)),
}
}
}
impl<'tcx> Repr<'tcx> for AutoDerefRef<'tcx> {
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
format!("AutoDerefRef({}, {})", self.autoderefs, self.autoref.repr(tcx))
format!("AutoDerefRef({}, unsize={}, {})",
self.autoderefs, self.unsize.repr(tcx), self.autoref.repr(tcx))
}
}
impl<'tcx> Repr<'tcx> for AutoRef<'tcx> {
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
match *self {
AutoPtr(a, b, ref c) => {
format!("AutoPtr({},{:?},{})", a.repr(tcx), b, c.repr(tcx))
}
AutoUnsize(ref a) => {
format!("AutoUnsize({})", a.repr(tcx))
}
AutoUnsizeUniq(ref a) => {
format!("AutoUnsizeUniq({})", a.repr(tcx))
AutoPtr(a, b) => {
format!("AutoPtr({},{:?})", a.repr(tcx), b)
}
AutoUnsafe(ref a, ref b) => {
format!("AutoUnsafe({:?},{})", a, b.repr(tcx))
AutoUnsafe(ref a) => {
format!("AutoUnsafe({:?})", a)
}
}
}
......
......@@ -477,24 +477,6 @@ fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::InstantiatedPred
}
}
impl<'tcx> TypeFoldable<'tcx> for ty::UnsizeKind<'tcx> {
fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::UnsizeKind<'tcx> {
match *self {
ty::UnsizeLength(len) => ty::UnsizeLength(len),
ty::UnsizeStruct(box ref k, n) => ty::UnsizeStruct(box k.fold_with(folder), n),
ty::UnsizeVtable(ty::TyTrait{ref principal, ref bounds}, self_ty) => {
ty::UnsizeVtable(
ty::TyTrait {
principal: principal.fold_with(folder),
bounds: bounds.fold_with(folder),
},
self_ty.fold_with(folder))
}
ty::UnsizeUpcast(t) => ty::UnsizeUpcast(t.fold_with(folder)),
}
}
}
impl<'tcx,O> TypeFoldable<'tcx> for traits::Obligation<'tcx,O>
where O : TypeFoldable<'tcx>
{
......@@ -768,16 +750,11 @@ pub fn super_fold_autoref<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
-> ty::AutoRef<'tcx>
{
match *autoref {
ty::AutoPtr(r, m, None) => ty::AutoPtr(this.fold_region(r), m, None),
ty::AutoPtr(r, m, Some(ref a)) => {
ty::AutoPtr(this.fold_region(r), m, Some(box super_fold_autoref(this, &**a)))
}
ty::AutoUnsafe(m, None) => ty::AutoUnsafe(m, None),
ty::AutoUnsafe(m, Some(ref a)) => {
ty::AutoUnsafe(m, Some(box super_fold_autoref(this, &**a)))
ty::AutoPtr(r, m) => {
let r = r.fold_with(this);
ty::AutoPtr(this.tcx().mk_region(r), m)
}
ty::AutoUnsize(ref k) => ty::AutoUnsize(k.fold_with(this)),
ty::AutoUnsizeUniq(ref k) => ty::AutoUnsizeUniq(k.fold_with(this)),
ty::AutoUnsafe(m) => ty::AutoUnsafe(m)
}
}
......
......@@ -1405,11 +1405,11 @@ fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
if let Some(adjustment) = cx.tcx.adjustments.borrow().get(&e.id) {
if let ty::AdjustDerefRef(ty::AutoDerefRef { ref autoref, .. }) = *adjustment {
match autoref {
&Some(ty::AutoPtr(_, ast::MutImmutable, None)) => {
&Some(ty::AutoPtr(_, ast::MutImmutable)) => {
cx.span_lint(UNUSED_ALLOCATION, e.span,
"unnecessary allocation, use & instead");
}
&Some(ty::AutoPtr(_, ast::MutMutable, None)) => {
&Some(ty::AutoPtr(_, ast::MutMutable)) => {
cx.span_lint(UNUSED_ALLOCATION, e.span,
"unnecessary allocation, use &mut instead");
}
......
......@@ -146,33 +146,6 @@ pub fn type_is_fat_ptr<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
}
}
// Return the smallest part of `ty` which is unsized. Fails if `ty` is sized.
// 'Smallest' here means component of the static representation of the type; not
// the size of an object at runtime.
pub fn unsized_part_of_type<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
match ty.sty {
ty::ty_str | ty::ty_trait(..) | ty::ty_vec(..) => ty,
ty::ty_struct(def_id, substs) => {
let unsized_fields: Vec<_> =
ty::struct_fields(cx, def_id, substs)
.iter()
.map(|f| f.mt.ty)
.filter(|ty| !type_is_sized(cx, *ty))
.collect();
// Exactly one of the fields must be unsized.
assert!(unsized_fields.len() == 1);
unsized_part_of_type(cx, unsized_fields[0])
}
_ => {
assert!(type_is_sized(cx, ty),
"unsized_part_of_type failed even though ty is unsized");
panic!("called unsized_part_of_type with sized ty");
}
}
}
// Some things don't need cleanups during unwinding because the
// task can free them all at once later. Currently only things
// that only contain scalars and shared boxes can avoid unwind
......
......@@ -254,7 +254,7 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
&ty::expr_ty_adjusted(cx.tcx(), e));
let opt_adj = cx.tcx().adjustments.borrow().get(&e.id).cloned();
match opt_adj {
Some(ty::AdjustReifyFnPointer(_def_id)) => {
Some(ty::AdjustReifyFnPointer) => {
// FIXME(#19925) once fn item types are
// zero-sized, we'll need to do something here
}
......@@ -272,73 +272,56 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
}
}
let second_autoref = match adj.autoref {
None => {
let (dv, dt) = const_deref(cx, llconst, ty);
llconst = dv;
// If we derefed a fat pointer then we will have an
// open type here. So we need to update the type with
// the one returned from const_deref.
ety_adjusted = dt;
None
}
Some(ty::AutoUnsafe(_, opt_autoref)) |
Some(ty::AutoPtr(_, _, opt_autoref)) => {
if adj.autoderefs == 0 {
// Don't copy data to do a deref+ref
// (i.e., skip the last auto-deref).
llconst = addr_of(cx, llconst, "autoref");
} else {
// Seeing as we are deref'ing here and take a reference
// again to make the pointer part of the far pointer below,
// we just skip the whole thing. We still need the type
// though. This works even if we don't need to deref
// because of byref semantics. Note that this is not just
// an optimisation, it is necessary for mutable vectors to
// work properly.
ty = match ty::deref(ty, true) {
Some(mt) => mt.ty,
None => {
cx.sess().bug(&format!("unexpected dereferenceable type {}",
ty_to_string(cx.tcx(), ty)))
}
}
}
opt_autoref
}
Some(autoref) => {
cx.sess().span_bug(e.span,
&format!("unimplemented const first autoref {:?}", autoref))
}
};
match second_autoref {
None => {}
Some(box ty::AutoUnsafe(_, None)) |
Some(box ty::AutoPtr(_, _, None)) => {
if adj.autoref.is_some() {
if adj.autoderefs == 0 {
// Don't copy data to do a deref+ref
// (i.e., skip the last auto-deref).
llconst = addr_of(cx, llconst, "autoref");
ty = ty::mk_imm_rptr(cx.tcx(), cx.tcx().mk_region(ty::ReStatic), ty);
}
Some(box ty::AutoUnsize(ref k)) => {
let info =
expr::unsized_info(
cx, k, e.id, ty, param_substs,
|| const_get_elt(cx, llconst, &[abi::FAT_PTR_EXTRA as u32]));
let unsized_ty = ty::unsize_ty(cx.tcx(), ty, k, e.span);
let ptr_ty = type_of::in_memory_type_of(cx, unsized_ty).ptr_to();
let base = ptrcast(llconst, ptr_ty);
let prev_const = cx.const_unsized().borrow_mut()
.insert(base, llconst);
assert!(prev_const.is_none() || prev_const == Some(llconst));
assert_eq!(abi::FAT_PTR_ADDR, 0);
assert_eq!(abi::FAT_PTR_EXTRA, 1);
llconst = C_struct(cx, &[base, info], false);
}
Some(autoref) => {
cx.sess().span_bug(e.span,
&format!("unimplemented const second autoref {:?}", autoref))
}
} else {
let (dv, dt) = const_deref(cx, llconst, ty);
llconst = dv;
// If we derefed a fat pointer then we will have an
// open type here. So we need to update the type with
// the one returned from const_deref.
ety_adjusted = dt;
}
if let Some(target) = adj.unsize {
let target = monomorphize::apply_param_substs(cx.tcx(),
param_substs,
&target);
let pointee_ty = ty::deref(ty, true)
.expect("consts: unsizing got non-pointer type").ty;
let (base, old_info) = if !type_is_sized(cx.tcx(), pointee_ty) {
// Normally, the source is a thin pointer and we are
// adding extra info to make a fat pointer. The exception
// is when we are upcasting an existing object fat pointer
// to use a different vtable. In that case, we want to
// load out the original data pointer so we can repackage
// it.
(const_get_elt(cx, llconst, &[abi::FAT_PTR_ADDR as u32]),
Some(const_get_elt(cx, llconst, &[abi::FAT_PTR_EXTRA as u32])))
} else {
(llconst, None)
};
let unsized_ty = ty::deref(target, true)
.expect("consts: unsizing got non-pointer target type").ty;
let ptr_ty = type_of::in_memory_type_of(cx, unsized_ty).ptr_to();
let base = ptrcast(base, ptr_ty);
let info = expr::unsized_info(cx, pointee_ty, unsized_ty,
old_info, param_substs);
let prev_const = cx.const_unsized().borrow_mut()
.insert(base, llconst);
assert!(prev_const.is_none() || prev_const == Some(llconst));
assert_eq!(abi::FAT_PTR_ADDR, 0);
assert_eq!(abi::FAT_PTR_EXTRA, 1);
llconst = C_struct(cx, &[base, info], false);
}
}
None => {}
......
......@@ -72,8 +72,7 @@
use trans::tvec;
use trans::type_of;
use middle::ty::{struct_fields, tup_fields};
use middle::ty::{AdjustDerefRef, AdjustReifyFnPointer, AdjustUnsafeFnPointer, AutoUnsafe};
use middle::ty::AutoPtr;
use middle::ty::{AdjustDerefRef, AdjustReifyFnPointer, AdjustUnsafeFnPointer};
use middle::ty::{self, Ty};
use middle::ty::MethodCall;
use util::common::indenter;
......@@ -290,72 +289,39 @@ pub fn copy_fat_ptr(bcx: Block, src_ptr: ValueRef, dst_ptr: ValueRef) {
Store(bcx, Load(bcx, get_len(bcx, src_ptr)), get_len(bcx, dst_ptr));
}
// Retrieve the information we are losing (making dynamic) in an unsizing
// adjustment.
//
// The `unadjusted_val` argument is a bit funny. It is intended
// for use in an upcast, where the new vtable for an object will
// be drived from the old one. Hence it is a pointer to the fat
// pointer.
pub fn unsized_info_bcx<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
kind: &ty::UnsizeKind<'tcx>,
id: ast::NodeId,
unadjusted_ty: Ty<'tcx>,
unadjusted_val: ValueRef, // see above (*)
param_substs: &'tcx subst::Substs<'tcx>)
-> ValueRef {
unsized_info(
bcx.ccx(),
kind,
id,
unadjusted_ty,
param_substs,
|| Load(bcx, GEPi(bcx, unadjusted_val, &[0, abi::FAT_PTR_EXTRA])))
}
// Same as `unsize_info_bcx`, but does not require a bcx -- instead it
// takes an extra closure to compute the upcast vtable.
pub fn unsized_info<'ccx, 'tcx, MK_UPCAST_VTABLE>(
ccx: &CrateContext<'ccx, 'tcx>,
kind: &ty::UnsizeKind<'tcx>,
id: ast::NodeId,
unadjusted_ty: Ty<'tcx>,
param_substs: &'tcx subst::Substs<'tcx>,
mk_upcast_vtable: MK_UPCAST_VTABLE) // see notes above
-> ValueRef
where MK_UPCAST_VTABLE: FnOnce() -> ValueRef
{
debug!("unsized_info(kind={:?}, id={}, unadjusted_ty={})",
kind, id, unadjusted_ty.repr(ccx.tcx()));
match kind {
&ty::UnsizeLength(len) => C_uint(ccx, len),
&ty::UnsizeStruct(box ref k, tp_index) => match unadjusted_ty.sty {
ty::ty_struct(_, ref substs) => {
let ty_substs = substs.types.get_slice(subst::TypeSpace);
unsized_info(ccx, k, id, ty_substs[tp_index], param_substs,
mk_upcast_vtable)
}
_ => ccx.sess().bug(&format!("UnsizeStruct with bad sty: {}",
unadjusted_ty.repr(ccx.tcx())))
},
&ty::UnsizeVtable(ty::TyTrait { ref principal, .. }, _) => {
/// Retrieve the information we are losing (making dynamic) in an unsizing
/// adjustment.
///
/// The `old_info` argument is a bit funny. It is intended for use
/// in an upcast, where the new vtable for an object will be drived
/// from the old one.
pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>,
source: Ty<'tcx>,
target: Ty<'tcx>,
old_info: Option<ValueRef>,
param_substs: &'tcx subst::Substs<'tcx>)
-> ValueRef {
let (source, target) = ty::struct_lockstep_tails(ccx.tcx(), source, target);
match (&source.sty, &target.sty) {
(&ty::ty_vec(_, Some(len)), &ty::ty_vec(_, None)) => C_uint(ccx, len),
(&ty::ty_trait(_), &ty::ty_trait(_)) => {
// For now, upcasts are limited to changes in marker
// traits, and hence never actually require an actual
// change to the vtable.
old_info.expect("unsized_info: missing old info for trait upcast")
}
(_, &ty::ty_trait(box ty::TyTrait { ref principal, .. })) => {
// Note that we preserve binding levels here:
let substs = principal.0.substs.with_self_ty(unadjusted_ty).erase_regions();
let substs = principal.0.substs.with_self_ty(source).erase_regions();
let substs = ccx.tcx().mk_substs(substs);
let trait_ref = ty::Binder(Rc::new(ty::TraitRef { def_id: principal.def_id(),
substs: substs }));
let trait_ref = monomorphize::apply_param_substs(ccx.tcx(),
param_substs,
&trait_ref);
substs: substs }));
consts::ptrcast(meth::get_vtable(ccx, trait_ref, param_substs),
Type::vtable_ptr(ccx))
}
&ty::UnsizeUpcast(_) => {
// For now, upcasts are limited to changes in marker
// traits, and hence never actually require an actual
// change to the vtable.
mk_upcast_vtable()
}
_ => ccx.sess().bug(&format!("unsized_info: invalid unsizing {} -> {}",
source.repr(ccx.tcx()),
target.repr(ccx.tcx())))
}
}
......@@ -379,7 +345,7 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
datum.to_string(bcx.ccx()),
adjustment);
match adjustment {
AdjustReifyFnPointer(_def_id) => {
AdjustReifyFnPointer => {
// FIXME(#19925) once fn item types are
// zero-sized, we'll need to do something here
}
......@@ -387,202 +353,112 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
// purely a type-level thing
}
AdjustDerefRef(ref adj) => {
let (autoderefs, use_autoref) = match adj.autoref {
// Extracting a value from a box counts as a deref, but if we are
// just converting Box<[T, ..n]> to Box<[T]> we aren't really doing
// a deref (and wouldn't if we could treat Box like a normal struct).
Some(ty::AutoUnsizeUniq(..)) => (adj.autoderefs - 1, true),
let skip_reborrows = if adj.autoderefs == 1 && adj.autoref.is_some() {
// We are a bit paranoid about adjustments and thus might have a re-
// borrow here which merely derefs and then refs again (it might have
// a different region or mutability, but we don't care here. It might
// also be just in case we need to unsize. But if there are no nested
// adjustments then it should be a no-op).
Some(ty::AutoPtr(_, _, None)) |
Some(ty::AutoUnsafe(_, None)) if adj.autoderefs == 1 => {
match datum.ty.sty {
// Don't skip a conversion from Box<T> to &T, etc.
ty::ty_rptr(..) => {
let method_call = MethodCall::autoderef(expr.id, adj.autoderefs-1);
let method = bcx.tcx().method_map.borrow().get(&method_call).is_some();
if method {
// Don't skip an overloaded deref.
(adj.autoderefs, true)
} else {
(adj.autoderefs - 1, false)
}
// a different region or mutability, but we don't care here).
match datum.ty.sty {
// Don't skip a conversion from Box<T> to &T, etc.
ty::ty_rptr(..) => {
let method_call = MethodCall::autoderef(expr.id, 0);
if bcx.tcx().method_map.borrow().contains_key(&method_call) {
// Don't skip an overloaded deref.
0
} else {
1
}
_ => (adj.autoderefs, true),
}
_ => 0
}
_ => (adj.autoderefs, true)
} else {
0
};
if autoderefs > 0 {
if adj.autoderefs > skip_reborrows {
// Schedule cleanup.
let lval = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "auto_deref", expr.id));
datum = unpack_datum!(
bcx, deref_multiple(bcx, expr, lval.to_expr_datum(), autoderefs));
datum = unpack_datum!(bcx, deref_multiple(bcx, expr,
lval.to_expr_datum(),
adj.autoderefs - skip_reborrows));
}
// (You might think there is a more elegant way to do this than a
// use_autoref bool, but then you remember that the borrow checker exists).
if let (true, &Some(ref a)) = (use_autoref, &adj.autoref) {
datum = unpack_datum!(bcx, apply_autoref(a,
bcx,
expr,
datum));
// skip_reborrows bool, but then you remember that the borrow checker exists).
if skip_reborrows == 0 && adj.autoref.is_some() {
datum = unpack_datum!(bcx, apply_autoref(bcx, expr, datum));
}
if let Some(target) = adj.unsize {
datum = unpack_datum!(bcx, unsize_pointer(bcx, datum,
bcx.monomorphize(&target)));
}
}
}
debug!("after adjustments, datum={}", datum.to_string(bcx.ccx()));
return DatumBlock::new(bcx, datum);
fn apply_autoref<'blk, 'tcx>(autoref: &ty::AutoRef<'tcx>,
bcx: Block<'blk, 'tcx>,
fn apply_autoref<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
expr: &ast::Expr,
datum: Datum<'tcx, Expr>)
-> DatumBlock<'blk, 'tcx, Expr> {
let mut bcx = bcx;
let mut datum = datum;
let datum = match autoref {
&AutoPtr(_, _, ref a) | &AutoUnsafe(_, ref a) => {
debug!(" AutoPtr");
if let &Some(box ref a) = a {
datum = unpack_datum!(bcx, apply_autoref(a, bcx, expr, datum));
}
if !type_is_sized(bcx.tcx(), datum.ty) {
// Arrange cleanup
let lval = unpack_datum!(bcx,
datum.to_lvalue_datum(bcx, "ref_fat_ptr", expr.id));
unpack_datum!(bcx, ref_fat_ptr(bcx, lval))
} else {
unpack_datum!(bcx, auto_ref(bcx, datum, expr))
}
}
&ty::AutoUnsize(ref k) => {
debug!(" AutoUnsize");
unpack_datum!(bcx, unsize_expr(bcx, expr, datum, k))
}
&ty::AutoUnsizeUniq(ty::UnsizeLength(len)) => {
debug!(" AutoUnsizeUniq(UnsizeLength)");
unpack_datum!(bcx, unsize_unique_vec(bcx, expr, datum, len))
}
&ty::AutoUnsizeUniq(ref k) => {
debug!(" AutoUnsizeUniq");
unpack_datum!(bcx, unsize_unique_expr(bcx, expr, datum, k))
}
};
DatumBlock::new(bcx, datum)
if !type_is_sized(bcx.tcx(), datum.ty) {
// Arrange cleanup
let lval = unpack_datum!(bcx,
datum.to_lvalue_datum(bcx, "ref_fat_ptr", expr.id));
ref_fat_ptr(bcx, lval)
} else {
auto_ref(bcx, datum, expr)
}
}
fn unsize_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
expr: &ast::Expr,
datum: Datum<'tcx, Expr>,
k: &ty::UnsizeKind<'tcx>)
-> DatumBlock<'blk, 'tcx, Expr> {
fn unsize_pointer<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
datum: Datum<'tcx, Expr>,
target: Ty<'tcx>)
-> DatumBlock<'blk, 'tcx, Expr> {
let mut bcx = bcx;
let tcx = bcx.tcx();
let datum_ty = datum.ty;
let unsized_ty = ty::unsize_ty(tcx, datum_ty, k, expr.span);
debug!("unsized_ty={}", unsized_ty.repr(bcx.tcx()));
let info = unsized_info_bcx(bcx, k, expr.id, datum_ty, datum.val, bcx.fcx.param_substs);
// Arrange cleanup
let lval = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "into_fat_ptr", expr.id));
let unsized_ty = ty::deref(target, true)
.expect("expr::unsize got non-pointer target type").ty;
debug!("unsize_lvalue(unsized_ty={})", unsized_ty.repr(bcx.tcx()));
// Compute the base pointer. This doesn't change the pointer value,
// but merely its type.
let ptr_ty = type_of::in_memory_type_of(bcx.ccx(), unsized_ty).ptr_to();
let base = if !type_is_sized(bcx.tcx(), lval.ty) {
// We do not arrange cleanup ourselves; if we already are an
// L-value, then cleanup will have already been scheduled (and
// the `datum.to_rvalue_datum` call below will emit code to zero
// the drop flag when moving out of the L-value). If we are an
// R-value, then we do not need to schedule cleanup.
let datum = unpack_datum!(bcx, datum.to_rvalue_datum(bcx, "__unsize_ref"));
let pointee_ty = ty::deref(datum.ty, true)
.expect("expr::unsize got non-pointer datum type").ty;
let (base, old_info) = if !type_is_sized(bcx.tcx(), pointee_ty) {
// Normally, the source is a thin pointer and we are
// adding extra info to make a fat pointer. The exception
// is when we are upcasting an existing object fat pointer
// to use a different vtable. In that case, we want to
// load out the original data pointer so we can repackage
// it.
Load(bcx, get_dataptr(bcx, lval.val))
(Load(bcx, get_dataptr(bcx, datum.val)),
Some(Load(bcx, get_len(bcx, datum.val))))
} else {
lval.val
(datum.val, None)
};
let info = unsized_info(bcx.ccx(), pointee_ty, unsized_ty,
old_info, bcx.fcx.param_substs);
// Compute the base pointer. This doesn't change the pointer value,
// but merely its type.
let ptr_ty = type_of::in_memory_type_of(bcx.ccx(), unsized_ty).ptr_to();
let base = PointerCast(bcx, base, ptr_ty);
let llty = type_of::type_of(bcx.ccx(), unsized_ty);
let llty = type_of::type_of(bcx.ccx(), target);
// HACK(eddyb) get around issues with lifetime intrinsics.
let scratch = alloca_no_lifetime(bcx, llty, "__fat_ptr");
Store(bcx, base, get_dataptr(bcx, scratch));
Store(bcx, info, get_len(bcx, scratch));
DatumBlock::new(bcx, Datum::new(scratch, unsized_ty, LvalueExpr))
}
fn unsize_unique_vec<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
expr: &ast::Expr,
datum: Datum<'tcx, Expr>,
len: usize)
-> DatumBlock<'blk, 'tcx, Expr> {
let mut bcx = bcx;
let tcx = bcx.tcx();
let datum_ty = datum.ty;
debug!("unsize_unique_vec expr.id={} datum_ty={} len={}",
expr.id, datum_ty.repr(tcx), len);
// We do not arrange cleanup ourselves; if we already are an
// L-value, then cleanup will have already been scheduled (and
// the `datum.store_to` call below will emit code to zero the
// drop flag when moving out of the L-value). If we are an R-value,
// then we do not need to schedule cleanup.
let ll_len = C_uint(bcx.ccx(), len);
let unit_ty = ty::sequence_element_type(tcx, ty::type_content(datum_ty));
let vec_ty = ty::mk_uniq(tcx, ty::mk_vec(tcx, unit_ty, None));
let scratch = rvalue_scratch_datum(bcx, vec_ty, "__unsize_unique");
let base = get_dataptr(bcx, scratch.val);
let base = PointerCast(bcx,
base,
type_of::type_of(bcx.ccx(), datum_ty).ptr_to());
bcx = datum.store_to(bcx, base);
Store(bcx, ll_len, get_len(bcx, scratch.val));
DatumBlock::new(bcx, scratch.to_expr_datum())
}
fn unsize_unique_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
expr: &ast::Expr,
datum: Datum<'tcx, Expr>,
k: &ty::UnsizeKind<'tcx>)
-> DatumBlock<'blk, 'tcx, Expr> {
let mut bcx = bcx;
let tcx = bcx.tcx();
let datum_ty = datum.ty;
let unboxed_ty = match datum_ty.sty {
ty::ty_uniq(t) => t,
_ => bcx.sess().bug(&format!("Expected ty_uniq, found {}",
bcx.ty_to_string(datum_ty)))
};
let result_ty = ty::mk_uniq(tcx, ty::unsize_ty(tcx, unboxed_ty, k, expr.span));
// We do not arrange cleanup ourselves; if we already are an
// L-value, then cleanup will have already been scheduled (and
// the `datum.store_to` call below will emit code to zero the
// drop flag when moving out of the L-value). If we are an R-value,
// then we do not need to schedule cleanup.
let scratch = rvalue_scratch_datum(bcx, result_ty, "__uniq_fat_ptr");
let llbox_ty = type_of::type_of(bcx.ccx(), datum_ty);
let base = PointerCast(bcx, get_dataptr(bcx, scratch.val), llbox_ty.ptr_to());
bcx = datum.store_to(bcx, base);
let info = unsized_info_bcx(bcx, k, expr.id, unboxed_ty, base, bcx.fcx.param_substs);
Store(bcx, info, get_len(bcx, scratch.val));
DatumBlock::new(bcx, scratch.to_expr_datum())
DatumBlock::new(bcx, Datum::new(scratch, target, RvalueExpr(Rvalue::new(ByRef))))
}
}
......@@ -2233,7 +2109,7 @@ fn deref_multiple<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
let mut bcx = bcx;
let mut datum = datum;
for i in 0..times {
let method_call = MethodCall::autoderef(expr.id, i);
let method_call = MethodCall::autoderef(expr.id, i as u32);
datum = unpack_datum!(bcx, deref_once(bcx, expr, datum, method_call));
}
DatumBlock { bcx: bcx, datum: datum }
......@@ -2265,10 +2141,11 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
// converts from the `Smaht<T>` pointer that we have into
// a `&T` pointer. We can then proceed down the normal
// path (below) to dereference that `&T`.
let datum = match method_call.adjustment {
let datum = if method_call.autoderef == 0 {
datum
} else {
// Always perform an AutoPtr when applying an overloaded auto-deref
ty::AutoDeref(_) => unpack_datum!(bcx, auto_ref(bcx, datum, expr)),
_ => datum
unpack_datum!(bcx, auto_ref(bcx, datum, expr))
};
let ref_ty = // invoked methods have their LB regions instantiated
......
......@@ -359,14 +359,14 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
cx.tn().find_type("str_slice").unwrap()
} else {
let ptr_ty = in_memory_type_of(cx, ty).ptr_to();
let unsized_part = unsized_part_of_type(cx.tcx(), ty);
let unsized_part = ty::struct_tail(cx.tcx(), ty);
let info_ty = match unsized_part.sty {
ty::ty_str | ty::ty_vec(..) => {
Type::uint_from_ty(cx, ast::TyUs)
}
ty::ty_trait(_) => Type::vtable_ptr(cx),
_ => panic!("Unexpected type returned from \
unsized_part_of_type: {} for ty={}",
struct_tail: {} for ty={}",
unsized_part.repr(cx.tcx()), ty.repr(cx.tcx()))
};
Type::struct_(cx, &[ptr_ty, info_ty], false)
......
......@@ -59,6 +59,7 @@
use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, ExplicitRscope,
ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope};
use util::common::{ErrorReported, FN_OUTPUT_NAME};
use util::nodemap::FnvHashSet;
use util::ppaux::{self, Repr, UserString};
use std::iter::repeat;
......@@ -1011,13 +1012,58 @@ fn trait_ref_to_object_type<'tcx>(this: &AstConv<'tcx>,
projection_bounds,
bounds);
let result = ty::mk_trait(this.tcx(), trait_ref, existential_bounds);
let result = make_object_type(this, span, trait_ref, existential_bounds);
debug!("trait_ref_to_object_type: result={}",
result.repr(this.tcx()));
result
}
fn make_object_type<'tcx>(this: &AstConv<'tcx>,
span: Span,
principal: ty::PolyTraitRef<'tcx>,
bounds: ty::ExistentialBounds<'tcx>)
-> Ty<'tcx> {
let tcx = this.tcx();
let object = ty::TyTrait {
principal: principal,
bounds: bounds
};
let object_trait_ref =
object.principal_trait_ref_with_self_ty(tcx, tcx.types.err);
// ensure the super predicates and stop if we encountered an error
if this.ensure_super_predicates(span, object.principal_def_id()).is_err() {
return tcx.types.err;
}
let mut associated_types: FnvHashSet<(ast::DefId, ast::Name)> =
traits::supertraits(tcx, object_trait_ref)
.flat_map(|tr| {
let trait_def = ty::lookup_trait_def(tcx, tr.def_id());
trait_def.associated_type_names
.clone()
.into_iter()
.map(move |associated_type_name| (tr.def_id(), associated_type_name))
})
.collect();
for projection_bound in &object.bounds.projection_bounds {
let pair = (projection_bound.0.projection_ty.trait_ref.def_id,
projection_bound.0.projection_ty.item_name);
associated_types.remove(&pair);
}
for (trait_def_id, name) in associated_types {
span_err!(tcx.sess, span, E0191,
"the value of the associated type `{}` (from the trait `{}`) must be specified",
name.user_string(tcx),
ty::item_path_str(tcx, trait_def_id));
}
ty::mk_trait(tcx, object.principal, object.bounds)
}
fn report_ambiguous_associated_type(tcx: &ty::ctxt,
span: Span,
type_str: &str,
......@@ -1914,7 +1960,7 @@ fn conv_ty_poly_trait_ref<'tcx>(
projection_bounds,
partitioned_bounds);
ty::mk_trait(this.tcx(), main_trait_bound, bounds)
make_object_type(this, span, main_trait_bound, bounds)
}
pub fn conv_existential_bounds_from_partitioned_bounds<'tcx>(
......
......@@ -125,14 +125,10 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
adjusted_ty.repr(fcx.tcx()),
autoderefs);
let autoderefref = ty::AutoDerefRef { autoderefs: autoderefs, autoref: None };
// If the callee is a bare function or a closure, then we're all set.
match structurally_resolved_type(fcx, callee_expr.span, adjusted_ty).sty {
ty::ty_bare_fn(..) => {
fcx.write_adjustment(callee_expr.id,
callee_expr.span,
ty::AdjustDerefRef(autoderefref));
fcx.write_autoderef_adjustment(callee_expr.id, autoderefs);
return Some(CallStep::Builtin);
}
......@@ -149,14 +145,14 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span,
infer::FnCall,
&closure_ty.sig).0;
fcx.record_deferred_call_resolution(
def_id,
Box::new(CallResolution {call_expr: call_expr,
callee_expr: callee_expr,
adjusted_ty: adjusted_ty,
autoderefref: autoderefref,
fn_sig: fn_sig.clone(),
closure_def_id: def_id}));
fcx.record_deferred_call_resolution(def_id, Box::new(CallResolution {
call_expr: call_expr,
callee_expr: callee_expr,
adjusted_ty: adjusted_ty,
autoderefs: autoderefs,
fn_sig: fn_sig.clone(),
closure_def_id: def_id
}));
return Some(CallStep::DeferredClosure(fn_sig));
}
}
......@@ -176,7 +172,7 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
_ => {}
}
try_overloaded_call_traits(fcx, call_expr, callee_expr, adjusted_ty, autoderefref)
try_overloaded_call_traits(fcx, call_expr, callee_expr, adjusted_ty, autoderefs)
.map(|method_callee| CallStep::Overloaded(method_callee))
}
......@@ -184,7 +180,7 @@ fn try_overloaded_call_traits<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
call_expr: &ast::Expr,
callee_expr: &ast::Expr,
adjusted_ty: Ty<'tcx>,
autoderefref: ty::AutoDerefRef<'tcx>)
autoderefs: usize)
-> Option<ty::MethodCallee<'tcx>>
{
// Try the options that are least restrictive on the caller first.
......@@ -203,7 +199,8 @@ fn try_overloaded_call_traits<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
Some(&*callee_expr),
method_name,
trait_def_id,
autoderefref.clone(),
autoderefs,
false,
adjusted_ty,
None) {
None => continue,
......@@ -335,7 +332,7 @@ struct CallResolution<'tcx> {
call_expr: &'tcx ast::Expr,
callee_expr: &'tcx ast::Expr,
adjusted_ty: Ty<'tcx>,
autoderefref: ty::AutoDerefRef<'tcx>,
autoderefs: usize,
fn_sig: ty::FnSig<'tcx>,
closure_def_id: ast::DefId,
}
......@@ -343,11 +340,11 @@ struct CallResolution<'tcx> {
impl<'tcx> Repr<'tcx> for CallResolution<'tcx> {
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
format!("CallResolution(call_expr={}, callee_expr={}, adjusted_ty={}, \
autoderefref={}, fn_sig={}, closure_def_id={})",
autoderefs={}, fn_sig={}, closure_def_id={})",
self.call_expr.repr(tcx),
self.callee_expr.repr(tcx),
self.adjusted_ty.repr(tcx),
self.autoderefref.repr(tcx),
self.autoderefs,
self.fn_sig.repr(tcx),
self.closure_def_id.repr(tcx))
}
......@@ -364,7 +361,7 @@ fn resolve<'a>(&mut self, fcx: &FnCtxt<'a,'tcx>) {
// We may now know enough to figure out fn vs fnmut etc.
match try_overloaded_call_traits(fcx, self.call_expr, self.callee_expr,
self.adjusted_ty, self.autoderefref.clone()) {
self.adjusted_ty, self.autoderefs) {
Some(method_callee) => {
// One problem is that when we get here, we are going
// to have a newly instantiated function signature
......
......@@ -24,7 +24,6 @@
use syntax::ast;
use syntax::codemap::Span;
use std::rc::Rc;
use std::mem;
use std::iter::repeat;
use util::ppaux::Repr;
......@@ -84,7 +83,7 @@ fn confirm(&mut self,
-> MethodCallee<'tcx>
{
// Adjust the self expression the user provided and obtain the adjusted type.
let self_ty = self.adjust_self_ty(unadjusted_self_ty, &pick.adjustment);
let self_ty = self.adjust_self_ty(unadjusted_self_ty, &pick);
// Make sure nobody calls `drop()` explicitly.
self.enforce_illegal_method_limitations(&pick);
......@@ -134,11 +133,20 @@ fn confirm(&mut self,
fn adjust_self_ty(&mut self,
unadjusted_self_ty: Ty<'tcx>,
adjustment: &probe::PickAdjustment)
pick: &probe::Pick<'tcx>)
-> Ty<'tcx>
{
// Construct the actual adjustment and write it into the table
let auto_deref_ref = self.create_ty_adjustment(adjustment);
let (autoref, unsize) = if let Some(mutbl) = pick.autoref {
let region = self.infcx().next_region_var(infer::Autoref(self.span));
let autoref = ty::AutoPtr(self.tcx().mk_region(region), mutbl);
(Some(autoref), pick.unsize.map(|target| {
ty::adjust_ty_for_autoref(self.tcx(), target, Some(autoref))
}))
} else {
// No unsizing should be performed without autoref.
assert!(pick.unsize.is_none());
(None, None)
};
// Commit the autoderefs by calling `autoderef again, but this
// time writing the results into the various tables.
......@@ -149,47 +157,27 @@ fn adjust_self_ty(&mut self,
UnresolvedTypeAction::Error,
NoPreference,
|_, n| {
if n == auto_deref_ref.autoderefs {
if n == pick.autoderefs {
Some(())
} else {
None
}
});
assert_eq!(n, auto_deref_ref.autoderefs);
assert_eq!(n, pick.autoderefs);
assert_eq!(result, Some(()));
let final_ty =
ty::adjust_ty_for_autoref(self.tcx(), self.span, autoderefd_ty,
auto_deref_ref.autoref.as_ref());
// Write out the final adjustment.
self.fcx.write_adjustment(self.self_expr.id, self.span, ty::AdjustDerefRef(auto_deref_ref));
final_ty
}
self.fcx.write_adjustment(self.self_expr.id,
ty::AdjustDerefRef(ty::AutoDerefRef {
autoderefs: pick.autoderefs,
autoref: autoref,
unsize: unsize
}));
fn create_ty_adjustment(&mut self,
adjustment: &probe::PickAdjustment)
-> ty::AutoDerefRef<'tcx>
{
match *adjustment {
probe::AutoDeref(num) => {
ty::AutoDerefRef {
autoderefs: num,
autoref: None,
}
}
probe::AutoUnsizeLength(autoderefs, len) => {
ty::AutoDerefRef {
autoderefs: autoderefs,
autoref: Some(ty::AutoUnsize(ty::UnsizeLength(len))),
}
}
probe::AutoRef(mutability, ref sub_adjustment) => {
let deref = self.create_ty_adjustment(&**sub_adjustment);
let region = self.infcx().next_region_var(infer::Autoref(self.span));
wrap_autoref(deref, |base| ty::AutoPtr(region, mutability, base))
}
if let Some(target) = unsize {
target
} else {
ty::adjust_ty_for_autoref(self.tcx(), autoderefd_ty, autoref)
}
}
......@@ -499,10 +487,7 @@ fn fixup_derefs_on_method_receiver_if_necessary(&self,
.adjustments
.borrow()
.get(&expr.id) {
Some(&ty::AdjustDerefRef(ty::AutoDerefRef {
autoderefs: autoderef_count,
autoref: _
})) => autoderef_count,
Some(&ty::AdjustDerefRef(ref adj)) => adj.autoderefs,
Some(_) | None => 0,
};
......@@ -529,17 +514,6 @@ fn fixup_derefs_on_method_receiver_if_necessary(&self,
if i != 0 {
match expr.node {
ast::ExprIndex(ref base_expr, ref index_expr) => {
let mut base_adjustment =
match self.fcx.inh.adjustments.borrow().get(&base_expr.id) {
Some(&ty::AdjustDerefRef(ref adr)) => (*adr).clone(),
None => ty::AutoDerefRef { autoderefs: 0, autoref: None },
Some(_) => {
self.tcx().sess.span_bug(
base_expr.span,
"unexpected adjustment type");
}
};
// If this is an overloaded index, the
// adjustment will include an extra layer of
// autoref because the method is an &self/&mut
......@@ -548,21 +522,44 @@ fn fixup_derefs_on_method_receiver_if_necessary(&self,
// expects. This is annoying and horrible. We
// ought to recode this routine so it doesn't
// (ab)use the normal type checking paths.
base_adjustment.autoref = match base_adjustment.autoref {
None => { None }
Some(ty::AutoPtr(_, _, None)) => { None }
Some(ty::AutoPtr(_, _, Some(box r))) => { Some(r) }
let adj = self.fcx.inh.adjustments.borrow().get(&base_expr.id).cloned();
let (autoderefs, unsize) = match adj {
Some(ty::AdjustDerefRef(adr)) => match adr.autoref {
None => {
assert!(adr.unsize.is_none());
(adr.autoderefs, None)
}
Some(ty::AutoPtr(_, _)) => {
(adr.autoderefs, adr.unsize.map(|target| {
ty::deref(target, false)
.expect("fixup: AutoPtr is not &T").ty
}))
}
Some(_) => {
self.tcx().sess.span_bug(
base_expr.span,
&format!("unexpected adjustment autoref {}",
adr.repr(self.tcx())));
}
},
None => (0, None),
Some(_) => {
self.tcx().sess.span_bug(
base_expr.span,
"unexpected adjustment autoref");
"unexpected adjustment type");
}
};
let adjusted_base_ty =
self.fcx.adjust_expr_ty(
&**base_expr,
Some(&ty::AdjustDerefRef(base_adjustment.clone())));
let (adjusted_base_ty, unsize) = if let Some(target) = unsize {
(target, true)
} else {
(self.fcx.adjust_expr_ty(base_expr,
Some(&ty::AdjustDerefRef(ty::AutoDerefRef {
autoderefs: autoderefs,
autoref: None,
unsize: None
}))), false)
};
let index_expr_ty = self.fcx.expr_ty(&**index_expr);
let result = check::try_index_step(
......@@ -571,7 +568,8 @@ fn fixup_derefs_on_method_receiver_if_necessary(&self,
expr,
&**base_expr,
adjusted_base_ty,
base_adjustment,
autoderefs,
unsize,
PreferMutLvalue,
index_expr_ty);
......@@ -658,14 +656,3 @@ fn replace_late_bound_regions_with_fresh_var<T>(&self, value: &ty::Binder<T>) ->
self.span, infer::FnCall, value).0
}
}
fn wrap_autoref<'tcx, F>(mut deref: ty::AutoDerefRef<'tcx>,
base_fn: F)
-> ty::AutoDerefRef<'tcx> where
F: FnOnce(Option<Box<ty::AutoRef<'tcx>>>) -> ty::AutoRef<'tcx>,
{
let autoref = mem::replace(&mut deref.autoref, None);
let autoref = autoref.map(|r| box r);
deref.autoref = Some(base_fn(autoref));
deref
}
......@@ -122,8 +122,7 @@ pub fn lookup_in_trait<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-> Option<MethodCallee<'tcx>>
{
lookup_in_trait_adjusted(fcx, span, self_expr, m_name, trait_def_id,
ty::AutoDerefRef { autoderefs: 0, autoref: None },
self_ty, opt_input_types)
0, false, self_ty, opt_input_types)
}
/// `lookup_in_trait_adjusted` is used for overloaded operators. It does a very narrow slice of
......@@ -140,7 +139,8 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
self_expr: Option<&ast::Expr>,
m_name: ast::Name,
trait_def_id: DefId,
autoderefref: ty::AutoDerefRef<'tcx>,
autoderefs: usize,
unsize: bool,
self_ty: Ty<'tcx>,
opt_input_types: Option<Vec<Ty<'tcx>>>)
-> Option<MethodCallee<'tcx>>
......@@ -241,18 +241,15 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
Some(self_expr) => {
debug!("lookup_in_trait_adjusted: inserting adjustment if needed \
(self-id={}, base adjustment={:?}, explicit_self={:?})",
self_expr.id, autoderefref, method_ty.explicit_self);
(self-id={}, autoderefs={}, unsize={}, explicit_self={:?})",
self_expr.id, autoderefs, unsize,
method_ty.explicit_self);
match method_ty.explicit_self {
ty::ByValueExplicitSelfCategory => {
// Trait method is fn(self), no transformation needed.
if !autoderefref.is_identity() {
fcx.write_adjustment(
self_expr.id,
span,
ty::AdjustDerefRef(autoderefref));
}
assert!(!unsize);
fcx.write_autoderef_adjustment(self_expr.id, autoderefs);
}
ty::ByReferenceExplicitSelfCategory(..) => {
......@@ -260,14 +257,15 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
// autoref. Pull the region etc out of the type of first argument.
match transformed_self_ty.sty {
ty::ty_rptr(region, ty::mt { mutbl, ty: _ }) => {
let ty::AutoDerefRef { autoderefs, autoref } = autoderefref;
let autoref = autoref.map(|r| box r);
fcx.write_adjustment(
self_expr.id,
span,
fcx.write_adjustment(self_expr.id,
ty::AdjustDerefRef(ty::AutoDerefRef {
autoderefs: autoderefs,
autoref: Some(ty::AutoPtr(*region, mutbl, autoref))
autoref: Some(ty::AutoPtr(region, mutbl)),
unsize: if unsize {
Some(transformed_self_ty)
} else {
None
}
}));
}
......
......@@ -31,7 +31,6 @@
use util::ppaux::Repr;
use self::CandidateKind::*;
pub use self::PickAdjustment::*;
pub use self::PickKind::*;
struct ProbeContext<'a, 'tcx:'a> {
......@@ -49,7 +48,8 @@ struct ProbeContext<'a, 'tcx:'a> {
struct CandidateStep<'tcx> {
self_ty: Ty<'tcx>,
adjustment: PickAdjustment,
autoderefs: usize,
unsize: bool
}
struct Candidate<'tcx> {
......@@ -70,8 +70,24 @@ enum CandidateKind<'tcx> {
pub struct Pick<'tcx> {
pub method_ty: Rc<ty::Method<'tcx>>,
pub adjustment: PickAdjustment,
pub kind: PickKind<'tcx>,
// Indicates that the source expression should be autoderef'd N times
//
// A = expr | *expr | **expr | ...
pub autoderefs: usize,
// Indicates that an autoref is applied after the optional autoderefs
//
// B = A | &A | &mut A
pub autoref: Option<ast::Mutability>,
// Indicates that the source expression should be "unsized" to a
// target type. This should probably eventually go away in favor
// of just coercing method receivers.
//
// C = B | unsize(B)
pub unsize: Option<Ty<'tcx>>,
}
#[derive(Clone,Debug)]
......@@ -85,30 +101,6 @@ pub enum PickKind<'tcx> {
pub type PickResult<'tcx> = Result<Pick<'tcx>, MethodError>;
// This is a kind of "abstracted" version of ty::AutoAdjustment. The
// difference is that it doesn't embed any regions or other
// specifics. The "confirmation" step recreates those details as
// needed.
#[derive(Clone,Debug)]
pub enum PickAdjustment {
// Indicates that the source expression should be autoderef'd N times
//
// A = expr | *expr | **expr
AutoDeref(usize),
// Indicates that the source expression should be autoderef'd N
// times and then "unsized". This should probably eventually go
// away in favor of just coercing method receivers.
//
// A = unsize(expr | *expr | **expr)
AutoUnsizeLength(/* number of autoderefs */ usize, /* length*/ usize),
// Indicates that an autoref is applied after some number of other adjustments
//
// A = &A | &mut A
AutoRef(ast::Mutability, Box<PickAdjustment>),
}
#[derive(PartialEq, Eq, Copy, Clone)]
pub enum Mode {
// An expression of the form `receiver.method_name(...)`.
......@@ -149,7 +141,8 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
} else {
vec![CandidateStep {
self_ty: self_ty,
adjustment: AutoDeref(0)
autoderefs: 0,
unsize: false
}]
};
......@@ -200,16 +193,21 @@ fn create_steps<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
UnresolvedTypeAction::Error,
NoPreference,
|t, d| {
let adjustment = AutoDeref(d);
steps.push(CandidateStep { self_ty: t, adjustment: adjustment });
steps.push(CandidateStep {
self_ty: t,
autoderefs: d,
unsize: false
});
None::<()> // keep iterating until we can't anymore
});
match final_ty.sty {
ty::ty_vec(elem_ty, Some(len)) => {
ty::ty_vec(elem_ty, Some(_)) => {
let slice_ty = ty::mk_vec(fcx.tcx(), elem_ty, None);
steps.push(CandidateStep {
self_ty: ty::mk_vec(fcx.tcx(), elem_ty, None),
adjustment: AutoUnsizeLength(dereferences, len),
self_ty: slice_ty,
autoderefs: dereferences,
unsize: true
});
}
ty::ty_err => return None,
......@@ -926,20 +924,21 @@ fn pick_by_value_method(&mut self,
* consuming them for their entire lifetime.
*/
let adjustment = match step.adjustment {
AutoDeref(d) => consider_reborrow(step.self_ty, d),
AutoUnsizeLength(..) | AutoRef(..) => step.adjustment.clone(),
};
if step.unsize {
return None;
}
return self.pick_method(step.self_ty).map(|r| self.adjust(r, adjustment.clone()));
self.pick_method(step.self_ty).map(|r| r.map(|mut pick| {
pick.autoderefs = step.autoderefs;
fn consider_reborrow<'tcx>(ty: Ty<'tcx>, d: usize) -> PickAdjustment {
// Insert a `&*` or `&mut *` if this is a reference type:
match ty.sty {
ty::ty_rptr(_, ref mt) => AutoRef(mt.mutbl, box AutoDeref(d+1)),
_ => AutoDeref(d),
if let ty::ty_rptr(_, mt) = step.self_ty.sty {
pick.autoderefs += 1;
pick.autoref = Some(mt.mutbl);
}
}
pick
}))
}
fn pick_autorefd_method(&mut self,
......@@ -947,46 +946,28 @@ fn pick_autorefd_method(&mut self,
-> Option<PickResult<'tcx>>
{
let tcx = self.tcx();
self.search_mutabilities(
|m| AutoRef(m, box step.adjustment.clone()),
|m,r| ty::mk_rptr(tcx, tcx.mk_region(r), ty::mt {ty:step.self_ty, mutbl:m}))
}
fn search_mutabilities<F, G>(&mut self,
mut mk_adjustment: F,
mut mk_autoref_ty: G)
-> Option<PickResult<'tcx>> where
F: FnMut(ast::Mutability) -> PickAdjustment,
G: FnMut(ast::Mutability, ty::Region) -> Ty<'tcx>,
{
// In general, during probing we erase regions. See
// `impl_self_ty()` for an explanation.
let region = ty::ReStatic;
let region = tcx.mk_region(ty::ReStatic);
// Search through mutabilities in order to find one where pick works:
[ast::MutImmutable, ast::MutMutable]
.iter()
.flat_map(|&m| {
let autoref_ty = mk_autoref_ty(m, region);
self.pick_method(autoref_ty)
.map(|r| self.adjust(r, mk_adjustment(m)))
.into_iter()
})
.nth(0)
}
fn adjust(&mut self,
result: PickResult<'tcx>,
adjustment: PickAdjustment)
-> PickResult<'tcx>
{
match result {
Err(e) => Err(e),
Ok(mut pick) => {
pick.adjustment = adjustment;
Ok(pick)
}
}
[ast::MutImmutable, ast::MutMutable].iter().filter_map(|&m| {
let autoref_ty = ty::mk_rptr(tcx, region, ty::mt {
ty: step.self_ty,
mutbl: m
});
self.pick_method(autoref_ty).map(|r| r.map(|mut pick| {
pick.autoderefs = step.autoderefs;
pick.autoref = Some(m);
pick.unsize = if step.unsize {
Some(step.self_ty)
} else {
None
};
pick
}))
}).nth(0)
}
fn pick_method(&mut self, self_ty: Ty<'tcx>) -> Option<PickResult<'tcx>> {
......@@ -1122,8 +1103,10 @@ fn collapse_candidates_to_trait_pick(&self,
let method_ty = probes[0].method_ty.clone();
Some(Pick {
method_ty: method_ty,
adjustment: AutoDeref(0),
kind: TraitPick(trait_def_id, method_num)
kind: TraitPick(trait_def_id, method_num),
autoderefs: 0,
autoref: None,
unsize: None
})
}
......@@ -1296,7 +1279,6 @@ impl<'tcx> Candidate<'tcx> {
fn to_unadjusted_pick(&self) -> Pick<'tcx> {
Pick {
method_ty: self.method_ty.clone(),
adjustment: AutoDeref(0),
kind: match self.kind {
InherentImplCandidate(def_id, _) => {
InherentImplPick(def_id)
......@@ -1323,7 +1305,10 @@ fn to_unadjusted_pick(&self) -> Pick<'tcx> {
ProjectionCandidate(def_id, index) => {
TraitPick(def_id, index)
}
}
},
autoderefs: 0,
autoref: None,
unsize: None
}
}
......@@ -1392,15 +1377,10 @@ fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
impl<'tcx> Repr<'tcx> for CandidateStep<'tcx> {
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
format!("CandidateStep({},{:?})",
format!("CandidateStep({}, autoderefs={}, unsize={})",
self.self_ty.repr(tcx),
self.adjustment)
}
}
impl<'tcx> Repr<'tcx> for PickAdjustment {
fn repr(&self, _tcx: &ty::ctxt) -> String {
format!("{:?}", self)
self.autoderefs,
self.unsize)
}
}
......@@ -1412,9 +1392,12 @@ fn repr(&self, _tcx: &ty::ctxt) -> String {
impl<'tcx> Repr<'tcx> for Pick<'tcx> {
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
format!("Pick(method_ty={}, adjustment={:?}, kind={:?})",
format!("Pick(method_ty={}, autoderefs={},
autoref={}, unsize={}, kind={:?})",
self.method_ty.repr(tcx),
self.adjustment,
self.autoderefs,
self.autoref.repr(tcx),
self.unsize.repr(tcx),
self.kind)
}
}
......@@ -1292,21 +1292,19 @@ pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts<'tcx>) {
pub fn write_autoderef_adjustment(&self,
node_id: ast::NodeId,
span: Span,
derefs: usize) {
if derefs == 0 { return; }
self.write_adjustment(
node_id,
span,
ty::AdjustDerefRef(ty::AutoDerefRef {
autoderefs: derefs,
autoref: None })
autoref: None,
unsize: None
})
);
}
pub fn write_adjustment(&self,
node_id: ast::NodeId,
span: Span,
adj: ty::AutoAdjustment<'tcx>) {
debug!("write_adjustment(node_id={}, adj={})", node_id, adj.repr(self.tcx()));
......@@ -1314,13 +1312,6 @@ pub fn write_adjustment(&self,
return;
}
// Careful: adjustments can imply trait obligations if we are
// casting from a concrete type to an object type. I think
// it'd probably be nicer to move the logic that creates the
// obligation into the code that creates the adjustment, but
// that's a bit awkward, so instead we go digging and pull the
// obligation out here.
self.register_adjustment_obligations(span, &adj);
self.inh.adjustments.borrow_mut().insert(node_id, adj);
}
......@@ -1383,74 +1374,6 @@ fn normalize_associated_type(&self,
cause)
}
fn register_adjustment_obligations(&self,
span: Span,
adj: &ty::AutoAdjustment<'tcx>) {
match *adj {
ty::AdjustReifyFnPointer(..) => { }
ty::AdjustUnsafeFnPointer => { }
ty::AdjustDerefRef(ref d_r) => {
match d_r.autoref {
Some(ref a_r) => {
self.register_autoref_obligations(span, a_r);
}
None => {}
}
}
}
}
fn register_autoref_obligations(&self,
span: Span,
autoref: &ty::AutoRef<'tcx>) {
match *autoref {
ty::AutoUnsize(ref unsize) => {
self.register_unsize_obligations(span, unsize);
}
ty::AutoPtr(_, _, None) |
ty::AutoUnsafe(_, None) => {
}
ty::AutoPtr(_, _, Some(ref a_r)) |
ty::AutoUnsafe(_, Some(ref a_r)) => {
self.register_autoref_obligations(span, &**a_r)
}
ty::AutoUnsizeUniq(ref unsize) => {
self.register_unsize_obligations(span, unsize);
}
}
}
fn register_unsize_obligations(&self,
span: Span,
unsize: &ty::UnsizeKind<'tcx>) {
debug!("register_unsize_obligations: unsize={:?}", unsize);
match *unsize {
ty::UnsizeLength(..) => {}
ty::UnsizeStruct(ref u, _) => {
self.register_unsize_obligations(span, &**u)
}
ty::UnsizeVtable(ref ty_trait, self_ty) => {
vtable::check_object_safety(self.tcx(), ty_trait, span);
// If the type is `Foo+'a`, ensures that the type
// being cast to `Foo+'a` implements `Foo`:
vtable::register_object_cast_obligations(self,
span,
ty_trait,
self_ty);
// If the type is `Foo+'a`, ensures that the type
// being cast to `Foo+'a` outlives `'a`:
let cause = traits::ObligationCause { span: span,
body_id: self.body_id,
code: traits::ObjectCastObligation(self_ty) };
self.register_region_obligation(self_ty, ty_trait.bounds.region_bound, cause);
}
ty::UnsizeUpcast(_) => { }
}
}
/// Returns the type of `def_id` with all generics replaced by by fresh type/region variables.
/// Also returns the substitution from the type parameters on `def_id` to the fresh variables.
/// Registers any trait obligations specified on `def_id` at the same time.
......@@ -1881,7 +1804,8 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>,
let mt = match ty::deref(resolved_t, false) {
Some(mt) => Some(mt),
None => {
let method_call = opt_expr.map(|expr| MethodCall::autoderef(expr.id, autoderefs));
let method_call =
opt_expr.map(|expr| MethodCall::autoderef(expr.id, autoderefs as u32));
// Super subtle: it might seem as though we should
// pass `opt_expr` to `try_overloaded_deref`, so that
......@@ -1972,13 +1896,13 @@ fn make_overloaded_lvalue_return_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
}
}
fn autoderef_for_index<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>,
base_expr: &ast::Expr,
base_ty: Ty<'tcx>,
lvalue_pref: LvaluePreference,
mut step: F)
-> Option<T> where
F: FnMut(Ty<'tcx>, ty::AutoDerefRef<'tcx>) -> Option<T>,
fn lookup_indexing<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
expr: &ast::Expr,
base_expr: &'tcx ast::Expr,
base_ty: Ty<'tcx>,
idx_ty: Ty<'tcx>,
lvalue_pref: LvaluePreference)
-> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)>
{
// FIXME(#18741) -- this is almost but not quite the same as the
// autoderef that normal method probing does. They could likely be
......@@ -1991,9 +1915,9 @@ fn autoderef_for_index<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>,
UnresolvedTypeAction::Error,
lvalue_pref,
|adj_ty, idx| {
let autoderefref = ty::AutoDerefRef { autoderefs: idx, autoref: None };
step(adj_ty, autoderefref)
});
try_index_step(fcx, MethodCall::expr(expr.id), expr, base_expr,
adj_ty, idx, false, lvalue_pref, idx_ty)
});
if final_mt.is_some() {
return final_mt;
......@@ -2001,41 +1925,38 @@ fn autoderef_for_index<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>,
// After we have fully autoderef'd, if the resulting type is [T, ..n], then
// do a final unsized coercion to yield [T].
match ty.sty {
ty::ty_vec(element_ty, Some(n)) => {
let adjusted_ty = ty::mk_vec(fcx.tcx(), element_ty, None);
let autoderefref = ty::AutoDerefRef {
autoderefs: autoderefs,
autoref: Some(ty::AutoUnsize(ty::UnsizeLength(n)))
};
step(adjusted_ty, autoderefref)
}
_ => {
None
}
if let ty::ty_vec(element_ty, Some(_)) = ty.sty {
let adjusted_ty = ty::mk_vec(fcx.tcx(), element_ty, None);
try_index_step(fcx, MethodCall::expr(expr.id), expr, base_expr,
adjusted_ty, autoderefs, true, lvalue_pref, idx_ty)
} else {
None
}
}
/// To type-check `base_expr[index_expr]`, we progressively autoderef (and otherwise adjust)
/// `base_expr`, looking for a type which either supports builtin indexing or overloaded indexing.
/// This loop implements one step in that search; the autoderef loop is implemented by
/// `autoderef_for_index`.
/// `lookup_indexing`.
fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
method_call: MethodCall,
expr: &ast::Expr,
base_expr: &'tcx ast::Expr,
adjusted_ty: Ty<'tcx>,
adjustment: ty::AutoDerefRef<'tcx>,
autoderefs: usize,
unsize: bool,
lvalue_pref: LvaluePreference,
index_ty: Ty<'tcx>)
-> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)>
{
let tcx = fcx.tcx();
debug!("try_index_step(expr={}, base_expr.id={}, adjusted_ty={}, adjustment={:?}, index_ty={})",
debug!("try_index_step(expr={}, base_expr.id={}, adjusted_ty={}, \
autoderefs={}, unsize={}, index_ty={})",
expr.repr(tcx),
base_expr.repr(tcx),
adjusted_ty.repr(tcx),
adjustment,
autoderefs,
unsize,
index_ty.repr(tcx));
let input_ty = fcx.infcx().next_ty_var();
......@@ -2044,7 +1965,9 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
match (ty::index(adjusted_ty), &index_ty.sty) {
(Some(ty), &ty::ty_uint(ast::TyUs)) | (Some(ty), &ty::ty_infer(ty::IntVar(_))) => {
debug!("try_index_step: success, using built-in indexing");
fcx.write_adjustment(base_expr.id, base_expr.span, ty::AdjustDerefRef(adjustment));
// If we had `[T; N]`, we should've caught it before unsizing to `[T]`.
assert!(!unsize);
fcx.write_autoderef_adjustment(base_expr.id, autoderefs);
return Some((tcx.types.usize, ty));
}
_ => {}
......@@ -2058,7 +1981,8 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
Some(&*base_expr),
token::intern("index_mut"),
trait_did,
adjustment.clone(),
autoderefs,
unsize,
adjusted_ty,
Some(vec![input_ty]))
}
......@@ -2073,7 +1997,8 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
Some(&*base_expr),
token::intern("index"),
trait_did,
adjustment.clone(),
autoderefs,
unsize,
adjusted_ty,
Some(vec![input_ty]))
}
......@@ -2662,7 +2587,7 @@ fn check_field<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
match field_ty {
Some(field_ty) => {
fcx.write_ty(expr.id, field_ty);
fcx.write_autoderef_adjustment(base.id, base.span, autoderefs);
fcx.write_autoderef_adjustment(base.id, autoderefs);
return;
}
None => {}
......@@ -2773,7 +2698,7 @@ fn check_tup_field<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
match field_ty {
Some(field_ty) => {
fcx.write_ty(expr.id, field_ty);
fcx.write_autoderef_adjustment(base.id, base.span, autoderefs);
fcx.write_autoderef_adjustment(base.id, autoderefs);
return;
}
None => {}
......@@ -3600,26 +3525,13 @@ fn check_struct_fields_on_error<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
fcx.write_ty(id, idx_t);
} else {
let base_t = structurally_resolved_type(fcx, expr.span, base_t);
let result =
autoderef_for_index(fcx, &**base, base_t, lvalue_pref, |adj_ty, adj| {
try_index_step(fcx,
MethodCall::expr(expr.id),
expr,
&**base,
adj_ty,
adj,
lvalue_pref,
idx_t)
});
match result {
match lookup_indexing(fcx, expr, base, base_t, idx_t, lvalue_pref) {
Some((index_ty, element_ty)) => {
let idx_expr_ty = fcx.expr_ty(idx);
demand::eqtype(fcx, expr.span, index_ty, idx_expr_ty);
fcx.write_ty(id, element_ty);
}
_ => {
None => {
check_expr_has_type(fcx, &**idx, fcx.tcx().types.err);
fcx.type_error_message(
expr.span,
......
......@@ -499,10 +499,10 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
if let Some(adjustment) = rcx.fcx.inh.adjustments.borrow().get(&expr.id) {
debug!("adjustment={:?}", adjustment);
match *adjustment {
ty::AdjustDerefRef(ty::AutoDerefRef {autoderefs, autoref: ref opt_autoref}) => {
ty::AdjustDerefRef(ty::AutoDerefRef {autoderefs, ref autoref, ..}) => {
let expr_ty = rcx.resolve_node_type(expr.id);
constrain_autoderefs(rcx, expr, autoderefs, expr_ty);
if let Some(ref autoref) = *opt_autoref {
if let Some(ref autoref) = *autoref {
link_autoref(rcx, expr, autoderefs, autoref);
// Require that the resulting region encompasses
......@@ -872,7 +872,7 @@ fn constrain_autoderefs<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
let r_deref_expr = ty::ReScope(CodeExtent::from_node_id(deref_expr.id));
for i in 0..derefs {
let method_call = MethodCall::autoderef(deref_expr.id, i);
let method_call = MethodCall::autoderef(deref_expr.id, i as u32);
debug!("constrain_autoderefs: method_call={:?} (of {:?} total)", method_call, derefs);
derefd_ty = match rcx.fcx.inh.method_map.borrow().get(&method_call) {
......@@ -904,7 +904,7 @@ fn constrain_autoderefs<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
let self_cmt = ignore_err!(mc.cat_expr_autoderefd(deref_expr, i));
debug!("constrain_autoderefs: self_cmt={:?}",
self_cmt.repr(rcx.tcx()));
link_region(rcx, deref_expr.span, *r,
link_region(rcx, deref_expr.span, r,
ty::BorrowKind::from_mutbl(m), self_cmt);
}
......@@ -1102,7 +1102,7 @@ fn link_pattern<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
ast::PatVec(_, Some(ref slice_pat), _) => {
match mc.cat_slice_pattern(sub_cmt, &**slice_pat) {
Ok((slice_cmt, slice_mutbl, slice_r)) => {
link_region(rcx, sub_pat.span, slice_r,
link_region(rcx, sub_pat.span, &slice_r,
ty::BorrowKind::from_mutbl(slice_mutbl),
slice_cmt);
}
......@@ -1127,16 +1127,15 @@ fn link_autoref(rcx: &Rcx,
debug!("expr_cmt={}", expr_cmt.repr(rcx.tcx()));
match *autoref {
ty::AutoPtr(r, m, _) => {
link_region(rcx, expr.span, r, ty::BorrowKind::from_mutbl(m), expr_cmt);
ty::AutoPtr(r, m) => {
link_region(rcx, expr.span, r,
ty::BorrowKind::from_mutbl(m), expr_cmt);
}
ty::AutoUnsafe(m, _) => {
ty::AutoUnsafe(m) => {
let r = ty::ReScope(CodeExtent::from_node_id(expr.id));
link_region(rcx, expr.span, r, ty::BorrowKind::from_mutbl(m), expr_cmt);
}
ty::AutoUnsizeUniq(_) | ty::AutoUnsize(_) => {}
}
}
......@@ -1151,7 +1150,7 @@ fn link_by_ref(rcx: &Rcx,
let mc = mc::MemCategorizationContext::new(rcx.fcx);
let expr_cmt = ignore_err!(mc.cat_expr(expr));
let borrow_region = ty::ReScope(callee_scope);
link_region(rcx, expr.span, borrow_region, ty::ImmBorrow, expr_cmt);
link_region(rcx, expr.span, &borrow_region, ty::ImmBorrow, expr_cmt);
}
/// Like `link_region()`, except that the region is extracted from the type of `id`, which must be
......@@ -1169,7 +1168,7 @@ fn link_region_from_node_type<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
let tcx = rcx.fcx.ccx.tcx;
debug!("rptr_ty={}", ty_to_string(tcx, rptr_ty));
let r = ty::ty_region(tcx, span, rptr_ty);
link_region(rcx, span, r, ty::BorrowKind::from_mutbl(mutbl),
link_region(rcx, span, &r, ty::BorrowKind::from_mutbl(mutbl),
cmt_borrowed);
}
}
......@@ -1179,7 +1178,7 @@ fn link_region_from_node_type<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
/// between regions, as explained in `link_reborrowed_region()`.
fn link_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
span: Span,
borrow_region: ty::Region,
borrow_region: &ty::Region,
borrow_kind: ty::BorrowKind,
borrow_cmt: mc::cmt<'tcx>) {
let mut borrow_cmt = borrow_cmt;
......@@ -1273,7 +1272,7 @@ fn link_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
/// recurse and process `ref_cmt` (see case 2 above).
fn link_reborrowed_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
span: Span,
borrow_region: ty::Region,
borrow_region: &ty::Region,
borrow_kind: ty::BorrowKind,
ref_cmt: mc::cmt<'tcx>,
ref_region: ty::Region,
......@@ -1318,7 +1317,7 @@ fn link_reborrowed_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
debug!("link_reborrowed_region: {} <= {}",
borrow_region.repr(rcx.tcx()),
ref_region.repr(rcx.tcx()));
rcx.fcx.mk_subr(cause, borrow_region, ref_region);
rcx.fcx.mk_subr(cause, *borrow_region, ref_region);
// If we end up needing to recurse and establish a region link
// with `ref_cmt`, calculate what borrow kind we will end up
......
......@@ -15,7 +15,6 @@
use middle::ty::{self, Ty, AsPredicate};
use syntax::ast;
use syntax::codemap::Span;
use util::nodemap::FnvHashSet;
use util::ppaux::{Repr, UserString};
......@@ -133,46 +132,9 @@ pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
fcx.register_predicate(projection_obligation);
}
// Finally, check that there IS a projection predicate for every associated type.
check_object_type_binds_all_associated_types(fcx.tcx(),
span,
object_trait);
object_trait_ref
}
fn check_object_type_binds_all_associated_types<'tcx>(tcx: &ty::ctxt<'tcx>,
span: Span,
object_trait: &ty::TyTrait<'tcx>)
{
let object_trait_ref =
object_trait.principal_trait_ref_with_self_ty(tcx, tcx.types.err);
let mut associated_types: FnvHashSet<(ast::DefId, ast::Name)> =
traits::supertraits(tcx, object_trait_ref.clone())
.flat_map(|tr| {
let trait_def = ty::lookup_trait_def(tcx, tr.def_id());
trait_def.associated_type_names
.clone()
.into_iter()
.map(move |associated_type_name| (tr.def_id(), associated_type_name))
})
.collect();
for projection_bound in &object_trait.bounds.projection_bounds {
let pair = (projection_bound.0.projection_ty.trait_ref.def_id,
projection_bound.0.projection_ty.item_name);
associated_types.remove(&pair);
}
for (trait_def_id, name) in associated_types {
span_err!(tcx.sess, span, E0191,
"the value of the associated type `{}` (from the trait `{}`) must be specified",
name.user_string(tcx),
ty::item_path_str(tcx, trait_def_id));
}
}
pub fn select_all_fcx_obligations_and_apply_defaults(fcx: &FnCtxt) {
debug!("select_all_fcx_obligations_and_apply_defaults");
......
......@@ -285,11 +285,8 @@ fn visit_adjustments(&self, reason: ResolveReason, id: ast::NodeId) {
}
Some(adjustment) => {
let adj_object = ty::adjust_is_object(&adjustment);
let resolved_adjustment = match adjustment {
ty::AdjustReifyFnPointer(def_id) => {
ty::AdjustReifyFnPointer(def_id)
}
ty::AdjustReifyFnPointer => ty::AdjustReifyFnPointer,
ty::AdjustUnsafeFnPointer => {
ty::AdjustUnsafeFnPointer
......@@ -297,18 +294,14 @@ fn visit_adjustments(&self, reason: ResolveReason, id: ast::NodeId) {
ty::AdjustDerefRef(adj) => {
for autoderef in 0..adj.autoderefs {
let method_call = MethodCall::autoderef(id, autoderef);
self.visit_method_map_entry(reason, method_call);
}
if adj_object {
let method_call = MethodCall::autoobject(id);
let method_call = MethodCall::autoderef(id, autoderef as u32);
self.visit_method_map_entry(reason, method_call);
}
ty::AdjustDerefRef(ty::AutoDerefRef {
autoderefs: adj.autoderefs,
autoref: self.resolve(&adj.autoref, reason),
unsize: self.resolve(&adj.unsize, reason),
})
}
};
......
......@@ -34,6 +34,8 @@ fn dent<C:BoxCar>(c: C, color: C::Color) {
fn dent_object<COLOR>(c: BoxCar<Color=COLOR>) {
//~^ ERROR ambiguous associated type
//~| ERROR the associated type `Color` (from the trait `Box`) must be specified
//~| ERROR the associated type `Color` (from the trait `Vehicle`) must be specified
}
fn paint<C:BoxCar>(c: C, d: C::Color) {
......
......@@ -20,7 +20,7 @@ impl Foo for X {
type Item = bool;
}
fn print_x(_: &Foo, extra: &str) {
fn print_x(_: &Foo<Item=bool>, extra: &str) {
println!("{}", extra);
}
......
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
......@@ -9,7 +9,7 @@
// except according to those terms.
// Test that a partially specified trait object with unspecified associated
// type does not ICE.
// type does not type-check.
// pretty-expanded FIXME #23616
......@@ -20,7 +20,6 @@ fn dummy(&self) { }
}
fn bar(x: &Foo) {}
// FIXME(#19482) -- `Foo` should specify `A`, but this is not
// currently enforced except at object creation
//~^ ERROR the associated type `A` (from the trait `Foo`) must be specified
pub fn main() {}
......@@ -11,7 +11,8 @@
#![feature(rustc_attrs)]
#![allow(warnings)]
pub fn fail(x: Option<& (Iterator+Send)>) -> Option<&Iterator> {
pub fn fail(x: Option<&(Iterator<Item=()>+Send)>)
-> Option<&Iterator<Item=()>> {
// This call used to trigger an LLVM assertion because the return
// slot had type "Option<&Iterator>"* instead of
// "Option<&(Iterator+Send)>"* -- but this now yields a
......@@ -23,7 +24,8 @@ pub fn fail(x: Option<& (Iterator+Send)>) -> Option<&Iterator> {
inner(x) //~ ERROR mismatched types
}
pub fn inner(x: Option<& (Iterator+Send)>) -> Option<&(Iterator+Send)> {
pub fn inner(x: Option<&(Iterator<Item=()>+Send)>)
-> Option<&(Iterator<Item=()>+Send)> {
x
}
......
......@@ -11,7 +11,7 @@
// Test that the `Fn` traits require `()` form without a feature gate.
fn bar1(x: &Fn<()>) {
fn bar1(x: &Fn<(), Output=()>) {
//~^ ERROR angle-bracket notation is not stable when used with the `Fn` family
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册