implement pattern-binding-modes RFC
See the [RFC] and [tracking issue]. [tracking issue]: https://github.com/rust-lang/rust/issues/42640 [RFC]: https://github.com/rust-lang/rfcs/blob/491e0af/text/2005-match-ergonomics.md
This commit is contained in:
parent
a8feaee5b6
commit
de55b4f077
@ -0,0 +1,58 @@
|
||||
# `match_default_bindings`
|
||||
|
||||
The tracking issue for this feature is: [#42640]
|
||||
|
||||
[#42640]: https://github.com/rust-lang/rust/issues/42640
|
||||
|
||||
------------------------
|
||||
|
||||
Match default bindings (also called "default binding modes in match") improves ergonomics for
|
||||
pattern-matching on references by introducing automatic dereferencing (and a corresponding shift
|
||||
in binding modes) for large classes of patterns that would otherwise not compile.
|
||||
|
||||
For example, under match default bindings,
|
||||
|
||||
```rust
|
||||
#![feature(match_default_bindings)]
|
||||
|
||||
fn main() {
|
||||
let x: &Option<_> = &Some(0);
|
||||
|
||||
match x {
|
||||
Some(y) => {
|
||||
println!("y={}", *y);
|
||||
},
|
||||
None => {},
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
compiles and is equivalent to either of the below:
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let x: &Option<_> = &Some(0);
|
||||
|
||||
match *x {
|
||||
Some(ref y) => {
|
||||
println!("y={}", *y);
|
||||
},
|
||||
None => {},
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let x: &Option<_> = &Some(0);
|
||||
|
||||
match x {
|
||||
&Some(ref y) => {
|
||||
println!("y={}", *y);
|
||||
},
|
||||
&None => {},
|
||||
}
|
||||
}
|
||||
```
|
@ -160,11 +160,13 @@ impl hir::Pat {
|
||||
variants
|
||||
}
|
||||
|
||||
/// Checks if the pattern contains any `ref` or `ref mut` bindings,
|
||||
/// and if yes whether it contains mutable or just immutables ones.
|
||||
/// Checks if the pattern contains any `ref` or `ref mut` bindings, and if
|
||||
/// yes whether it contains mutable or just immutables ones.
|
||||
///
|
||||
/// FIXME(tschottdorf): this is problematic as the HIR is being scraped,
|
||||
/// but ref bindings may be implicit after #42640.
|
||||
/// FIXME(tschottdorf): this is problematic as the HIR is being scraped, but
|
||||
/// ref bindings are be implicit after #42640 (default match binding modes).
|
||||
///
|
||||
/// See #44848.
|
||||
pub fn contains_explicit_ref_binding(&self) -> Option<hir::Mutability> {
|
||||
let mut result = None;
|
||||
self.each_binding(|annotation, _, _, _| {
|
||||
@ -188,7 +190,9 @@ impl hir::Arm {
|
||||
/// bindings, and if yes whether its containing mutable ones or just immutables ones.
|
||||
pub fn contains_explicit_ref_binding(&self) -> Option<hir::Mutability> {
|
||||
// FIXME(tschottdorf): contains_explicit_ref_binding() must be removed
|
||||
// for #42640.
|
||||
// for #42640 (default match binding modes).
|
||||
//
|
||||
// See #44848.
|
||||
self.pats.iter()
|
||||
.filter_map(|pat| pat.contains_explicit_ref_binding())
|
||||
.max_by_key(|m| match *m {
|
||||
|
@ -1094,7 +1094,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
// FIXME(#19596) This is a workaround, but there should be a better way to do this
|
||||
fn cat_pattern_<F>(&self, cmt: cmt<'tcx>, pat: &hir::Pat, op: &mut F) -> McResult<()>
|
||||
fn cat_pattern_<F>(&self, mut cmt: cmt<'tcx>, pat: &hir::Pat, op: &mut F) -> McResult<()>
|
||||
where F : FnMut(cmt<'tcx>, &hir::Pat)
|
||||
{
|
||||
// Here, `cmt` is the categorization for the value being
|
||||
@ -1144,6 +1144,56 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||
|
||||
debug!("cat_pattern: {:?} cmt={:?}", pat, cmt);
|
||||
|
||||
// If (pattern) adjustments are active for this pattern, adjust the `cmt` correspondingly.
|
||||
// `cmt`s are constructed differently from patterns. For example, in
|
||||
//
|
||||
// ```
|
||||
// match foo {
|
||||
// &&Some(x, ) => { ... },
|
||||
// _ => { ... },
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// the pattern `&&Some(x,)` is represented as `Ref { Ref { TupleStruct }}`. To build the
|
||||
// corresponding `cmt` we start with a `cmt` for `foo`, and then, by traversing the
|
||||
// pattern, try to answer the question: given the address of `foo`, how is `x` reached?
|
||||
//
|
||||
// `&&Some(x,)` `cmt_foo`
|
||||
// `&Some(x,)` `deref { cmt_foo}`
|
||||
// `Some(x,)` `deref { deref { cmt_foo }}`
|
||||
// (x,)` `field0 { deref { deref { cmt_foo }}}` <- resulting cmt
|
||||
//
|
||||
// The above example has no adjustments. If the code were instead the (after adjustments,
|
||||
// equivalent) version
|
||||
//
|
||||
// ```
|
||||
// match foo {
|
||||
// Some(x, ) => { ... },
|
||||
// _ => { ... },
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// Then we see that to get the same result, we must start with `deref { deref { cmt_foo }}`
|
||||
// instead of `cmt_foo` since the pattern is now `Some(x,)` and not `&&Some(x,)`, even
|
||||
// though its assigned type is that of `&&Some(x,)`.
|
||||
for _ in 0..self.tables
|
||||
.pat_adjustments()
|
||||
.get(pat.hir_id)
|
||||
.map(|v| v.len())
|
||||
.unwrap_or(0) {
|
||||
cmt = self.cat_deref(pat, cmt, true /* implicit */)?;
|
||||
}
|
||||
let cmt = cmt; // lose mutability
|
||||
|
||||
// Invoke the callback, but only now, after the `cmt` has adjusted.
|
||||
//
|
||||
// To see that this makes sense, consider `match &Some(3) { Some(x) => { ... }}`. In that
|
||||
// case, the initial `cmt` will be that for `&Some(3)` and the pattern is `Some(x)`. We
|
||||
// don't want to call `op` with these incompatible values. As written, what happens instead
|
||||
// is that `op` is called with the adjusted cmt (that for `*&Some(3)`) and the pattern
|
||||
// `Some(x)` (which matches). Recursing once more, `*&Some(3)` and the pattern `Some(x)`
|
||||
// result in the cmt `Downcast<Some>(*&Some(3)).0` associated to `x` and invoke `op` with
|
||||
// that (where the `ref` on `x` is implied).
|
||||
op(cmt.clone(), pat);
|
||||
|
||||
match pat.node {
|
||||
|
@ -337,9 +337,24 @@ pub struct TypeckTables<'tcx> {
|
||||
|
||||
adjustments: ItemLocalMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
|
||||
|
||||
// Stores the actual binding mode for all instances of hir::BindingAnnotation.
|
||||
/// Stores the actual binding mode for all instances of hir::BindingAnnotation.
|
||||
pat_binding_modes: ItemLocalMap<BindingMode>,
|
||||
|
||||
/// Stores the types which were implicitly dereferenced in pattern binding modes
|
||||
/// for later usage in HAIR lowering. For example,
|
||||
///
|
||||
/// ```
|
||||
/// match &&Some(5i32) {
|
||||
/// Some(n) => {},
|
||||
/// _ => {},
|
||||
/// }
|
||||
/// ```
|
||||
/// leads to a `vec![&&Option<i32>, &Option<i32>]`. Empty vectors are not stored.
|
||||
///
|
||||
/// See:
|
||||
/// https://github.com/rust-lang/rfcs/blob/master/text/2005-match-ergonomics.md#definitions
|
||||
pat_adjustments: ItemLocalMap<Vec<Ty<'tcx>>>,
|
||||
|
||||
/// Borrows
|
||||
pub upvar_capture_map: ty::UpvarCaptureMap<'tcx>,
|
||||
|
||||
@ -394,6 +409,7 @@ impl<'tcx> TypeckTables<'tcx> {
|
||||
node_substs: ItemLocalMap(),
|
||||
adjustments: ItemLocalMap(),
|
||||
pat_binding_modes: ItemLocalMap(),
|
||||
pat_adjustments: ItemLocalMap(),
|
||||
upvar_capture_map: FxHashMap(),
|
||||
generator_sigs: ItemLocalMap(),
|
||||
generator_interiors: ItemLocalMap(),
|
||||
@ -574,6 +590,21 @@ impl<'tcx> TypeckTables<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pat_adjustments(&self) -> LocalTableInContext<Vec<Ty<'tcx>>> {
|
||||
LocalTableInContext {
|
||||
local_id_root: self.local_id_root,
|
||||
data: &self.pat_adjustments,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pat_adjustments_mut(&mut self)
|
||||
-> LocalTableInContextMut<Vec<Ty<'tcx>>> {
|
||||
LocalTableInContextMut {
|
||||
local_id_root: self.local_id_root,
|
||||
data: &mut self.pat_adjustments,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> ty::UpvarCapture<'tcx> {
|
||||
self.upvar_capture_map[&upvar_id]
|
||||
}
|
||||
@ -699,6 +730,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for TypeckTables<'gcx> {
|
||||
ref node_substs,
|
||||
ref adjustments,
|
||||
ref pat_binding_modes,
|
||||
ref pat_adjustments,
|
||||
ref upvar_capture_map,
|
||||
ref closure_tys,
|
||||
ref closure_kinds,
|
||||
@ -720,6 +752,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for TypeckTables<'gcx> {
|
||||
node_substs.hash_stable(hcx, hasher);
|
||||
adjustments.hash_stable(hcx, hasher);
|
||||
pat_binding_modes.hash_stable(hcx, hasher);
|
||||
pat_adjustments.hash_stable(hcx, hasher);
|
||||
hash_stable_hashmap(hcx, hasher, upvar_capture_map, |up_var_id, hcx| {
|
||||
let ty::UpvarId {
|
||||
var_id,
|
||||
|
@ -301,6 +301,44 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
||||
}
|
||||
|
||||
pub fn lower_pattern(&mut self, pat: &'tcx hir::Pat) -> Pattern<'tcx> {
|
||||
// When implicit dereferences have been inserted in this pattern, the unadjusted lowered
|
||||
// pattern has the type that results *after* dereferencing. For example, in this code:
|
||||
//
|
||||
// ```
|
||||
// match &&Some(0i32) {
|
||||
// Some(n) => { ... },
|
||||
// _ => { ... },
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// the type assigned to `Some(n)` in `unadjusted_pat` would be `Option<i32>` (this is
|
||||
// determined in rustc_typeck::check::match). The adjustments would be
|
||||
//
|
||||
// `vec![&&Option<i32>, &Option<i32>]`.
|
||||
//
|
||||
// Applying the adjustments, we want to instead output `&&Some(n)` (as a HAIR pattern). So
|
||||
// we wrap the unadjusted pattern in `PatternKind::Deref` repeatedly, consuming the
|
||||
// adjustments in *reverse order* (last-in-first-out, so that the last `Deref` inserted
|
||||
// gets the least-dereferenced type).
|
||||
let unadjusted_pat = self.lower_pattern_unadjusted(pat);
|
||||
self.tables
|
||||
.pat_adjustments()
|
||||
.get(pat.hir_id)
|
||||
.unwrap_or(&vec![])
|
||||
.iter()
|
||||
.rev()
|
||||
.fold(unadjusted_pat, |pat, ref_ty| {
|
||||
debug!("{:?}: wrapping pattern with type {:?}", pat, ref_ty);
|
||||
Pattern {
|
||||
span: pat.span,
|
||||
ty: ref_ty,
|
||||
kind: Box::new(PatternKind::Deref { subpattern: pat }),
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat) -> Pattern<'tcx> {
|
||||
let mut ty = self.tables.node_id_to_type(pat.hir_id);
|
||||
|
||||
let kind = match pat.node {
|
||||
|
@ -27,25 +27,111 @@ use syntax::ptr::P;
|
||||
use syntax_pos::Span;
|
||||
|
||||
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
pub fn check_pat(&self, pat: &'gcx hir::Pat, expected: Ty<'tcx>) {
|
||||
self.check_pat_arg(pat, expected, false);
|
||||
}
|
||||
|
||||
/// The `is_arg` argument indicates whether this pattern is the
|
||||
/// *outermost* pattern in an argument (e.g., in `fn foo(&x:
|
||||
/// &u32)`, it is true for the `&x` pattern but not `x`). This is
|
||||
/// used to tailor error reporting.
|
||||
pub fn check_pat_arg(&self, pat: &'gcx hir::Pat, expected: Ty<'tcx>, is_arg: bool) {
|
||||
pub fn check_pat_walk(
|
||||
&self,
|
||||
pat: &'gcx hir::Pat,
|
||||
mut expected: Ty<'tcx>,
|
||||
mut def_bm: ty::BindingMode,
|
||||
is_arg: bool)
|
||||
{
|
||||
let tcx = self.tcx;
|
||||
|
||||
debug!("check_pat(pat={:?},expected={:?},is_arg={})", pat, expected, is_arg);
|
||||
debug!("check_pat_walk(pat={:?},expected={:?},def_bm={:?},is_arg={})",
|
||||
pat, expected, def_bm, is_arg);
|
||||
|
||||
let is_non_ref_pat = match pat.node {
|
||||
PatKind::Struct(..) |
|
||||
PatKind::TupleStruct(..) |
|
||||
PatKind::Tuple(..) |
|
||||
PatKind::Box(_) |
|
||||
PatKind::Range(..) |
|
||||
PatKind::Slice(..) => true,
|
||||
PatKind::Lit(ref lt) => {
|
||||
let ty = self.check_expr(lt);
|
||||
match ty.sty {
|
||||
ty::TypeVariants::TyRef(..) => false,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
PatKind::Path(ref qpath) => {
|
||||
let (def, _, _) = self.resolve_ty_and_def_ufcs(qpath, pat.id, pat.span);
|
||||
match def {
|
||||
Def::Const(..) | Def::AssociatedConst(..) => false,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
PatKind::Wild |
|
||||
PatKind::Binding(..) |
|
||||
PatKind::Ref(..) => false,
|
||||
};
|
||||
if is_non_ref_pat && tcx.sess.features.borrow().match_default_bindings {
|
||||
debug!("pattern is non reference pattern");
|
||||
let mut exp_ty = self.resolve_type_vars_with_obligations(&expected);
|
||||
|
||||
// Peel off as many `&` or `&mut` from the discriminant as possible. For example,
|
||||
// for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches
|
||||
// the `Some(5)` which is not of type TyRef.
|
||||
//
|
||||
// For each ampersand peeled off, update the binding mode and push the original
|
||||
// type into the adjustments vector.
|
||||
//
|
||||
// See the examples in `run-pass/match-defbm*.rs`.
|
||||
let mut pat_adjustments = vec![];
|
||||
expected = loop {
|
||||
debug!("inspecting {:?} with type {:?}", exp_ty, exp_ty.sty);
|
||||
match exp_ty.sty {
|
||||
ty::TypeVariants::TyRef(_, ty::TypeAndMut{
|
||||
ty: inner_ty, mutbl: inner_mutability,
|
||||
}) => {
|
||||
debug!("current discriminant is TyRef, inserting implicit deref");
|
||||
// Preserve the reference type. We'll need it later during HAIR lowering.
|
||||
pat_adjustments.push(exp_ty);
|
||||
|
||||
exp_ty = inner_ty;
|
||||
def_bm = match def_bm {
|
||||
// If default binding mode is by value, make it `ref` or `ref mut`
|
||||
// (depending on whether we observe `&` or `&mut`).
|
||||
ty::BindByValue(_) =>
|
||||
ty::BindByReference(inner_mutability),
|
||||
|
||||
// Once a `ref`, always a `ref`. This is because a `& &mut` can't mutate
|
||||
// the underlying value.
|
||||
ty::BindByReference(hir::Mutability::MutImmutable) =>
|
||||
ty::BindByReference(hir::Mutability::MutImmutable),
|
||||
|
||||
// When `ref mut`, stay a `ref mut` (on `&mut`) or downgrade to `ref`
|
||||
// (on `&`).
|
||||
ty::BindByReference(hir::Mutability::MutMutable) =>
|
||||
ty::BindByReference(inner_mutability),
|
||||
};
|
||||
},
|
||||
_ => break exp_ty,
|
||||
}
|
||||
};
|
||||
if pat_adjustments.len() > 0 {
|
||||
debug!("default binding mode is now {:?}", def_bm);
|
||||
self.inh.tables.borrow_mut()
|
||||
.pat_adjustments_mut()
|
||||
.insert(pat.hir_id, pat_adjustments);
|
||||
}
|
||||
}
|
||||
|
||||
// Lose mutability now that we know binding mode and discriminant type.
|
||||
let def_bm = def_bm;
|
||||
let expected = expected;
|
||||
|
||||
let ty = match pat.node {
|
||||
PatKind::Wild => {
|
||||
expected
|
||||
}
|
||||
PatKind::Lit(ref lt) => {
|
||||
let ty = self.check_expr(<);
|
||||
// We've already computed the type above (when checking for a non-ref pat), so
|
||||
// avoid computing it again.
|
||||
let ty = self.node_ty(lt.hir_id);
|
||||
|
||||
// Byte string patterns behave the same way as array patterns
|
||||
// They can denote both statically and dynamically sized byte arrays
|
||||
@ -114,10 +200,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
common_type
|
||||
}
|
||||
PatKind::Binding(ba, var_id, _, ref sub) => {
|
||||
// Note the binding mode in the typeck tables. For now, what we store is always
|
||||
// identical to what could be scraped from the HIR, but this will change with
|
||||
// default binding modes (#42640).
|
||||
let bm = ty::BindingMode::convert(ba);
|
||||
let bm = if ba == hir::BindingAnnotation::Unannotated {
|
||||
def_bm
|
||||
} else {
|
||||
ty::BindingMode::convert(ba)
|
||||
};
|
||||
self.inh
|
||||
.tables
|
||||
.borrow_mut()
|
||||
@ -155,19 +242,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
if let Some(ref p) = *sub {
|
||||
self.check_pat(&p, expected);
|
||||
self.check_pat_walk(&p, expected, def_bm, true);
|
||||
}
|
||||
|
||||
typ
|
||||
}
|
||||
PatKind::TupleStruct(ref qpath, ref subpats, ddpos) => {
|
||||
self.check_pat_tuple_struct(pat, qpath, &subpats, ddpos, expected)
|
||||
self.check_pat_tuple_struct(pat, qpath, &subpats, ddpos, expected, def_bm)
|
||||
}
|
||||
PatKind::Path(ref qpath) => {
|
||||
self.check_pat_path(pat, qpath, expected)
|
||||
}
|
||||
PatKind::Struct(ref qpath, ref fields, etc) => {
|
||||
self.check_pat_struct(pat, qpath, fields, etc, expected)
|
||||
self.check_pat_struct(pat, qpath, fields, etc, expected, def_bm)
|
||||
}
|
||||
PatKind::Tuple(ref elements, ddpos) => {
|
||||
let mut expected_len = elements.len();
|
||||
@ -188,7 +275,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
let pat_ty = tcx.mk_ty(ty::TyTuple(element_tys, false));
|
||||
self.demand_eqtype(pat.span, expected, pat_ty);
|
||||
for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
|
||||
self.check_pat(elem, &element_tys[i]);
|
||||
self.check_pat_walk(elem, &element_tys[i], def_bm, true);
|
||||
}
|
||||
pat_ty
|
||||
}
|
||||
@ -201,10 +288,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
// think any errors can be introduced by using
|
||||
// `demand::eqtype`.
|
||||
self.demand_eqtype(pat.span, expected, uniq_ty);
|
||||
self.check_pat(&inner, inner_ty);
|
||||
self.check_pat_walk(&inner, inner_ty, def_bm, true);
|
||||
uniq_ty
|
||||
} else {
|
||||
self.check_pat(&inner, tcx.types.err);
|
||||
self.check_pat_walk(&inner, tcx.types.err, def_bm, true);
|
||||
tcx.types.err
|
||||
}
|
||||
}
|
||||
@ -219,7 +306,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
// can, to avoid creating needless variables. This
|
||||
// also helps with the bad interactions of the given
|
||||
// hack detailed in (*) below.
|
||||
debug!("check_pat_arg: expected={:?}", expected);
|
||||
debug!("check_pat_walk: expected={:?}", expected);
|
||||
let (rptr_ty, inner_ty) = match expected.sty {
|
||||
ty::TyRef(_, mt) if mt.mutbl == mutbl => {
|
||||
(expected, mt.ty)
|
||||
@ -230,7 +317,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
let mt = ty::TypeAndMut { ty: inner_ty, mutbl: mutbl };
|
||||
let region = self.next_region_var(infer::PatternRegion(pat.span));
|
||||
let rptr_ty = tcx.mk_ref(region, mt);
|
||||
debug!("check_pat_arg: demanding {:?} = {:?}", expected, rptr_ty);
|
||||
debug!("check_pat_walk: demanding {:?} = {:?}", expected, rptr_ty);
|
||||
let err = self.demand_eqtype_diag(pat.span, expected, rptr_ty);
|
||||
|
||||
// Look for a case like `fn foo(&foo: u32)` and suggest
|
||||
@ -253,10 +340,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
};
|
||||
|
||||
self.check_pat(&inner, inner_ty);
|
||||
self.check_pat_walk(&inner, inner_ty, def_bm, true);
|
||||
rptr_ty
|
||||
} else {
|
||||
self.check_pat(&inner, tcx.types.err);
|
||||
self.check_pat_walk(&inner, tcx.types.err, def_bm, true);
|
||||
tcx.types.err
|
||||
}
|
||||
}
|
||||
@ -314,13 +401,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
};
|
||||
|
||||
for elt in before {
|
||||
self.check_pat(&elt, inner_ty);
|
||||
self.check_pat_walk(&elt, inner_ty, def_bm, true);
|
||||
}
|
||||
if let Some(ref slice) = *slice {
|
||||
self.check_pat(&slice, slice_ty);
|
||||
self.check_pat_walk(&slice, slice_ty, def_bm, true);
|
||||
}
|
||||
for elt in after {
|
||||
self.check_pat(&elt, inner_ty);
|
||||
self.check_pat_walk(&elt, inner_ty, def_bm, true);
|
||||
}
|
||||
expected_ty
|
||||
}
|
||||
@ -329,7 +416,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
self.write_ty(pat.hir_id, ty);
|
||||
|
||||
// (*) In most of the cases above (literals and constants being
|
||||
// the exception), we relate types using strict equality, evewn
|
||||
// the exception), we relate types using strict equality, even
|
||||
// though subtyping would be sufficient. There are a few reasons
|
||||
// for this, some of which are fairly subtle and which cost me
|
||||
// (nmatsakis) an hour or two debugging to remember, so I thought
|
||||
@ -339,7 +426,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
// cause some inconvenience. What we are saying is that the type
|
||||
// of `x` becomes *exactly* what is expected. This can cause unnecessary
|
||||
// errors in some cases, such as this one:
|
||||
// it will cause errors in a case like this:
|
||||
//
|
||||
// ```
|
||||
// fn foo<'x>(x: &'x int) {
|
||||
@ -409,11 +495,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
// use the *precise* type of the discriminant, *not* some supertype, as
|
||||
// the "discriminant type" (issue #23116).
|
||||
//
|
||||
// FIXME(tschottdorf): don't call contains_explicit_ref_binding, which
|
||||
// is problematic as the HIR is being scraped, but ref bindings may be
|
||||
// implicit after #42640. We need to make sure that pat_adjustments
|
||||
// (once introduced) is populated by the time we get here.
|
||||
//
|
||||
// arielb1 [writes here in this comment thread][c] that there
|
||||
// is certainly *some* potential danger, e.g. for an example
|
||||
// like:
|
||||
@ -455,7 +536,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
// assert_eq!(foo.0.0, 42);
|
||||
// }
|
||||
// ```
|
||||
|
||||
//
|
||||
// FIXME(tschottdorf): don't call contains_explicit_ref_binding, which
|
||||
// is problematic as the HIR is being scraped, but ref bindings may be
|
||||
// implicit after #42640. We need to make sure that pat_adjustments
|
||||
// (once introduced) is populated by the time we get here.
|
||||
//
|
||||
// See #44848.
|
||||
let contains_ref_bindings = arms.iter()
|
||||
.filter_map(|a| a.contains_explicit_ref_binding())
|
||||
.max_by_key(|m| match *m {
|
||||
@ -495,7 +582,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
let mut all_pats_diverge = Diverges::WarnedAlways;
|
||||
for p in &arm.pats {
|
||||
self.diverges.set(Diverges::Maybe);
|
||||
self.check_pat(&p, discrim_ty);
|
||||
self.check_pat_walk(&p, discrim_ty,
|
||||
ty::BindingMode::BindByValue(hir::Mutability::MutImmutable), true);
|
||||
all_pats_diverge &= self.diverges.get();
|
||||
}
|
||||
|
||||
@ -576,14 +664,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
qpath: &hir::QPath,
|
||||
fields: &'gcx [Spanned<hir::FieldPat>],
|
||||
etc: bool,
|
||||
expected: Ty<'tcx>) -> Ty<'tcx>
|
||||
expected: Ty<'tcx>,
|
||||
def_bm: ty::BindingMode) -> Ty<'tcx>
|
||||
{
|
||||
// Resolve the path and check the definition for errors.
|
||||
let (variant, pat_ty) = if let Some(variant_ty) = self.check_struct_path(qpath, pat.id) {
|
||||
variant_ty
|
||||
} else {
|
||||
for field in fields {
|
||||
self.check_pat(&field.node.pat, self.tcx.types.err);
|
||||
self.check_pat_walk(&field.node.pat, self.tcx.types.err, def_bm, true);
|
||||
}
|
||||
return self.tcx.types.err;
|
||||
};
|
||||
@ -592,7 +681,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
self.demand_eqtype(pat.span, expected, pat_ty);
|
||||
|
||||
// Type check subpatterns.
|
||||
self.check_struct_pat_fields(pat_ty, pat.id, pat.span, variant, fields, etc);
|
||||
self.check_struct_pat_fields(pat_ty, pat.id, pat.span, variant, fields, etc, def_bm);
|
||||
pat_ty
|
||||
}
|
||||
|
||||
@ -637,12 +726,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
qpath: &hir::QPath,
|
||||
subpats: &'gcx [P<hir::Pat>],
|
||||
ddpos: Option<usize>,
|
||||
expected: Ty<'tcx>) -> Ty<'tcx>
|
||||
expected: Ty<'tcx>,
|
||||
def_bm: ty::BindingMode) -> Ty<'tcx>
|
||||
{
|
||||
let tcx = self.tcx;
|
||||
let on_error = || {
|
||||
for pat in subpats {
|
||||
self.check_pat(&pat, tcx.types.err);
|
||||
self.check_pat_walk(&pat, tcx.types.err, def_bm, true);
|
||||
}
|
||||
};
|
||||
let report_unexpected_def = |def: Def| {
|
||||
@ -678,6 +768,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
// Replace constructor type with constructed type for tuple struct patterns.
|
||||
let pat_ty = pat_ty.fn_sig(tcx).output();
|
||||
let pat_ty = tcx.no_late_bound_regions(&pat_ty).expect("expected fn type");
|
||||
|
||||
self.demand_eqtype(pat.span, expected, pat_ty);
|
||||
|
||||
// Type check subpatterns.
|
||||
@ -689,7 +780,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
};
|
||||
for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) {
|
||||
let field_ty = self.field_ty(subpat.span, &variant.fields[i], substs);
|
||||
self.check_pat(&subpat, field_ty);
|
||||
self.check_pat_walk(&subpat, field_ty, def_bm, true);
|
||||
|
||||
self.tcx.check_stability(variant.fields[i].did, pat.id, subpat.span);
|
||||
}
|
||||
@ -715,7 +806,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
span: Span,
|
||||
variant: &'tcx ty::VariantDef,
|
||||
fields: &'gcx [Spanned<hir::FieldPat>],
|
||||
etc: bool) {
|
||||
etc: bool,
|
||||
def_bm: ty::BindingMode) {
|
||||
let tcx = self.tcx;
|
||||
|
||||
let (substs, kind_name) = match adt_ty.sty {
|
||||
@ -772,7 +864,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
};
|
||||
|
||||
self.check_pat(&field.pat, field_ty);
|
||||
self.check_pat_walk(&field.pat, field_ty, def_bm, true);
|
||||
}
|
||||
|
||||
// Report an error if incorrect number of the fields were specified.
|
||||
|
@ -1037,7 +1037,8 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
|
||||
// Add formal parameters.
|
||||
for (arg_ty, arg) in fn_sig.inputs().iter().zip(&body.arguments) {
|
||||
// Check the pattern.
|
||||
fcx.check_pat_arg(&arg.pat, arg_ty, true);
|
||||
fcx.check_pat_walk(&arg.pat, arg_ty,
|
||||
ty::BindingMode::BindByValue(hir::Mutability::MutImmutable), true);
|
||||
|
||||
// Check that argument is Sized.
|
||||
// The check for a non-trivial pattern is a hack to avoid duplicate warnings
|
||||
@ -4106,6 +4107,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
(self.to_ty(qself), segment)
|
||||
}
|
||||
};
|
||||
let hir_id = self.tcx.hir.node_to_hir_id(node_id);
|
||||
if let Some(cached_def) = self.tables.borrow().type_dependent_defs().get(hir_id) {
|
||||
// Return directly on cache hit. This is useful to avoid doubly reporting
|
||||
// errors with default match binding modes. See #44614.
|
||||
return (*cached_def, Some(ty), slice::ref_slice(&**item_segment))
|
||||
}
|
||||
let item_name = item_segment.name;
|
||||
let def = match self.resolve_ufcs(span, item_name, ty, node_id) {
|
||||
Ok(def) => def,
|
||||
@ -4122,7 +4129,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
};
|
||||
|
||||
// Write back the new resolution.
|
||||
let hir_id = self.tcx.hir.node_to_hir_id(node_id);
|
||||
self.tables.borrow_mut().type_dependent_defs_mut().insert(hir_id, def);
|
||||
(def, Some(ty), slice::ref_slice(&**item_segment))
|
||||
}
|
||||
@ -4132,7 +4138,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
init: &'gcx hir::Expr) -> Ty<'tcx>
|
||||
{
|
||||
// FIXME(tschottdorf): contains_explicit_ref_binding() must be removed
|
||||
// for #42640.
|
||||
// for #42640 (default match binding modes).
|
||||
//
|
||||
// See #44848.
|
||||
let ref_bindings = local.pat.contains_explicit_ref_binding();
|
||||
|
||||
let local_ty = self.local_ty(init.span, local.id);
|
||||
@ -4164,7 +4172,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
self.check_pat(&local.pat, t);
|
||||
self.check_pat_walk(&local.pat, t,
|
||||
ty::BindingMode::BindByValue(hir::Mutability::MutImmutable),
|
||||
true);
|
||||
let pat_ty = self.node_ty(local.pat.hir_id);
|
||||
if pat_ty.references_error() {
|
||||
self.write_ty(local.hir_id, pat_ty);
|
||||
|
@ -197,6 +197,8 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
|
||||
_ => {}
|
||||
};
|
||||
|
||||
self.visit_pat_adjustments(p.span, p.hir_id);
|
||||
|
||||
self.visit_node_id(p.span, p.hir_id);
|
||||
intravisit::walk_pat(self, p);
|
||||
}
|
||||
@ -366,6 +368,25 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_pat_adjustments(&mut self, span: Span, hir_id: hir::HirId) {
|
||||
let adjustment = self.fcx
|
||||
.tables
|
||||
.borrow_mut()
|
||||
.pat_adjustments_mut()
|
||||
.remove(hir_id);
|
||||
match adjustment {
|
||||
None => {
|
||||
debug!("No pat_adjustments for node {:?}", hir_id);
|
||||
}
|
||||
|
||||
Some(adjustment) => {
|
||||
let resolved_adjustment = self.resolve(&adjustment, &span);
|
||||
debug!("pat_adjustments for node {:?}: {:?}", hir_id, resolved_adjustment);
|
||||
self.tables.pat_adjustments_mut().insert(hir_id, resolved_adjustment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_generator_interiors(&mut self) {
|
||||
let common_local_id_root = self.fcx.tables.borrow().local_id_root.unwrap();
|
||||
for (&id, interior) in self.fcx.tables.borrow().generator_interiors().iter() {
|
||||
|
@ -395,6 +395,9 @@ declare_features! (
|
||||
|
||||
// allow `..=` in patterns (RFC 1192)
|
||||
(active, dotdoteq_in_patterns, "1.22.0", Some(28237)),
|
||||
|
||||
// Default match binding modes (RFC 2005)
|
||||
(active, match_default_bindings, "1.22.0", Some(42640)),
|
||||
);
|
||||
|
||||
declare_features! (
|
||||
|
16
src/test/compile-fail/feature-gate-match_default_bindings.rs
Normal file
16
src/test/compile-fail/feature-gate-match_default_bindings.rs
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
pub fn main() {
|
||||
match &Some(3) {
|
||||
Some(n) => {}, //~ ERROR mismatched types [E0308]
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
@ -9,7 +9,8 @@
|
||||
// except according to those terms.
|
||||
|
||||
fn main() {
|
||||
for (ref i,) in [].iter() { //~ ERROR mismatched types
|
||||
// NB: this (almost) typechecks when default binding modes are enabled.
|
||||
for (ref i,) in [].iter() { //~ ERROR mismatched types [E0308]
|
||||
i.clone();
|
||||
}
|
||||
}
|
||||
|
@ -21,17 +21,4 @@ fn main() {
|
||||
//~| expected tuple, found enum `A`
|
||||
_ => ()
|
||||
}
|
||||
|
||||
match &Some(42) {
|
||||
Some(x) => (),
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected type `&std::option::Option<{integer}>`
|
||||
//~| found type `std::option::Option<_>`
|
||||
//~| expected reference, found enum `std::option::Option`
|
||||
None => ()
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected type `&std::option::Option<{integer}>`
|
||||
//~| found type `std::option::Option<_>`
|
||||
//~| expected reference, found enum `std::option::Option`
|
||||
}
|
||||
}
|
||||
|
@ -17,8 +17,9 @@ fn main() {
|
||||
_ => { }
|
||||
};
|
||||
|
||||
// Note that this one works with default binding modes.
|
||||
match &[0, 1, 2] {
|
||||
[..] => {} //~ ERROR expected an array or slice, found `&[{integer}; 3]`
|
||||
[..] => {} //~ ERROR expected an array or slice, found `&[{integer}; 3]` [E0529]
|
||||
};
|
||||
|
||||
match &[0, 1, 2] {
|
||||
|
@ -10,13 +10,19 @@
|
||||
|
||||
#![feature(slice_patterns)]
|
||||
|
||||
// NB: this test was introduced in #23121 and will have to change when default match binding modes
|
||||
// stabilizes.
|
||||
|
||||
fn slice_pat(x: &[u8]) {
|
||||
// OLD!
|
||||
match x {
|
||||
[a, b..] => {}
|
||||
[a, b..] => {},
|
||||
//~^ ERROR expected an array or slice, found `&[u8]`
|
||||
//~| HELP the semantics of slice patterns changed recently; see issue #23121
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
fn main() {
|
||||
slice_pat("foo".as_bytes());
|
||||
}
|
||||
|
27
src/test/run-pass/rfc-2005-default-binding-mode/box.rs
Normal file
27
src/test/run-pass/rfc-2005-default-binding-mode/box.rs
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(box_syntax, box_patterns)]
|
||||
#![feature(match_default_bindings)]
|
||||
|
||||
struct Foo{}
|
||||
|
||||
pub fn main() {
|
||||
let b = box Foo{};
|
||||
let box f = &b;
|
||||
let _: &Foo = f;
|
||||
|
||||
match &&&b {
|
||||
box f => {
|
||||
let _: &Foo = f;
|
||||
},
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
51
src/test/run-pass/rfc-2005-default-binding-mode/constref.rs
Normal file
51
src/test/run-pass/rfc-2005-default-binding-mode/constref.rs
Normal file
@ -0,0 +1,51 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(match_default_bindings)]
|
||||
|
||||
const CONST_REF: &[u8; 3] = b"foo";
|
||||
|
||||
trait Foo {
|
||||
const CONST_REF_DEFAULT: &'static [u8; 3] = b"bar";
|
||||
const CONST_REF: &'static [u8; 3];
|
||||
}
|
||||
|
||||
impl Foo for i32 {
|
||||
const CONST_REF: &'static [u8; 3] = b"jjj";
|
||||
}
|
||||
|
||||
impl Foo for i64 {
|
||||
const CONST_REF_DEFAULT: &'static [u8; 3] = b"ggg";
|
||||
const CONST_REF: &'static [u8; 3] = b"fff";
|
||||
}
|
||||
|
||||
// Check that (associated and free) const references are not mistaken for a
|
||||
// non-reference pattern (in which case they would be auto-dereferenced, making
|
||||
// the types mismatched).
|
||||
|
||||
fn const_ref() -> bool {
|
||||
let f = b"foo";
|
||||
match f {
|
||||
CONST_REF => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn associated_const_ref() -> bool {
|
||||
match (b"bar", b"jjj", b"ggg", b"fff") {
|
||||
(i32::CONST_REF_DEFAULT, i32::CONST_REF, i64::CONST_REF_DEFAULT, i64::CONST_REF) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
assert!(const_ref());
|
||||
assert!(associated_const_ref());
|
||||
}
|
56
src/test/run-pass/rfc-2005-default-binding-mode/enum.rs
Normal file
56
src/test/run-pass/rfc-2005-default-binding-mode/enum.rs
Normal file
@ -0,0 +1,56 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(match_default_bindings)]
|
||||
|
||||
enum Wrapper {
|
||||
Wrap(i32),
|
||||
}
|
||||
|
||||
use Wrapper::Wrap;
|
||||
|
||||
pub fn main() {
|
||||
let Wrap(x) = &Wrap(3);
|
||||
println!("{}", *x);
|
||||
|
||||
let Wrap(x) = &mut Wrap(3);
|
||||
println!("{}", *x);
|
||||
|
||||
if let Some(x) = &Some(3) {
|
||||
println!("{}", *x);
|
||||
} else {
|
||||
panic!();
|
||||
}
|
||||
|
||||
if let Some(x) = &mut Some(3) {
|
||||
println!("{}", *x);
|
||||
} else {
|
||||
panic!();
|
||||
}
|
||||
|
||||
if let Some(x) = &mut Some(3) {
|
||||
*x += 1;
|
||||
} else {
|
||||
panic!();
|
||||
}
|
||||
|
||||
while let Some(x) = &Some(3) {
|
||||
println!("{}", *x);
|
||||
break;
|
||||
}
|
||||
while let Some(x) = &mut Some(3) {
|
||||
println!("{}", *x);
|
||||
break;
|
||||
}
|
||||
while let Some(x) = &mut Some(3) {
|
||||
*x += 1;
|
||||
break;
|
||||
}
|
||||
}
|
31
src/test/run-pass/rfc-2005-default-binding-mode/for.rs
Normal file
31
src/test/run-pass/rfc-2005-default-binding-mode/for.rs
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(match_default_bindings)]
|
||||
|
||||
pub fn main() {
|
||||
let mut tups = vec![(0u8, 1u8)];
|
||||
|
||||
for (n, m) in &tups {
|
||||
let _: &u8 = n;
|
||||
let _: &u8 = m;
|
||||
}
|
||||
|
||||
for (n, m) in &mut tups {
|
||||
*n += 1;
|
||||
*m += 2;
|
||||
}
|
||||
|
||||
assert_eq!(tups, vec![(1u8, 3u8)]);
|
||||
|
||||
for (n, m) in tups {
|
||||
println!("{} {}", m, n);
|
||||
}
|
||||
}
|
259
src/test/run-pass/rfc-2005-default-binding-mode/general.rs
Normal file
259
src/test/run-pass/rfc-2005-default-binding-mode/general.rs
Normal file
@ -0,0 +1,259 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(match_default_bindings)]
|
||||
|
||||
fn some_or_wildcard(r: &Option<i32>, b: &i32) {
|
||||
let _: &i32 = match r {
|
||||
Some(a) => a,
|
||||
_ => b,
|
||||
};
|
||||
}
|
||||
|
||||
fn none_or_wildcard(r: &Option<i32>, b: &i32) {
|
||||
let _: &i32 = match r {
|
||||
None => b,
|
||||
_ => b,
|
||||
};
|
||||
}
|
||||
|
||||
fn some_or_ref_none(r: &Option<i32>, b: &i32) {
|
||||
let _: &i32 = match r {
|
||||
Some(a) => a,
|
||||
&None => b,
|
||||
};
|
||||
}
|
||||
|
||||
fn ref_some_or_none(r: &Option<i32>, b: &i32) {
|
||||
let _: &i32 = match r {
|
||||
&Some(ref a) => a,
|
||||
None => b,
|
||||
};
|
||||
}
|
||||
|
||||
fn some_or_self(r: &Option<i32>) {
|
||||
let _: &Option<i32> = match r {
|
||||
Some(n) => {
|
||||
let _: &i32 = n;
|
||||
r
|
||||
},
|
||||
x => x,
|
||||
};
|
||||
}
|
||||
|
||||
fn multiple_deref(r: &&&&&Option<i32>) {
|
||||
let _: i32 = match r {
|
||||
Some(a) => *a,
|
||||
None => 5,
|
||||
};
|
||||
}
|
||||
|
||||
fn match_with_or() {
|
||||
// FIXME(tschottdorf): #44912.
|
||||
//
|
||||
// let x = &Some((3, 3));
|
||||
// let _: &i32 = match x {
|
||||
// Some((x, 3)) | &Some((ref x, 5)) => x,
|
||||
// _ => &5i32,
|
||||
// };
|
||||
}
|
||||
|
||||
fn nested_mixed() {
|
||||
match (&Some(5), &Some(6)) {
|
||||
(Some(a), &Some(mut b)) => {
|
||||
// Here, the `a` will be `&i32`, because in the first half of the tuple
|
||||
// we hit a non-reference pattern and shift into `ref` mode.
|
||||
//
|
||||
// In the second half of the tuple there's no non-reference pattern,
|
||||
// so `b` will be `i32` (bound with `move` mode). Moreover, `b` is
|
||||
// mutable.
|
||||
let _: &i32 = a;
|
||||
b = 7;
|
||||
let _: i32 = b;
|
||||
},
|
||||
_ => {},
|
||||
};
|
||||
}
|
||||
|
||||
fn nested_mixed_multiple_deref_1() {
|
||||
let x = (1, &Some(5));
|
||||
let y = &Some(x);
|
||||
match y {
|
||||
Some((a, Some(b))) => {
|
||||
let _: &i32 = a;
|
||||
let _: &i32 = b;
|
||||
},
|
||||
_ => {},
|
||||
};
|
||||
}
|
||||
|
||||
fn nested_mixed_multiple_deref_2() {
|
||||
let x = &Some(5);
|
||||
let y = &x;
|
||||
match y {
|
||||
Some(z) => {
|
||||
let _: &i32 = z;
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
fn new_mutable_reference() {
|
||||
let mut x = &mut Some(5);
|
||||
match &mut x {
|
||||
Some(y) => {
|
||||
*y = 5;
|
||||
},
|
||||
None => { },
|
||||
}
|
||||
|
||||
match &mut x {
|
||||
Some(y) => {
|
||||
println!("{}", *y);
|
||||
},
|
||||
None => {},
|
||||
}
|
||||
}
|
||||
|
||||
fn let_implicit_ref_binding() {
|
||||
struct Foo(i32);
|
||||
|
||||
// Note that these rules apply to any pattern matching
|
||||
// whether it be in a `match` or a `let`.
|
||||
// For example, `x` here is a `ref` binding:
|
||||
let Foo(x) = &Foo(3);
|
||||
let _: &i32 = x;
|
||||
}
|
||||
|
||||
fn explicit_mut_binding() {
|
||||
match &Some(5i32) {
|
||||
Some(mut n) => {
|
||||
n += 1;
|
||||
let _ = n;
|
||||
}
|
||||
None => {},
|
||||
};
|
||||
|
||||
match &mut Some(5i32) {
|
||||
Some(n) => {
|
||||
*n += 1;
|
||||
let _ = n;
|
||||
}
|
||||
None => {},
|
||||
};
|
||||
|
||||
match &mut &mut Some(5i32) {
|
||||
Some(n) => {
|
||||
let _: &mut i32 = n;
|
||||
}
|
||||
None => {},
|
||||
};
|
||||
}
|
||||
|
||||
fn tuple_mut_and_mut_mut() {
|
||||
match (Some(5i32), &Some(5i32)) {
|
||||
(Some(n), Some(m)) => {
|
||||
// `n` and `m` are bound as immutable references. Make new references from them to
|
||||
// assert that.
|
||||
let r = n;
|
||||
let _ = r;
|
||||
let q = m;
|
||||
let _ = q;
|
||||
|
||||
// Assert the types. Note that we use `n` and `m` here which would fail had they been
|
||||
// moved due to the assignments above.
|
||||
let _: i32 = n;
|
||||
let _: &i32 = m;
|
||||
}
|
||||
(_, _) => {},
|
||||
};
|
||||
|
||||
match (&Some(5i32), &&Some(5i32)) {
|
||||
(Some(n), Some(m)) => {
|
||||
let _: &i32 = n;
|
||||
let _: &i32 = m;
|
||||
}
|
||||
(_, _) => {},
|
||||
};
|
||||
|
||||
match &mut &mut (Some(5i32), Some(5i32)) {
|
||||
(Some(n), Some(m)) => {
|
||||
// Dereferenced through &mut &mut, so a mutable binding results.
|
||||
let _: &mut i32 = n;
|
||||
let _: &mut i32 = m;
|
||||
}
|
||||
(_, _) => {},
|
||||
};
|
||||
|
||||
match (&mut Some(5i32), &mut &mut Some(5i32)) {
|
||||
(Some(n), Some(m)) => {
|
||||
let _: &mut i32 = n;
|
||||
let _: &mut i32 = m;
|
||||
}
|
||||
(_, _) => {},
|
||||
};
|
||||
}
|
||||
|
||||
fn min_mir_embedded_type() {
|
||||
// The reduced invocation that an ICE was diagnosed with (was consuming
|
||||
// adjustments in wrong order).
|
||||
match (0u8, &&Some(5i32)) {
|
||||
(_, Some(m)) => {
|
||||
let _: &i32 = m;
|
||||
}
|
||||
(_, _) => {},
|
||||
};
|
||||
}
|
||||
|
||||
fn no_autoderef() {
|
||||
// Binding.
|
||||
let x = &3;
|
||||
println!("{}", *x);
|
||||
|
||||
// Wildcard.
|
||||
let _ = &3;
|
||||
|
||||
// Constant of generic type (string)
|
||||
const Y: &'static str = "foo";
|
||||
assert_eq!(0, match "foo" {
|
||||
Y => 0,
|
||||
_ => 1,
|
||||
});
|
||||
|
||||
// Reference pattern.
|
||||
let &x = &3;
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let r: &Option<i32> = &Some(3);
|
||||
let b = &4i32;
|
||||
|
||||
none_or_wildcard(r, b);
|
||||
some_or_wildcard(r, b);
|
||||
some_or_ref_none(r, b);
|
||||
ref_some_or_none(r, b);
|
||||
|
||||
some_or_self(r);
|
||||
multiple_deref(&&&&r);
|
||||
match_with_or();
|
||||
|
||||
nested_mixed();
|
||||
nested_mixed_multiple_deref_1();
|
||||
nested_mixed_multiple_deref_2();
|
||||
|
||||
new_mutable_reference();
|
||||
explicit_mut_binding();
|
||||
tuple_mut_and_mut_mut();
|
||||
min_mir_embedded_type();
|
||||
|
||||
let_implicit_ref_binding();
|
||||
|
||||
no_autoderef();
|
||||
}
|
44
src/test/run-pass/rfc-2005-default-binding-mode/lit.rs
Normal file
44
src/test/run-pass/rfc-2005-default-binding-mode/lit.rs
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(match_default_bindings)]
|
||||
|
||||
fn with_u8() {
|
||||
let s = 5u8;
|
||||
let r = match &s {
|
||||
4 => false,
|
||||
5 => true,
|
||||
_ => false,
|
||||
};
|
||||
assert!(r);
|
||||
}
|
||||
|
||||
// A string literal isn't mistaken for a non-ref pattern (in which case we'd
|
||||
// deref `s` and mess things up).
|
||||
fn with_str() {
|
||||
let s: &'static str = "abc";
|
||||
match s {
|
||||
"abc" => true,
|
||||
_ => panic!(),
|
||||
};
|
||||
}
|
||||
|
||||
// Ditto with byte strings.
|
||||
fn with_bytes() {
|
||||
let s: &'static [u8] = b"abc";
|
||||
match s {
|
||||
b"abc" => true,
|
||||
_ => panic!(),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
with_str();
|
||||
}
|
20
src/test/run-pass/rfc-2005-default-binding-mode/range.rs
Normal file
20
src/test/run-pass/rfc-2005-default-binding-mode/range.rs
Normal file
@ -0,0 +1,20 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(match_default_bindings)]
|
||||
|
||||
pub fn main() {
|
||||
let i = 5;
|
||||
match &&&&i {
|
||||
1 ... 3 => panic!(),
|
||||
3 ... 8 => {},
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(match_default_bindings)]
|
||||
|
||||
fn foo<'a, 'b>(x: &'a &'b Option<u32>) -> &'a u32 {
|
||||
let x: &'a &'a Option<u32> = x;
|
||||
match x {
|
||||
Some(r) => {
|
||||
let _: &u32 = r;
|
||||
r
|
||||
},
|
||||
&None => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let x = Some(5);
|
||||
foo(&&x);
|
||||
}
|
36
src/test/run-pass/rfc-2005-default-binding-mode/slice.rs
Normal file
36
src/test/run-pass/rfc-2005-default-binding-mode/slice.rs
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(slice_patterns)]
|
||||
#![feature(match_default_bindings)]
|
||||
|
||||
fn slice_pat() {
|
||||
let sl: &[u8] = b"foo";
|
||||
|
||||
match sl {
|
||||
[first, remainder..] => {
|
||||
let _: &u8 = first;
|
||||
assert_eq!(first, &b'f');
|
||||
assert_eq!(remainder, b"oo");
|
||||
}
|
||||
[] => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn slice_pat_omission() {
|
||||
match &[0, 1, 2] {
|
||||
[..] => {}
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
slice_pat();
|
||||
slice_pat_omission();
|
||||
}
|
33
src/test/run-pass/rfc-2005-default-binding-mode/struct.rs
Normal file
33
src/test/run-pass/rfc-2005-default-binding-mode/struct.rs
Normal file
@ -0,0 +1,33 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(match_default_bindings)]
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
struct Foo {
|
||||
x: u8,
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let mut foo = Foo {
|
||||
x: 1,
|
||||
};
|
||||
|
||||
match &mut foo {
|
||||
Foo{x: n} => {
|
||||
*n += 1;
|
||||
},
|
||||
};
|
||||
|
||||
assert_eq!(foo, Foo{x: 2});
|
||||
|
||||
let Foo{x: n} = &foo;
|
||||
assert_eq!(*n, 2);
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(match_default_bindings)]
|
||||
|
||||
enum Foo {
|
||||
Bar(Option<i8>, (), (), Vec<i32>),
|
||||
Baz,
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let foo = Foo::Bar(Some(1), (), (), vec![2, 3]);
|
||||
|
||||
match &foo {
|
||||
Foo::Baz => panic!(),
|
||||
Foo::Bar(None, ..) => panic!(),
|
||||
Foo::Bar(Some(n), .., v) => {
|
||||
assert_eq!((*v).len(), 2);
|
||||
assert_eq!(*n, 1);
|
||||
}
|
||||
}
|
||||
}
|
23
src/test/run-pass/rfc-2005-default-binding-mode/tuple.rs
Normal file
23
src/test/run-pass/rfc-2005-default-binding-mode/tuple.rs
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(match_default_bindings)]
|
||||
|
||||
pub fn main() {
|
||||
let foo = (Some(1), (), (), vec![2, 3]);
|
||||
|
||||
match &foo {
|
||||
(Some(n), .., v) => {
|
||||
assert_eq!((*v).len(), 2);
|
||||
assert_eq!(*n, 1);
|
||||
}
|
||||
(None, (), (), ..) => panic!(),
|
||||
}
|
||||
}
|
20
src/test/ui/const-expr-addr-operator.rs
Normal file
20
src/test/ui/const-expr-addr-operator.rs
Normal file
@ -0,0 +1,20 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Encountered while testing #44614.
|
||||
|
||||
pub fn main() {
|
||||
// Constant of generic type (int)
|
||||
const X: &'static u32 = &22;
|
||||
assert_eq!(0, match &22 {
|
||||
X => 0,
|
||||
_ => 1,
|
||||
});
|
||||
}
|
14
src/test/ui/const-expr-addr-operator.stderr
Normal file
14
src/test/ui/const-expr-addr-operator.stderr
Normal file
@ -0,0 +1,14 @@
|
||||
error[E0080]: constant evaluation error
|
||||
--> $DIR/const-expr-addr-operator.rs:15:29
|
||||
|
|
||||
15 | const X: &'static u32 = &22;
|
||||
| ^^^ unimplemented constant expression: address operator
|
||||
|
|
||||
note: for pattern here
|
||||
--> $DIR/const-expr-addr-operator.rs:17:9
|
||||
|
|
||||
17 | X => 0,
|
||||
| ^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -25,6 +25,8 @@ fn qux(foo: &Foo) {
|
||||
fn zar(&foo: &Foo) {
|
||||
}
|
||||
|
||||
// The somewhat unexpected help message in this case is courtesy of
|
||||
// match_default_bindings.
|
||||
fn agh(&&bar: &u32) {
|
||||
}
|
||||
|
||||
|
@ -9,27 +9,28 @@ error[E0308]: mismatched types
|
||||
= help: did you mean `foo: &Foo`?
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-38371.rs:28:9
|
||||
--> $DIR/issue-38371.rs:30:9
|
||||
|
|
||||
28 | fn agh(&&bar: &u32) {
|
||||
30 | fn agh(&&bar: &u32) {
|
||||
| ^^^^ expected u32, found reference
|
||||
|
|
||||
= note: expected type `u32`
|
||||
found type `&_`
|
||||
= help: did you mean `bar: &u32`?
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-38371.rs:31:8
|
||||
--> $DIR/issue-38371.rs:33:8
|
||||
|
|
||||
31 | fn bgh(&&bar: u32) {
|
||||
33 | fn bgh(&&bar: u32) {
|
||||
| ^^^^^ expected u32, found reference
|
||||
|
|
||||
= note: expected type `u32`
|
||||
found type `&_`
|
||||
|
||||
error[E0529]: expected an array or slice, found `u32`
|
||||
--> $DIR/issue-38371.rs:34:9
|
||||
--> $DIR/issue-38371.rs:36:9
|
||||
|
|
||||
34 | fn ugh(&[bar]: &u32) {
|
||||
36 | fn ugh(&[bar]: &u32) {
|
||||
| ^^^^^ pattern cannot match with input type `u32`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
29
src/test/ui/rfc-2005-default-binding-mode/const.rs
Normal file
29
src/test/ui/rfc-2005-default-binding-mode/const.rs
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// FIXME(tschottdorf): this test should pass.
|
||||
|
||||
#![feature(match_default_bindings)]
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
struct Foo {
|
||||
bar: i32,
|
||||
}
|
||||
|
||||
const FOO: Foo = Foo{bar: 5};
|
||||
|
||||
fn main() {
|
||||
let f = Foo{bar:6};
|
||||
|
||||
match &f {
|
||||
FOO => {},
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
11
src/test/ui/rfc-2005-default-binding-mode/const.stderr
Normal file
11
src/test/ui/rfc-2005-default-binding-mode/const.stderr
Normal file
@ -0,0 +1,11 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/const.rs:26:9
|
||||
|
|
||||
26 | FOO => {},
|
||||
| ^^^ expected &Foo, found struct `Foo`
|
||||
|
|
||||
= note: expected type `&Foo`
|
||||
found type `Foo`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
34
src/test/ui/rfc-2005-default-binding-mode/enum.rs
Normal file
34
src/test/ui/rfc-2005-default-binding-mode/enum.rs
Normal file
@ -0,0 +1,34 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(match_default_bindings)]
|
||||
|
||||
enum Wrapper {
|
||||
Wrap(i32),
|
||||
}
|
||||
|
||||
use Wrapper::Wrap;
|
||||
|
||||
pub fn main() {
|
||||
let Wrap(x) = &Wrap(3);
|
||||
*x += 1;
|
||||
|
||||
|
||||
if let Some(x) = &Some(3) {
|
||||
*x += 1;
|
||||
} else {
|
||||
panic!();
|
||||
}
|
||||
|
||||
while let Some(x) = &Some(3) {
|
||||
*x += 1;
|
||||
break;
|
||||
}
|
||||
}
|
26
src/test/ui/rfc-2005-default-binding-mode/enum.stderr
Normal file
26
src/test/ui/rfc-2005-default-binding-mode/enum.stderr
Normal file
@ -0,0 +1,26 @@
|
||||
error[E0594]: cannot assign to immutable borrowed content `*x`
|
||||
--> $DIR/enum.rs:21:5
|
||||
|
|
||||
20 | let Wrap(x) = &Wrap(3);
|
||||
| - consider changing this to `x`
|
||||
21 | *x += 1;
|
||||
| ^^^^^^^ cannot borrow as mutable
|
||||
|
||||
error[E0594]: cannot assign to immutable borrowed content `*x`
|
||||
--> $DIR/enum.rs:25:9
|
||||
|
|
||||
24 | if let Some(x) = &Some(3) {
|
||||
| - consider changing this to `x`
|
||||
25 | *x += 1;
|
||||
| ^^^^^^^ cannot borrow as mutable
|
||||
|
||||
error[E0594]: cannot assign to immutable borrowed content `*x`
|
||||
--> $DIR/enum.rs:31:9
|
||||
|
|
||||
30 | while let Some(x) = &Some(3) {
|
||||
| - consider changing this to `x`
|
||||
31 | *x += 1;
|
||||
| ^^^^^^^ cannot borrow as mutable
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
40
src/test/ui/rfc-2005-default-binding-mode/explicit-mut.rs
Normal file
40
src/test/ui/rfc-2005-default-binding-mode/explicit-mut.rs
Normal file
@ -0,0 +1,40 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(match_default_bindings)]
|
||||
|
||||
// Verify the binding mode shifts - only when no `&` are auto-dereferenced is the
|
||||
// final default binding mode mutable.
|
||||
|
||||
fn main() {
|
||||
match &&Some(5i32) {
|
||||
Some(n) => {
|
||||
*n += 1;
|
||||
let _ = n;
|
||||
}
|
||||
None => {},
|
||||
};
|
||||
|
||||
match &mut &Some(5i32) {
|
||||
Some(n) => {
|
||||
*n += 1;
|
||||
let _ = n;
|
||||
}
|
||||
None => {},
|
||||
};
|
||||
|
||||
match &&mut Some(5i32) {
|
||||
Some(n) => {
|
||||
*n += 1;
|
||||
let _ = n;
|
||||
}
|
||||
None => {},
|
||||
};
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
error[E0594]: cannot assign to immutable borrowed content `*n`
|
||||
--> $DIR/explicit-mut.rs:19:13
|
||||
|
|
||||
18 | Some(n) => {
|
||||
| - consider changing this to `n`
|
||||
19 | *n += 1;
|
||||
| ^^^^^^^ cannot borrow as mutable
|
||||
|
||||
error[E0594]: cannot assign to immutable borrowed content `*n`
|
||||
--> $DIR/explicit-mut.rs:27:13
|
||||
|
|
||||
26 | Some(n) => {
|
||||
| - consider changing this to `n`
|
||||
27 | *n += 1;
|
||||
| ^^^^^^^ cannot borrow as mutable
|
||||
|
||||
error[E0594]: cannot assign to immutable borrowed content `*n`
|
||||
--> $DIR/explicit-mut.rs:35:13
|
||||
|
|
||||
34 | Some(n) => {
|
||||
| - consider changing this to `n`
|
||||
35 | *n += 1;
|
||||
| ^^^^^^^ cannot borrow as mutable
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
20
src/test/ui/rfc-2005-default-binding-mode/for.rs
Normal file
20
src/test/ui/rfc-2005-default-binding-mode/for.rs
Normal file
@ -0,0 +1,20 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(match_default_bindings)]
|
||||
|
||||
struct Foo {}
|
||||
|
||||
pub fn main() {
|
||||
let mut tups = vec![(Foo{}, Foo{})];
|
||||
// The below desugars to &(ref n, mut m).
|
||||
for (n, mut m) in &tups {
|
||||
}
|
||||
}
|
10
src/test/ui/rfc-2005-default-binding-mode/for.stderr
Normal file
10
src/test/ui/rfc-2005-default-binding-mode/for.stderr
Normal file
@ -0,0 +1,10 @@
|
||||
error[E0009]: cannot bind by-move and by-ref in the same pattern
|
||||
--> $DIR/for.rs:18:13
|
||||
|
|
||||
18 | for (n, mut m) in &tups {
|
||||
| - ^^^^^ by-move pattern here
|
||||
| |
|
||||
| both by-ref and by-move used
|
||||
|
||||
error: aborting due to previous error
|
||||
|
21
src/test/ui/rfc-2005-default-binding-mode/issue-44912-or.rs
Normal file
21
src/test/ui/rfc-2005-default-binding-mode/issue-44912-or.rs
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(match_default_bindings)]
|
||||
|
||||
// FIXME(tschottdorf): This should compile. See #44912.
|
||||
|
||||
pub fn main() {
|
||||
let x = &Some((3, 3));
|
||||
let _: &i32 = match x {
|
||||
Some((x, 3)) | &Some((ref x, 5)) => x,
|
||||
_ => &5i32,
|
||||
};
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
error[E0409]: variable `x` is bound in inconsistent ways within the same match arm
|
||||
--> $DIR/issue-44912-or.rs:18:35
|
||||
|
|
||||
18 | Some((x, 3)) | &Some((ref x, 5)) => x,
|
||||
| - first binding ^ bound in different ways
|
||||
|
||||
error: aborting due to previous error
|
||||
|
36
src/test/ui/rfc-2005-default-binding-mode/lit.rs
Normal file
36
src/test/ui/rfc-2005-default-binding-mode/lit.rs
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(match_default_bindings)]
|
||||
|
||||
// FIXME(tschottdorf): we want these to compile, but they don't.
|
||||
|
||||
fn with_str() {
|
||||
let s: &'static str = "abc";
|
||||
|
||||
match &s {
|
||||
"abc" => true,
|
||||
_ => panic!(),
|
||||
};
|
||||
}
|
||||
|
||||
fn with_bytes() {
|
||||
let s: &'static [u8] = b"abc";
|
||||
|
||||
match &s {
|
||||
b"abc" => true,
|
||||
_ => panic!(),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
with_str();
|
||||
with_bytes();
|
||||
}
|
20
src/test/ui/rfc-2005-default-binding-mode/lit.stderr
Normal file
20
src/test/ui/rfc-2005-default-binding-mode/lit.stderr
Normal file
@ -0,0 +1,20 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/lit.rs:19:13
|
||||
|
|
||||
19 | "abc" => true,
|
||||
| ^^^^^ expected &str, found str
|
||||
|
|
||||
= note: expected type `&&str`
|
||||
found type `&'static str`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/lit.rs:28:9
|
||||
|
|
||||
28 | b"abc" => true,
|
||||
| ^^^^^^ expected &[u8], found array of 3 elements
|
||||
|
|
||||
= note: expected type `&&[u8]`
|
||||
found type `&'static [u8; 3]`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
21
src/test/ui/rfc-2005-default-binding-mode/no-double-error.rs
Normal file
21
src/test/ui/rfc-2005-default-binding-mode/no-double-error.rs
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Without caching type lookups in FnCtxt.resolve_ty_and_def_ufcs
|
||||
// the error below would be reported twice (once when checking
|
||||
// for a non-ref pattern, once when processing the pattern).
|
||||
|
||||
fn main() {
|
||||
let foo = 22;
|
||||
match foo {
|
||||
u32::XXX => { }
|
||||
_ => { }
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
error[E0599]: no associated item named `XXX` found for type `u32` in the current scope
|
||||
--> $DIR/no-double-error.rs:18:9
|
||||
|
|
||||
18 | u32::XXX => { }
|
||||
| ^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
20
src/test/ui/rfc-2005-default-binding-mode/slice.rs
Normal file
20
src/test/ui/rfc-2005-default-binding-mode/slice.rs
Normal file
@ -0,0 +1,20 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(slice_patterns)]
|
||||
#![feature(match_default_bindings)]
|
||||
|
||||
pub fn main() {
|
||||
let sl: &[u8] = b"foo";
|
||||
|
||||
match sl {
|
||||
[first, remainder..] => {},
|
||||
};
|
||||
}
|
8
src/test/ui/rfc-2005-default-binding-mode/slice.stderr
Normal file
8
src/test/ui/rfc-2005-default-binding-mode/slice.stderr
Normal file
@ -0,0 +1,8 @@
|
||||
error[E0004]: non-exhaustive patterns: `&[]` not covered
|
||||
--> $DIR/slice.rs:17:11
|
||||
|
|
||||
17 | match sl {
|
||||
| ^^ pattern `&[]` not covered
|
||||
|
||||
error: aborting due to previous error
|
||||
|
Loading…
x
Reference in New Issue
Block a user