From 9844777a508203b8faf8c09c3ec1a2023022da9b Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Fri, 20 Oct 2017 08:59:55 -0400 Subject: [PATCH] typeck: suggest use of match_default_bindings feature Fixes #45383. Updates #42640. --- src/librustc_typeck/check/_match.rs | 29 ++++++++++++++----- src/test/compile-fail/E0029.rs | 1 + .../feature-gate-match_default_bindings.rs | 3 +- src/test/compile-fail/issue-16338.rs | 3 +- src/test/compile-fail/issue-20261.rs | 3 +- .../keyword-false-as-identifier.rs | 2 +- .../keyword-self-as-identifier.rs | 2 +- .../keyword-super-as-identifier.rs | 2 +- .../keyword-true-as-identifier.rs | 2 +- src/test/compile-fail/match-range-fail.rs | 2 ++ src/test/compile-fail/match-vec-mismatch.rs | 2 +- src/test/compile-fail/pat-slice-old-style.rs | 5 ++-- .../mismatched_types/closure-arg-count.stderr | 14 +++++++-- .../suggestion.rs | 15 ++++++++++ .../suggestion.stderr | 10 +++++++ 15 files changed, 74 insertions(+), 21 deletions(-) create mode 100644 src/test/ui/rfc-2005-default-binding-mode/suggestion.rs create mode 100644 src/test/ui/rfc-2005-default-binding-mode/suggestion.stderr diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index ab8994bcae253..e25f7d796689d 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -23,6 +23,7 @@ use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::cmp; use syntax::ast; use syntax::codemap::Spanned; +use syntax::feature_gate; use syntax::ptr::P; use syntax_pos::Span; @@ -68,7 +69,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { PatKind::Binding(..) | PatKind::Ref(..) => false, }; - if is_non_ref_pat && tcx.sess.features.borrow().match_default_bindings { + if is_non_ref_pat { debug!("pattern is non reference pattern"); let mut exp_ty = self.resolve_type_vars_with_obligations(&expected); @@ -113,10 +114,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }; 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); + if tcx.sess.features.borrow().match_default_bindings { + debug!("default binding mode is now {:?}", def_bm); + self.inh.tables.borrow_mut() + .pat_adjustments_mut() + .insert(pat.hir_id, pat_adjustments); + } else { + let mut err = feature_gate::feature_err( + &tcx.sess.parse_sess, + "match_default_bindings", + pat.span, + feature_gate::GateIssue::Language, + "non-reference pattern used to match a reference", + ); + if let Ok(snippet) = tcx.sess.codemap().span_to_snippet(pat.span) { + err.span_suggestion(pat.span, "consider using", format!("&{}", &snippet)); + } + err.emit(); + } } } @@ -325,8 +340,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(mut err) = err { if is_arg { if let PatKind::Binding(..) = inner.node { - if let Ok(snippet) = self.sess().codemap() - .span_to_snippet(pat.span) + if let Ok(snippet) = tcx.sess.codemap() + .span_to_snippet(pat.span) { err.help(&format!("did you mean `{}: &{}`?", &snippet[1..], diff --git a/src/test/compile-fail/E0029.rs b/src/test/compile-fail/E0029.rs index ec84e2a3f8a36..e43290bb15416 100644 --- a/src/test/compile-fail/E0029.rs +++ b/src/test/compile-fail/E0029.rs @@ -17,6 +17,7 @@ fn main() { //~| NOTE ranges require char or numeric types //~| NOTE start type: &'static str //~| NOTE end type: &'static str + //~| ERROR non-reference pattern used to match a reference _ => {} } } diff --git a/src/test/compile-fail/feature-gate-match_default_bindings.rs b/src/test/compile-fail/feature-gate-match_default_bindings.rs index 2b3bf94eadce5..4ee2c1e2936a8 100644 --- a/src/test/compile-fail/feature-gate-match_default_bindings.rs +++ b/src/test/compile-fail/feature-gate-match_default_bindings.rs @@ -10,7 +10,8 @@ pub fn main() { match &Some(3) { - Some(n) => {}, //~ ERROR mismatched types [E0308] + Some(n) => {}, + //~^ ERROR non-reference pattern used to match a reference _ => panic!(), } } diff --git a/src/test/compile-fail/issue-16338.rs b/src/test/compile-fail/issue-16338.rs index a4517e60d66e1..6fdf8802e385e 100644 --- a/src/test/compile-fail/issue-16338.rs +++ b/src/test/compile-fail/issue-16338.rs @@ -16,7 +16,6 @@ struct Slice { fn main() { let Slice { data: data, len: len } = "foo"; //~^ ERROR mismatched types - //~| expected type `&str` //~| found type `Slice<_>` - //~| expected &str, found struct `Slice` + //~| ERROR non-reference pattern used to match a reference } diff --git a/src/test/compile-fail/issue-20261.rs b/src/test/compile-fail/issue-20261.rs index 7b5e61380f2ba..092aaa7695505 100644 --- a/src/test/compile-fail/issue-20261.rs +++ b/src/test/compile-fail/issue-20261.rs @@ -10,7 +10,8 @@ fn main() { // NB: this (almost) typechecks when default binding modes are enabled. - for (ref i,) in [].iter() { //~ ERROR mismatched types [E0308] + for (ref i,) in [].iter() { + //~^ ERROR non-reference pattern used to match a reference i.clone(); } } diff --git a/src/test/compile-fail/keyword-false-as-identifier.rs b/src/test/compile-fail/keyword-false-as-identifier.rs index e8af94f16b1b9..f246d6e75df8d 100644 --- a/src/test/compile-fail/keyword-false-as-identifier.rs +++ b/src/test/compile-fail/keyword-false-as-identifier.rs @@ -9,5 +9,5 @@ // except according to those terms. fn main() { - let false = "foo"; //~ error: mismatched types + let false = 22; //~ error: mismatched types } diff --git a/src/test/compile-fail/keyword-self-as-identifier.rs b/src/test/compile-fail/keyword-self-as-identifier.rs index f01aab92356dd..b50fc68bed6be 100644 --- a/src/test/compile-fail/keyword-self-as-identifier.rs +++ b/src/test/compile-fail/keyword-self-as-identifier.rs @@ -9,5 +9,5 @@ // except according to those terms. fn main() { - let Self = "foo"; //~ ERROR cannot find unit struct/variant or constant `Self` in this scope + let Self = 22; //~ ERROR cannot find unit struct/variant or constant `Self` in this scope } diff --git a/src/test/compile-fail/keyword-super-as-identifier.rs b/src/test/compile-fail/keyword-super-as-identifier.rs index 62649ba8a0fe1..54dac771f01ed 100644 --- a/src/test/compile-fail/keyword-super-as-identifier.rs +++ b/src/test/compile-fail/keyword-super-as-identifier.rs @@ -9,5 +9,5 @@ // except according to those terms. fn main() { - let super = "foo"; //~ ERROR failed to resolve. There are too many initial `super`s + let super = 22; //~ ERROR failed to resolve. There are too many initial `super`s } diff --git a/src/test/compile-fail/keyword-true-as-identifier.rs b/src/test/compile-fail/keyword-true-as-identifier.rs index 90414fa912dba..b09d09db560f5 100644 --- a/src/test/compile-fail/keyword-true-as-identifier.rs +++ b/src/test/compile-fail/keyword-true-as-identifier.rs @@ -9,5 +9,5 @@ // except according to those terms. fn main() { - let true = "foo"; //~ error: mismatched types + let true = 22; //~ error: mismatched types } diff --git a/src/test/compile-fail/match-range-fail.rs b/src/test/compile-fail/match-range-fail.rs index f89b3e39390d3..355ff6404cea7 100644 --- a/src/test/compile-fail/match-range-fail.rs +++ b/src/test/compile-fail/match-range-fail.rs @@ -15,6 +15,7 @@ fn main() { //~^^ ERROR only char and numeric types are allowed in range //~| start type: &'static str //~| end type: &'static str + //~| ERROR non-reference pattern used to match a reference match "wow" { 10 ... "what" => () @@ -22,6 +23,7 @@ fn main() { //~^^ ERROR only char and numeric types are allowed in range //~| start type: {integer} //~| end type: &'static str + //~| ERROR non-reference pattern used to match a reference match 5 { 'c' ... 100 => { } diff --git a/src/test/compile-fail/match-vec-mismatch.rs b/src/test/compile-fail/match-vec-mismatch.rs index d72ec8ba40868..fed68da006889 100644 --- a/src/test/compile-fail/match-vec-mismatch.rs +++ b/src/test/compile-fail/match-vec-mismatch.rs @@ -19,7 +19,7 @@ fn main() { // Note that this one works with default binding modes. match &[0, 1, 2] { - [..] => {} //~ ERROR expected an array or slice, found `&[{integer}; 3]` [E0529] + [..] => {} //~ ERROR non-reference pattern used to match a reference }; match &[0, 1, 2] { diff --git a/src/test/compile-fail/pat-slice-old-style.rs b/src/test/compile-fail/pat-slice-old-style.rs index 54028ffa63ffc..d49ce56ccf6e7 100644 --- a/src/test/compile-fail/pat-slice-old-style.rs +++ b/src/test/compile-fail/pat-slice-old-style.rs @@ -17,8 +17,9 @@ fn slice_pat(x: &[u8]) { // OLD! match x { [a, b..] => {}, - //~^ ERROR expected an array or slice, found `&[u8]` - //~| HELP the semantics of slice patterns changed recently; see issue #23121 + //~^ ERROR non-reference pattern used to match a reference + //~| HELP add #![feature(match_default_bindings)] to the crate attributes to enable + //~| HELP consider using _ => panic!(), } } diff --git a/src/test/ui/mismatched_types/closure-arg-count.stderr b/src/test/ui/mismatched_types/closure-arg-count.stderr index 9d4ac6305465a..ca06825d0ad8b 100644 --- a/src/test/ui/mismatched_types/closure-arg-count.stderr +++ b/src/test/ui/mismatched_types/closure-arg-count.stderr @@ -14,13 +14,21 @@ error[E0593]: closure is expected to take 2 arguments, but it takes 1 argument | | | expected closure that takes 2 arguments +error: non-reference pattern used to match a reference (see issue #42640) + --> $DIR/closure-arg-count.rs:17:24 + | +17 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!()); + | ^^^^^^^^^^^^^^^ help: consider using: `&(tuple, tuple2)` + | + = help: add #![feature(match_default_bindings)] to the crate attributes to enable + error[E0308]: mismatched types --> $DIR/closure-arg-count.rs:17:24 | 17 | [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 is expected to take 2 arguments, but it takes 1 argument @@ -65,5 +73,5 @@ error[E0593]: closure is expected to take a single 2-tuple as argument, but it t | | | expected closure that takes a single 2-tuple as argument -error: aborting due to 8 previous errors +error: aborting due to 9 previous errors diff --git a/src/test/ui/rfc-2005-default-binding-mode/suggestion.rs b/src/test/ui/rfc-2005-default-binding-mode/suggestion.rs new file mode 100644 index 0000000000000..52ff817dff488 --- /dev/null +++ b/src/test/ui/rfc-2005-default-binding-mode/suggestion.rs @@ -0,0 +1,15 @@ +// 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 main() { + if let Some(y) = &Some(22) { + println!("{}", y); + } +} diff --git a/src/test/ui/rfc-2005-default-binding-mode/suggestion.stderr b/src/test/ui/rfc-2005-default-binding-mode/suggestion.stderr new file mode 100644 index 0000000000000..0594f865f327e --- /dev/null +++ b/src/test/ui/rfc-2005-default-binding-mode/suggestion.stderr @@ -0,0 +1,10 @@ +error: non-reference pattern used to match a reference (see issue #42640) + --> $DIR/suggestion.rs:12:12 + | +12 | if let Some(y) = &Some(22) { + | ^^^^^^^ help: consider using: `&Some(y)` + | + = help: add #![feature(match_default_bindings)] to the crate attributes to enable + +error: aborting due to previous error +