Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement RFC495 semantics for slice patterns #32202

Merged
merged 15 commits into from
Jun 9, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions mk/crates.mk
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ DEPS_rustc := syntax fmt_macros flate arena serialize getopts rbml \
log graphviz rustc_llvm rustc_back rustc_data_structures\
rustc_const_math
DEPS_rustc_back := std syntax flate log libc
DEPS_rustc_borrowck := rustc rustc_mir log graphviz syntax
DEPS_rustc_borrowck := rustc log graphviz syntax rustc_mir
DEPS_rustc_data_structures := std log serialize
DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_borrowck \
rustc_typeck rustc_mir rustc_resolve log syntax serialize rustc_llvm \
Expand All @@ -123,9 +123,9 @@ DEPS_rustc_passes := syntax rustc core rustc_const_eval
DEPS_rustc_mir := rustc syntax rustc_const_math rustc_const_eval rustc_bitflags
DEPS_rustc_resolve := arena rustc log syntax
DEPS_rustc_platform_intrinsics := std
DEPS_rustc_plugin := rustc rustc_metadata syntax rustc_mir
DEPS_rustc_plugin := rustc rustc_metadata syntax
DEPS_rustc_privacy := rustc log syntax
DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back rustc_mir \
DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back \
log syntax serialize rustc_llvm rustc_platform_intrinsics \
rustc_const_math rustc_const_eval rustc_incremental
DEPS_rustc_incremental := rbml rustc serialize rustc_data_structures
Expand Down
6 changes: 3 additions & 3 deletions src/doc/book/slice-patterns.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ fn main() {
let v = vec!["match_this", "1"];

match &v[..] {
["match_this", second] => println!("The second element is {}", second),
&["match_this", second] => println!("The second element is {}", second),
_ => {},
}
}
Expand All @@ -26,8 +26,8 @@ slice will be bound to that name. For example:

fn is_symmetric(list: &[u32]) -> bool {
match list {
[] | [_] => true,
[x, inside.., y] if x == y => is_symmetric(inside),
&[] | &[_] => true,
&[x, ref inside.., y] if x == y => is_symmetric(inside),
_ => false
}
}
Expand Down
1 change: 1 addition & 0 deletions src/librustc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ pub mod mir {
pub mod tcx;
pub mod visit;
pub mod transform;
pub mod traversal;
pub mod mir_map;
}

Expand Down
34 changes: 0 additions & 34 deletions src/librustc/middle/expr_use_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -993,40 +993,6 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
}
}
}
PatKind::Vec(_, Some(ref slice_pat), _) => {
// The `slice_pat` here creates a slice into
// the original vector. This is effectively a
// borrow of the elements of the vector being
// matched.

let (slice_cmt, slice_mutbl, slice_r) =
return_if_err!(mc.cat_slice_pattern(cmt_pat, &slice_pat));

// Note: We declare here that the borrow
// occurs upon entering the `[...]`
// pattern. This implies that something like
// `[a; b]` where `a` is a move is illegal,
// because the borrow is already in effect.
// In fact such a move would be safe-ish, but
// it effectively *requires* that we use the
// nulling out semantics to indicate when a
// value has been moved, which we are trying
// to move away from. Otherwise, how can we
// indicate that the first element in the
// vector has been moved? Eventually, we
// could perhaps modify this rule to permit
// `[..a, b]` where `b` is a move, because in
// that case we can adjust the length of the
// original vec accordingly, but we'd have to
// make trans do the right thing, and it would
// only work for `Box<[T]>`s. It seems simpler
// to just require that people call
// `vec.pop()` or `vec.unshift()`.
let slice_bk = ty::BorrowKind::from_mutbl(slice_mutbl);
delegate.borrow(pat.id, pat.span,
slice_cmt, slice_r,
slice_bk, RefBinding);
}
_ => {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

happy to see this logic go

}
}));
Expand Down
127 changes: 11 additions & 116 deletions src/librustc/middle/mem_categorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,10 +228,10 @@ fn deref_kind(t: Ty, context: DerefKindContext) -> McResult<deref_kind> {
Ok(deref_interior(InteriorField(PositionalField(0))))
}

