diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index fb0cdab0b6a0f..045061228490e 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -333,9 +333,24 @@ pub struct TypeckTables<'tcx> { adjustments: ItemLocalMap>>, - // 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, + /// 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![&&i32, &i32]`. Empty vectors are not stored. + /// + /// See: + /// https://github.com/rust-lang/rfcs/blob/master/text/2005-match-ergonomics.md#definitions + pat_adjustments: ItemLocalMap>>, + /// Borrows pub upvar_capture_map: ty::UpvarCaptureMap<'tcx>, @@ -390,6 +405,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(), @@ -570,6 +586,21 @@ impl<'tcx> TypeckTables<'tcx> { } } + pub fn pat_adjustments(&self) -> LocalTableInContext>> { + LocalTableInContext { + local_id_root: self.local_id_root, + data: &self.pat_adjustments, + } + } + + pub fn pat_adjustments_mut(&mut self) + -> LocalTableInContextMut>> { + 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] } @@ -695,6 +726,7 @@ impl<'a, 'gcx, 'tcx> HashStable> for Typeck ref node_substs, ref adjustments, ref pat_binding_modes, + ref pat_adjustments, ref upvar_capture_map, ref closure_tys, ref closure_kinds, @@ -716,6 +748,7 @@ impl<'a, 'gcx, 'tcx> HashStable> for Typeck ich::hash_stable_itemlocalmap(hcx, hasher, node_substs); ich::hash_stable_itemlocalmap(hcx, hasher, adjustments); ich::hash_stable_itemlocalmap(hcx, hasher, pat_binding_modes); + ich::hash_stable_itemlocalmap(hcx, hasher, pat_adjustments); ich::hash_stable_hashmap(hcx, hasher, upvar_capture_map, |hcx, up_var_id| { let ty::UpvarId { var_id, diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs index a87fa0c2746a3..6adee1d19e43f 100644 --- a/src/librustc_const_eval/pattern.rs +++ b/src/librustc_const_eval/pattern.rs @@ -301,6 +301,24 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } pub fn lower_pattern(&mut self, pat: &'tcx hir::Pat) -> Pattern<'tcx> { + let unadjusted_pat = self.lower_pattern_unadjusted(pat); + self.tables + .pat_adjustments() + .get(pat.hir_id) + .unwrap_or(&vec![]) + .iter() + .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 }), + } + }, + ) + } + + pub 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 { diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index cbf58209d056a..2dbfec1c77a9a 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -27,18 +27,92 @@ 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); + pub fn check_pat(&self, pat: &'gcx hir::Pat, expected: Ty<'tcx>, def_bm: ty::BindingMode) { + self.check_pat_arg(pat, expected, def_bm, 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) { + #[allow(unused_assignments)] + pub fn check_pat_arg(&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(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::Lit(_) | // FIXME(tschottdorf): causes lots of errors + PatKind::Range(..) | + PatKind::Slice(..) => true, + PatKind::Path(..) => { + // FIXME(tschottdorf): to handle const refs, should be enough to + // check whether pat_ty starts with a TypeVariant::TyRef and if + // so, not apply const binding modes. + true + } + PatKind::Wild | + PatKind::Binding(..) | + PatKind::Ref(..) => false, + _ => false, + }; + if is_non_ref_pat { + debug!("is_non_ref_pat"); + 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, increment a counter and update the binding mode. + // See the examples in compile-pass/FIXME(tschottdorf). + 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!("is a ref"); + // Preserve the reference type. We'll need it later during HAIR lowering. + pat_adjustments.push(exp_ty); + + // FIXME(tschottdorf): is it OK to keep the same flags? + 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 { + 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 => { @@ -114,10 +188,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 +230,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } if let Some(ref p) = *sub { - self.check_pat(&p, expected); + self.check_pat(&p, expected, def_bm); } 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 +263,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(elem, &element_tys[i], def_bm); } pat_ty } @@ -201,10 +276,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(&inner, inner_ty, def_bm); uniq_ty } else { - self.check_pat(&inner, tcx.types.err); + self.check_pat(&inner, tcx.types.err, def_bm); tcx.types.err } } @@ -253,10 +328,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }; - self.check_pat(&inner, inner_ty); + self.check_pat(&inner, inner_ty, def_bm); rptr_ty } else { - self.check_pat(&inner, tcx.types.err); + self.check_pat(&inner, tcx.types.err, def_bm); tcx.types.err } } @@ -314,13 +389,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; for elt in before { - self.check_pat(&elt, inner_ty); + self.check_pat(&elt, inner_ty, def_bm); } if let Some(ref slice) = *slice { - self.check_pat(&slice, slice_ty); + self.check_pat(&slice, slice_ty, def_bm); } for elt in after { - self.check_pat(&elt, inner_ty); + self.check_pat(&elt, inner_ty, def_bm); } expected_ty } @@ -495,7 +570,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(&p, discrim_ty, + ty::BindingMode::BindByValue(hir::Mutability::MutImmutable)); all_pats_diverge &= self.diverges.get(); } @@ -576,14 +652,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { qpath: &hir::QPath, fields: &'gcx [Spanned], 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(&field.node.pat, self.tcx.types.err, def_bm); } return self.tcx.types.err; }; @@ -592,7 +669,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 +714,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { qpath: &hir::QPath, subpats: &'gcx [P], ddpos: Option, - 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(&pat, tcx.types.err, def_bm); } }; let report_unexpected_def = |def: Def| { @@ -678,6 +756,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 +768,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(&subpat, field_ty, def_bm); self.tcx.check_stability(variant.fields[i].did, pat.id, subpat.span); } @@ -715,7 +794,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { span: Span, variant: &'tcx ty::VariantDef, fields: &'gcx [Spanned], - etc: bool) { + etc: bool, + def_bm: ty::BindingMode) { let tcx = self.tcx; let (substs, kind_name) = match adt_ty.sty { @@ -772,7 +852,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }; - self.check_pat(&field.pat, field_ty); + self.check_pat(&field.pat, field_ty, def_bm); } // Report an error if incorrect number of the fields were specified. diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index ae2430990ba57..f092852244015 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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_arg(&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 @@ -4159,7 +4160,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - self.check_pat(&local.pat, t); + self.check_pat(&local.pat, t, ty::BindingMode::BindByValue(hir::Mutability::MutImmutable)); let pat_ty = self.node_ty(local.pat.hir_id); if pat_ty.references_error() { self.write_ty(local.hir_id, pat_ty); diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 7810d9049e10e..622e4be0a1757 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -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); } @@ -359,6 +361,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() { diff --git a/src/test/compile-fail/match-defbm-explicit-mut.rs b/src/test/compile-fail/match-defbm-explicit-mut.rs new file mode 100644 index 0000000000000..a487166572c80 --- /dev/null +++ b/src/test/compile-fail/match-defbm-explicit-mut.rs @@ -0,0 +1,38 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// 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; //~ ERROR cannot assign to immutable borrowed content `*n` [E0594] + let _ = n; + } + None => {}, + }; + + match &mut &Some(5i32) { + Some(n) => { + *n += 1; //~ ERROR cannot assign to immutable borrowed content `*n` [E0594] + let _ = n; + } + None => {}, + }; + + match &&mut Some(5i32) { + Some(n) => { + *n += 1; //~ ERROR cannot assign to immutable borrowed content `*n` [E0594] + let _ = n; + } + None => {}, + }; +} diff --git a/src/test/run-pass/issue-18352.rs b/src/test/run-pass/issue-18352.rs index cce6ba407a663..2c0825c638385 100644 --- a/src/test/run-pass/issue-18352.rs +++ b/src/test/run-pass/issue-18352.rs @@ -13,7 +13,7 @@ const X: &'static str = "12345"; fn test(s: String) -> bool { match &*s { - X => true, + X => true, // FIXME(tschottdorf): must not treat X as a non-ref pattern _ => false } } diff --git a/src/test/run-pass/match-defbm-option.rs b/src/test/run-pass/match-defbm-option.rs new file mode 100644 index 0000000000000..5dffc43cf472d --- /dev/null +++ b/src/test/run-pass/match-defbm-option.rs @@ -0,0 +1,218 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn some_or_wildcard(r: &Option, b: &i32) { + let _: &i32 = match r { + Some(a) => a, + _ => b, + }; +} + +fn none_or_wildcard(r: &Option, b: &i32) { + let _: &i32 = match r { + None => b, + _ => b, + }; +} + +fn some_or_ref_none(r: &Option, b: &i32) { + let _: &i32 = match r { + Some(a) => a, + &None => b, + }; +} + +fn ref_some_or_none(r: &Option, b: &i32) { + let _: &i32 = match r { + &Some(ref a) => a, + None => b, + }; +} + +fn some_or_self(r: &Option) { + let _: &Option = match r { + Some(n) => { + let _: &i32 = n; + r + }, + x => x, + }; +} + +fn multiple_deref(r: &&&&&Option) { + let _: i32 = match r { + Some(a) => *a, + None => 5, + }; +} + +fn match_with_or() { + let x = &Some((3, 3)); + let _: &i32 = match x { + // Here, each of the patterns are treated independently + // FIXME(tschottdorf): + // Some((x, 3)) | &Some((ref x, 5)) => x, + // - first binding ^ bound in different ways + /*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 => { }, + } +} + +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_ice() { + 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)) => { + let _: &mut i32 = n; + let _: &mut i32 = m; + } + (_, _) => {}, + }; + + + // FIXME(tschottdorf): + // + // broken MIR in NodeId(4) ((_2.1: &mut std::option::Option)): bad field access (&mut &mut + // std::option::Option: &mut std::option::Option): Sorts(ExpectedFound { expected: + // std::option::Option, found: &mut std::option::Option }) + + // match (&mut Some(5i32), &mut &mut Some(5i32)) { + // (Some(n), Some(m)) => { + // let _: &mut i32 = n; + // let _: &mut i32 = m; + // } + // (_, _) => {}, + // }; + + // Same problem without `mut`: + + // match (&Some(5i32), &&Some(5i32)) { + // (Some(n), Some(m)) => { + // let _: &i32 = n; + // let _: &i32 = m; + // } + // (_, _) => {}, + // }; +} + +pub fn main() { + let r: &Option = &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_ice(); + + let_implicit_ref_binding(); +} diff --git a/src/test/run-pass/match-defbm-ref-region.rs b/src/test/run-pass/match-defbm-ref-region.rs new file mode 100644 index 0000000000000..3c3d4bf718513 --- /dev/null +++ b/src/test/run-pass/match-defbm-ref-region.rs @@ -0,0 +1,49 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// FIXME(tschottdorf): Uncommenting `// r` below, get: +// +// error[E0597]: `(x:std::prelude::v1::Some).0` does not live long enough +// --> /Users/tschottdorf/rust/binding-modes/src/test/run-pass/match-defbm-ref-region.rs:14:14 +// | +// 14 | Some(r) => r, +// | ^ does not live long enough +// ... +// 17 | } +// | - borrowed value only lives until here +// | +// note: borrowed value must be valid for the lifetime 'a as defined on the function body at 11:1... +// --> /Users/tschottdorf/rust/binding-modes/src/test/run-pass/match-defbm-ref-region.rs:11:1 +// | +// 11 | / fn foo<'a, 'b>(x: &'a &'b Option) -> &'a u32 { +// 12 | | let x: &'a &'a Option = x; +// 13 | | match x { +// 14 | | Some(r) => r, +// 15 | | &None => panic!(), +// 16 | | } +// 17 | | } +// | |_^ + +fn foo<'a, 'b>(x: &'a &'b Option) -> &'a u32 { + let x: &'a &'a Option = x; + match x { + Some(r) => { + let _: &u32 = r; + &5 + // r + }, + &None => panic!(), + } +} + +pub fn main() { + let x = Some(5); + foo(&&x); +} diff --git a/src/test/ui/mismatched_types/closure-arg-count.stderr b/src/test/ui/mismatched_types/closure-arg-count.stderr index ca71154e872ee..8278ba4ba4bb7 100644 --- a/src/test/ui/mismatched_types/closure-arg-count.stderr +++ b/src/test/ui/mismatched_types/closure-arg-count.stderr @@ -18,9 +18,9 @@ error[E0308]: mismatched types --> $DIR/closure-arg-count.rs:14:24 | 14 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!()); - | ^^^^^^^^^^^^^^^ expected &{integer}, found tuple + | ^^^^^^^^^^^^^^^ expected integral variable, found tuple | - = note: expected type `&{integer}` + = note: expected type `{integer}` found type `(_, _)` error[E0593]: closure takes 1 argument but 2 arguments are required