Fix ICE caused in unwrap module

This commit is contained in:
Eduardo Broto 2020-05-12 22:05:56 +02:00
parent b20a9cd474
commit e4cd8e7961
2 changed files with 31 additions and 2 deletions

View File

@ -8,6 +8,7 @@
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::map::Map; use rustc_middle::hir::map::Map;
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::Ty;
use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span; use rustc_span::source_map::Span;
@ -90,6 +91,14 @@ fn collect_unwrap_info<'a, 'tcx>(
branch: &'tcx Expr<'_>, branch: &'tcx Expr<'_>,
invert: bool, invert: bool,
) -> Vec<UnwrapInfo<'tcx>> { ) -> Vec<UnwrapInfo<'tcx>> {
fn is_relevant_option_call(cx: &LateContext<'_, '_>, ty: Ty<'_>, method_name: &str) -> bool {
is_type_diagnostic_item(cx, ty, sym!(option_type)) && ["is_some", "is_none"].contains(&method_name)
}
fn is_relevant_result_call(cx: &LateContext<'_, '_>, ty: Ty<'_>, method_name: &str) -> bool {
is_type_diagnostic_item(cx, ty, sym!(result_type)) && ["is_ok", "is_err"].contains(&method_name)
}
if let ExprKind::Binary(op, left, right) = &expr.kind { if let ExprKind::Binary(op, left, right) = &expr.kind {
match (invert, op.node) { match (invert, op.node) {
(false, BinOpKind::And) | (false, BinOpKind::BitAnd) | (true, BinOpKind::Or) | (true, BinOpKind::BitOr) => { (false, BinOpKind::And) | (false, BinOpKind::BitAnd) | (true, BinOpKind::Or) | (true, BinOpKind::BitOr) => {
@ -106,9 +115,8 @@ fn collect_unwrap_info<'a, 'tcx>(
if let ExprKind::MethodCall(method_name, _, args) = &expr.kind; if let ExprKind::MethodCall(method_name, _, args) = &expr.kind;
if let ExprKind::Path(QPath::Resolved(None, path)) = &args[0].kind; if let ExprKind::Path(QPath::Resolved(None, path)) = &args[0].kind;
let ty = cx.tables.expr_ty(&args[0]); let ty = cx.tables.expr_ty(&args[0]);
if is_type_diagnostic_item(cx, ty, sym!(option_type)) || is_type_diagnostic_item(cx, ty, sym!(result_type));
let name = method_name.ident.as_str(); let name = method_name.ident.as_str();
if ["is_some", "is_none", "is_ok", "is_err"].contains(&&*name); if is_relevant_option_call(cx, ty, &name) || is_relevant_result_call(cx, ty, &name);
then { then {
assert!(args.len() == 1); assert!(args.len() == 1);
let unwrappable = match name.as_ref() { let unwrappable = match name.as_ref() {

View File

@ -78,3 +78,24 @@ fn main() {
assert!(x.is_ok(), "{:?}", x.unwrap_err()); // ok, it's a common test pattern assert!(x.is_ok(), "{:?}", x.unwrap_err()); // ok, it's a common test pattern
} }
mod issue_5579 {
trait IsErr {
fn is_err(&self, err: &str) -> bool;
}
impl<T> IsErr for Option<T> {
fn is_err(&self, _err: &str) -> bool {
true
}
}
#[allow(unused)]
fn boom() {
let t = Some(1);
if t.is_err("") {
t.unwrap();
}
}
}