ty::TyArray(_, _) | ty::TySlice(_) | ty::TyStr => {
ty::TyArray(_, _) | ty::TySlice(_) => {
// no deref of indexed content without supplying InteriorOffsetKind
if let Some(context) = context {
Ok(deref_interior(InteriorElement(context, element_kind(t))))
Ok(deref_interior(InteriorElement(context, ElementKind::VecElement)))
} else {
Err(())
}
Expand Down Expand Up @@ -981,121 +981,31 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
let method_call = ty::MethodCall::expr(elt.id());
let method_ty = self.infcx.node_method_ty(method_call);

let element_ty = match method_ty {
let (element_ty, element_kind) = match method_ty {
Some(method_ty) => {
let ref_ty = self.overloaded_method_return_ty(method_ty);
base_cmt = self.cat_rvalue_node(elt.id(), elt.span(), ref_ty);

// FIXME(#20649) -- why are we using the `self_ty` as the element type...?
let self_ty = method_ty.fn_sig().input(0);
self.tcx().no_late_bound_regions(&self_ty).unwrap()
(self.tcx().no_late_bound_regions(&self_ty).unwrap(),
ElementKind::OtherElement)
}
None => {
match base_cmt.ty.builtin_index() {
Some(ty) => ty,
Some(ty) => (ty, ElementKind::VecElement),
None => {
return Err(());
}
}
}
};

let m = base_cmt.mutbl.inherit();
let ret = interior(elt, base_cmt.clone(), base_cmt.ty,
m, context, element_ty);
let interior_elem = InteriorElement(context, element_kind);
let ret =
self.cat_imm_interior(elt, base_cmt.clone(), element_ty, interior_elem);
debug!("cat_index ret {:?}", ret);
return Ok(ret);

fn interior<'tcx, N: ast_node>(elt: &N,
of_cmt: cmt<'tcx>,
vec_ty: Ty<'tcx>,
mutbl: MutabilityCategory,
context: InteriorOffsetKind,
element_ty: Ty<'tcx>) -> cmt<'tcx>
{
let interior_elem = InteriorElement(context, element_kind(vec_ty));
Rc::new(cmt_ {
id:elt.id(),
span:elt.span(),
cat:Categorization::Interior(of_cmt, interior_elem),
mutbl:mutbl,
ty:element_ty,
note: NoteNone
})
}
}

// Takes either a vec or a reference to a vec and returns the cmt for the
// underlying vec.
fn deref_vec<N:ast_node>(&self,
elt: &N,
base_cmt: cmt<'tcx>,
context: InteriorOffsetKind)
-> McResult<cmt<'tcx>>
{
let ret = match deref_kind(base_cmt.ty, Some(context))? {
deref_ptr(ptr) => {
// for unique ptrs, we inherit mutability from the
// owning reference.
let m = MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr);

// the deref is explicit in the resulting cmt
Rc::new(cmt_ {
id:elt.id(),
span:elt.span(),
cat:Categorization::Deref(base_cmt.clone(), 0, ptr),
mutbl:m,
ty: match base_cmt.ty.builtin_deref(false, ty::NoPreference) {
Some(mt) => mt.ty,
None => bug!("Found non-derefable type")
},
note: NoteNone
})
}

deref_interior(_) => {
base_cmt
}
};
debug!("deref_vec ret {:?}", ret);
Ok(ret)
}

/// Given a pattern P like: `[_, ..Q, _]`, where `vec_cmt` is the cmt for `P`, `slice_pat` is
/// the pattern `Q`, returns:
///
/// * a cmt for `Q`
/// * the mutability and region of the slice `Q`
///
/// These last two bits of info happen to be things that borrowck needs.
pub fn cat_slice_pattern(&self,
vec_cmt: cmt<'tcx>,
slice_pat: &hir::Pat)
-> McResult<(cmt<'tcx>, hir::Mutability, ty::Region)> {
let slice_ty = self.node_ty(slice_pat.id)?;
let (slice_mutbl, slice_r) = vec_slice_info(slice_pat, slice_ty);
let context = InteriorOffsetKind::Pattern;
let cmt_vec = self.deref_vec(slice_pat, vec_cmt, context)?;
let cmt_slice = self.cat_index(slice_pat, cmt_vec, context)?;
return Ok((cmt_slice, slice_mutbl, slice_r));

/// In a pattern like [a, b, ..c], normally `c` has slice type, but if you have [a, b,
/// ..ref c], then the type of `ref c` will be `&&[]`, so to extract the slice details we
/// have to recurse through rptrs.
fn vec_slice_info(pat: &hir::Pat, slice_ty: Ty)
-> (hir::Mutability, ty::Region) {
match slice_ty.sty {
ty::TyRef(r, ref mt) => match mt.ty.sty {
ty::TySlice(_) => (mt.mutbl, *r),
_ => vec_slice_info(pat, mt.ty),
},

_ => {
span_bug!(pat.span,
"type of slice pattern is not a slice");
}
}
}
}

pub fn cat_imm_interior<N:ast_node>(&self,
Expand Down Expand Up @@ -1319,15 +1229,12 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {

PatKind::Vec(ref before, ref slice, ref after) => {
let context = InteriorOffsetKind::Pattern;
let vec_cmt = self.deref_vec(pat, cmt, context)?;
let elt_cmt = self.cat_index(pat, vec_cmt, context)?;
let elt_cmt = self.cat_index(pat, cmt, context)?;
for before_pat in before {
self.cat_pattern_(elt_cmt.clone(), &before_pat, op)?;
}
if let Some(ref slice_pat) = *slice {
let slice_ty = self.pat_ty(&slice_pat)?;
let slice_cmt = self.cat_rvalue_node(pat.id(), pat.span(), slice_ty);
self.cat_pattern_(slice_cmt, &slice_pat, op)?;
self.cat_pattern_(elt_cmt.clone(), &slice_pat, op)?;
}
for after_pat in after {
self.cat_pattern_(elt_cmt.clone(), &after_pat, op)?;
Expand Down Expand Up @@ -1620,18 +1527,6 @@ impl fmt::Debug for InteriorKind {
}
}

fn element_kind(t: Ty) -> ElementKind {
match t.sty {
ty::TyRef(_, ty::TypeAndMut{ty, ..}) |
ty::TyBox(ty) => match ty.sty {
ty::TySlice(_) => VecElement,
_ => OtherElement
},
ty::TyArray(..) | ty::TySlice(_) => VecElement,
_ => OtherElement
}
}

impl fmt::Debug for Upvar {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}/{:?}", self.id, self.kind)
Expand Down
Loading