Merge pull request #1592 from Manishearth/node_id_to_type

Bugfixes
This commit is contained in:
Martin Carton 2017-03-03 19:53:15 +01:00 committed by GitHub
commit c2d9d46cc1
5 changed files with 61 additions and 76 deletions

View File

@ -53,21 +53,6 @@ pub enum Constant {
Tuple(Vec<Constant>),
}
impl Constant {
/// Convert to `u64` if possible.
///
/// # panics
///
/// If the constant could not be converted to `u64` losslessly.
fn as_u64(&self) -> u64 {
if let Constant::Int(val) = *self {
val.to_u64().expect("negative constant can't be casted to `u64`")
} else {
panic!("Could not convert a `{:?}` to `u64`", self);
}
}
}
impl PartialEq for Constant {
fn eq(&self, other: &Constant) -> bool {
match (self, other) {
@ -266,11 +251,12 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
ExprLit(ref lit) => Some(lit_to_constant(&lit.node, self.tcx, self.tables.expr_ty(e))),
ExprArray(ref vec) => self.multi(vec).map(Constant::Vec),
ExprTup(ref tup) => self.multi(tup).map(Constant::Tuple),
ExprRepeat(ref value, number_id) => {
let val = &self.tcx.hir.body(number_id).value;
self.binop_apply(value,
val,
|v, n| Some(Constant::Repeat(Box::new(v), n.as_u64() as usize)))
ExprRepeat(ref value, _) => {
let n = match self.tables.expr_ty(e).sty {
ty::TyArray(_, n) => n,
_ => span_bug!(e.span, "typeck error"),
};
self.expr(value).map(|v| Constant::Repeat(Box::new(v), n))
},
ExprUnary(op, ref operand) => {
self.expr(operand).and_then(|o| match op {
@ -375,15 +361,4 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
_ => None,
}
}
fn binop_apply<F>(&mut self, left: &Expr, right: &Expr, op: F) -> Option<Constant>
where F: Fn(Constant, Constant) -> Option<Constant>
{
if let (Some(lc), Some(rc)) = (self.expr(left), self.expr(right)) {
op(lc, rc)
} else {
None
}
}
}

View File

@ -10,7 +10,7 @@ use syntax::ast::LitKind;
use syntax::codemap::Span;
use utils::paths;
use utils::{match_type, snippet, span_note_and_lint, span_lint_and_then, in_external_macro, expr_block, walk_ptrs_ty,
is_expn_of};
is_expn_of, remove_blocks};
use utils::sugg::Sugg;
/// **What it does:** Checks for matches with a single arm where an `if let`
@ -179,11 +179,12 @@ fn check_single_match(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) {
if arms.len() == 2 &&
arms[0].pats.len() == 1 && arms[0].guard.is_none() &&
arms[1].pats.len() == 1 && arms[1].guard.is_none() {
let els = if is_unit_expr(&arms[1].body) {
let els = remove_blocks(&arms[1].body);
let els = if is_unit_expr(els) {
None
} else if let ExprBlock(_) = arms[1].body.node {
} else if let ExprBlock(_) = els.node {
// matches with blocks that contain statements are prettier as `if let + else`
Some(&*arms[1].body)
Some(els)
} else {
// allow match arms with just expressions
return;
@ -198,29 +199,33 @@ fn check_single_match(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) {
fn check_single_match_single_pattern(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr, els: Option<&Expr>) {
if arms[1].pats[0].node == PatKind::Wild {
let lint = if els.is_some() {
SINGLE_MATCH_ELSE
} else {
SINGLE_MATCH
};
let els_str = els.map_or(String::new(), |els| format!(" else {}", expr_block(cx, els, None, "..")));
span_lint_and_then(cx,
lint,
expr.span,
"you seem to be trying to use match for destructuring a single pattern. \
Consider using `if let`",
|db| {
db.span_suggestion(expr.span,
"try this",
format!("if let {} = {} {}{}",
snippet(cx, arms[0].pats[0].span, ".."),
snippet(cx, ex.span, ".."),
expr_block(cx, &arms[0].body, None, ".."),
els_str));
});
report_single_match_single_pattern(cx, ex, arms, expr, els);
}
}
fn report_single_match_single_pattern(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr, els: Option<&Expr>) {
let lint = if els.is_some() {
SINGLE_MATCH_ELSE
} else {
SINGLE_MATCH
};
let els_str = els.map_or(String::new(), |els| format!(" else {}", expr_block(cx, els, None, "..")));
span_lint_and_then(cx,
lint,
expr.span,
"you seem to be trying to use match for destructuring a single pattern. \
Consider using `if let`",
|db| {
db.span_suggestion(expr.span,
"try this",
format!("if let {} = {} {}{}",
snippet(cx, arms[0].pats[0].span, ".."),
snippet(cx, ex.span, ".."),
expr_block(cx, &arms[0].body, None, ".."),
els_str));
});
}
fn check_single_match_opt_like(
cx: &LateContext,
ex: &Expr,
@ -253,26 +258,7 @@ fn check_single_match_opt_like(
for &(ty_path, pat_path) in candidates {
if &path == pat_path && match_type(cx, ty, ty_path) {
let lint = if els.is_some() {
SINGLE_MATCH_ELSE
} else {
SINGLE_MATCH
};
let els_str = els.map_or(String::new(), |els| format!(" else {}", expr_block(cx, els, None, "..")));
span_lint_and_then(cx,
lint,
expr.span,
"you seem to be trying to use match for destructuring a single pattern. Consider \
using `if let`",
|db| {
db.span_suggestion(expr.span,
"try this",
format!("if let {} = {} {}{}",
snippet(cx, arms[0].pats[0].span, ".."),
snippet(cx, ex.span, ".."),
expr_block(cx, &arms[0].body, None, ".."),
els_str));
});
report_single_match_single_pattern(cx, ex, arms, expr, els);
}
}
}

View File

@ -385,7 +385,7 @@ pub fn get_item_name(cx: &LateContext, expr: &Expr) -> Option<Name> {
/// snippet(cx, expr.span, "..")
/// ```
pub fn snippet<'a, 'b, T: LintContext<'b>>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> {
cx.sess().codemap().span_to_snippet(span).map(From::from).unwrap_or_else(|_| Cow::Borrowed(default))
snippet_opt(cx, span).map_or_else(|| Cow::Borrowed(default), From::from)
}
/// Convert a span to a code snippet. Returns `None` if not available.

View File

@ -0,0 +1,13 @@
#![feature(plugin)]
#![plugin(clippy)]
#![allow(clippy)]
fn main() {
match 1 {
1 => {}
2 => {
[0; 1];
}
_ => {}
}
}

View File

@ -0,0 +1,11 @@
#![feature(plugin)]
#![plugin(clippy)]
#![warn(single_match_else)]
fn main() {
let n = match (42, 43) {
(42, n) => n,
_ => panic!("typeck error"),
};
assert_eq!(n, 43);
}