Auto merge of #3772 - flip1995:ice-3719, r=Manishearth
Fix ICE #3719+#3718 in lint match_ref_pats Fixes #3719 This conveniently also fixes #3718 The ICE occurs when the match expression was a macro call, where the macro was defined in another file. Since we don't have the ability to reproduce this behavior with our UI tests (AFAIK), I couldn't add a test reproducing this ICE.. However, I added a test which is related to the ICE, to show the new behavior of the lint. I tested it with the mscheme repo locally and the ICE didn't happen anymore. r? @matthiaskrgr
This commit is contained in:
commit
1ac6f4e9ae
4 changed files with 91 additions and 37 deletions
|
|
@ -570,13 +570,15 @@ fn check_match_ref_pats(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr:
|
|||
if has_only_ref_pats(arms) {
|
||||
let mut suggs = Vec::new();
|
||||
let (title, msg) = if let ExprKind::AddrOf(Mutability::MutImmutable, ref inner) = ex.node {
|
||||
suggs.push((ex.span, Sugg::hir(cx, inner, "..").to_string()));
|
||||
let span = ex.span.source_callsite();
|
||||
suggs.push((span, Sugg::hir_with_macro_callsite(cx, inner, "..").to_string()));
|
||||
(
|
||||
"you don't need to add `&` to both the expression and the patterns",
|
||||
"try",
|
||||
)
|
||||
} else {
|
||||
suggs.push((ex.span, Sugg::hir(cx, ex, "..").deref().to_string()));
|
||||
let span = ex.span.source_callsite();
|
||||
suggs.push((span, Sugg::hir_with_macro_callsite(cx, ex, "..").deref().to_string()));
|
||||
(
|
||||
"you don't need to add `&` to all patterns",
|
||||
"instead of prefixing all patterns with `&`, you can dereference the expression",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
//! Contains utility functions to generate suggestions.
|
||||
#![deny(clippy::missing_docs_in_private_items)]
|
||||
|
||||
use crate::utils::{higher, in_macro, snippet, snippet_opt};
|
||||
use crate::utils::{higher, in_macro, snippet, snippet_opt, snippet_with_macro_callsite};
|
||||
use matches::matches;
|
||||
use rustc::hir;
|
||||
use rustc::lint::{EarlyContext, LateContext, LintContext};
|
||||
|
|
@ -46,38 +46,7 @@ impl<'a> Sugg<'a> {
|
|||
pub fn hir_opt(cx: &LateContext<'_, '_>, expr: &hir::Expr) -> Option<Self> {
|
||||
snippet_opt(cx, expr.span).map(|snippet| {
|
||||
let snippet = Cow::Owned(snippet);
|
||||
match expr.node {
|
||||
hir::ExprKind::AddrOf(..)
|
||||
| hir::ExprKind::Box(..)
|
||||
| hir::ExprKind::Closure(.., _)
|
||||
| hir::ExprKind::If(..)
|
||||
| hir::ExprKind::Unary(..)
|
||||
| hir::ExprKind::Match(..) => Sugg::MaybeParen(snippet),
|
||||
hir::ExprKind::Continue(..)
|
||||
| hir::ExprKind::Yield(..)
|
||||
| hir::ExprKind::Array(..)
|
||||
| hir::ExprKind::Block(..)
|
||||
| hir::ExprKind::Break(..)
|
||||
| hir::ExprKind::Call(..)
|
||||
| hir::ExprKind::Field(..)
|
||||
| hir::ExprKind::Index(..)
|
||||
| hir::ExprKind::InlineAsm(..)
|
||||
| hir::ExprKind::Lit(..)
|
||||
| hir::ExprKind::Loop(..)
|
||||
| hir::ExprKind::MethodCall(..)
|
||||
| hir::ExprKind::Path(..)
|
||||
| hir::ExprKind::Repeat(..)
|
||||
| hir::ExprKind::Ret(..)
|
||||
| hir::ExprKind::Struct(..)
|
||||
| hir::ExprKind::Tup(..)
|
||||
| hir::ExprKind::While(..)
|
||||
| hir::ExprKind::Err => Sugg::NonParen(snippet),
|
||||
hir::ExprKind::Assign(..) => Sugg::BinOp(AssocOp::Assign, snippet),
|
||||
hir::ExprKind::AssignOp(op, ..) => Sugg::BinOp(hirbinop2assignop(op), snippet),
|
||||
hir::ExprKind::Binary(op, ..) => Sugg::BinOp(AssocOp::from_ast_binop(higher::binop(op.node)), snippet),
|
||||
hir::ExprKind::Cast(..) => Sugg::BinOp(AssocOp::As, snippet),
|
||||
hir::ExprKind::Type(..) => Sugg::BinOp(AssocOp::Colon, snippet),
|
||||
}
|
||||
Self::hir_from_snippet(expr, snippet)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -111,6 +80,50 @@ impl<'a> Sugg<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
/// Same as `hir`, but will use the pre expansion span if the `expr` was in a macro.
|
||||
pub fn hir_with_macro_callsite(cx: &LateContext<'_, '_>, expr: &hir::Expr, default: &'a str) -> Self {
|
||||
let snippet = snippet_with_macro_callsite(cx, expr.span, default);
|
||||
|
||||
Self::hir_from_snippet(expr, snippet)
|
||||
}
|
||||
|
||||
/// Generate a suggestion for an expression with the given snippet. This is used by the `hir_*`
|
||||
/// function variants of `Sugg`, since these use different snippet functions.
|
||||
fn hir_from_snippet(expr: &hir::Expr, snippet: Cow<'a, str>) -> Self {
|
||||
match expr.node {
|
||||
hir::ExprKind::AddrOf(..)
|
||||
| hir::ExprKind::Box(..)
|
||||
| hir::ExprKind::Closure(.., _)
|
||||
| hir::ExprKind::If(..)
|
||||
| hir::ExprKind::Unary(..)
|
||||
| hir::ExprKind::Match(..) => Sugg::MaybeParen(snippet),
|
||||
hir::ExprKind::Continue(..)
|
||||
| hir::ExprKind::Yield(..)
|
||||
| hir::ExprKind::Array(..)
|
||||
| hir::ExprKind::Block(..)
|
||||
| hir::ExprKind::Break(..)
|
||||
| hir::ExprKind::Call(..)
|
||||
| hir::ExprKind::Field(..)
|
||||
| hir::ExprKind::Index(..)
|
||||
| hir::ExprKind::InlineAsm(..)
|
||||
| hir::ExprKind::Lit(..)
|
||||
| hir::ExprKind::Loop(..)
|
||||
| hir::ExprKind::MethodCall(..)
|
||||
| hir::ExprKind::Path(..)
|
||||
| hir::ExprKind::Repeat(..)
|
||||
| hir::ExprKind::Ret(..)
|
||||
| hir::ExprKind::Struct(..)
|
||||
| hir::ExprKind::Tup(..)
|
||||
| hir::ExprKind::While(..)
|
||||
| hir::ExprKind::Err => Sugg::NonParen(snippet),
|
||||
hir::ExprKind::Assign(..) => Sugg::BinOp(AssocOp::Assign, snippet),
|
||||
hir::ExprKind::AssignOp(op, ..) => Sugg::BinOp(hirbinop2assignop(op), snippet),
|
||||
hir::ExprKind::Binary(op, ..) => Sugg::BinOp(AssocOp::from_ast_binop(higher::binop(op.node)), snippet),
|
||||
hir::ExprKind::Cast(..) => Sugg::BinOp(AssocOp::As, snippet),
|
||||
hir::ExprKind::Type(..) => Sugg::BinOp(AssocOp::Colon, snippet),
|
||||
}
|
||||
}
|
||||
|
||||
/// Prepare a suggestion from an expression.
|
||||
pub fn ast(cx: &EarlyContext<'_>, expr: &ast::Expr, default: &'a str) -> Self {
|
||||
use syntax::ast::RangeLimits;
|
||||
|
|
|
|||
|
|
@ -150,4 +150,29 @@ fn match_as_ref() {
|
|||
};
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
macro_rules! foo_variant(
|
||||
($idx:expr) => (Foo::get($idx).unwrap())
|
||||
);
|
||||
|
||||
enum Foo {
|
||||
A,
|
||||
B,
|
||||
}
|
||||
|
||||
impl Foo {
|
||||
fn get(idx: u8) -> Option<&'static Self> {
|
||||
match idx {
|
||||
0 => Some(&Foo::A),
|
||||
1 => Some(&Foo::B),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// ICE #3719
|
||||
match foo_variant!(0) {
|
||||
&Foo::A => println!("A"),
|
||||
_ => println!("Wild"),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -278,5 +278,19 @@ LL | | Some(ref mut v) => Some(v),
|
|||
LL | | };
|
||||
| |_____^ help: try this: `mut_owned.as_mut()`
|
||||
|
||||
error: aborting due to 19 previous errors
|
||||
error: you don't need to add `&` to all patterns
|
||||
--> $DIR/matches.rs:174:5
|
||||
|
|
||||
LL | / match foo_variant!(0) {
|
||||
LL | | &Foo::A => println!("A"),
|
||||
LL | | _ => println!("Wild"),
|
||||
LL | | }
|
||||
| |_____^
|
||||
help: instead of prefixing all patterns with `&`, you can dereference the expression
|
||||
|
|
||||
LL | match *foo_variant!(0) {
|
||||
LL | Foo::A => println!("A"),
|
||||
|
|
||||
|
||||
error: aborting due to 20 previous errors
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue