Skip to content

Commit 052f598

Browse files
committed
Fix types comparison
1 parent 8e9e858 commit 052f598

File tree

5 files changed

+49
-13
lines changed

5 files changed

+49
-13
lines changed

src/methods.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use std::{fmt, iter};
1010
use syntax::codemap::Span;
1111
use syntax::ptr::P;
1212
use utils::{get_trait_def_id, implements_trait, in_external_macro, in_macro, match_path, match_trait_method,
13-
match_type, method_chain_args, return_ty, snippet, snippet_opt, span_lint,
13+
match_type, method_chain_args, return_ty, same_tys, snippet, snippet_opt, span_lint,
1414
span_lint_and_then, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth};
1515
use utils::{BTREEMAP_ENTRY_PATH, DEFAULT_TRAIT_PATH, HASHMAP_ENTRY_PATH, OPTION_PATH, RESULT_PATH, STRING_PATH,
1616
VEC_PATH};
@@ -432,7 +432,7 @@ impl LateLintPass for MethodsPass {
432432
}
433433

434434
let ret_ty = return_ty(cx.tcx.node_id_to_type(implitem.id));
435-
if &name.as_str() == &"new" && !ret_ty.map_or(false, |ret_ty| ret_ty.walk().any(|t| t == ty)) {
435+
if &name.as_str() == &"new" && !ret_ty.map_or(false, |ret_ty| ret_ty.walk().any(|t| same_tys(cx, t, ty))) {
436436
span_lint(cx,
437437
NEW_RET_NO_SELF,
438438
sig.explicit_self.span,

src/new_without_default.rs

+11-11
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ use rustc_front::hir;
33
use rustc_front::intravisit::FnKind;
44
use syntax::ast;
55
use syntax::codemap::Span;
6-
use utils::{get_trait_def_id, implements_trait, in_external_macro, return_ty, span_lint, DEFAULT_TRAIT_PATH};
6+
use utils::{get_trait_def_id, implements_trait, in_external_macro, return_ty, same_tys, span_lint,
7+
DEFAULT_TRAIT_PATH};
78

89
/// **What it does:** This lints about type with a `fn new() -> Self` method and no `Default`
910
/// implementation.
@@ -49,16 +50,15 @@ impl LateLintPass for NewWithoutDefault {
4950
if decl.inputs.is_empty() && name.as_str() == "new" {
5051
let self_ty = cx.tcx.lookup_item_type(cx.tcx.map.local_def_id(cx.tcx.map.get_parent(id))).ty;
5152

52-
let ret_ty = return_ty(cx.tcx.node_id_to_type(id));
53-
54-
if Some(self_ty) == ret_ty {
55-
if let Some(default_trait_id) = get_trait_def_id(cx, &DEFAULT_TRAIT_PATH) {
56-
if !implements_trait(cx, self_ty, default_trait_id, Vec::new()) {
57-
span_lint(cx, NEW_WITHOUT_DEFAULT, span,
58-
&format!("you should consider adding a `Default` implementation for `{}`", self_ty));
59-
}
60-
}
61-
}
53+
if_let_chain!{[
54+
let Some(ret_ty) = return_ty(cx.tcx.node_id_to_type(id)),
55+
same_tys(cx, self_ty, ret_ty),
56+
let Some(default_trait_id) = get_trait_def_id(cx, &DEFAULT_TRAIT_PATH),
57+
!implements_trait(cx, self_ty, default_trait_id, Vec::new())
58+
], {
59+
span_lint(cx, NEW_WITHOUT_DEFAULT, span,
60+
&format!("you should consider adding a `Default` implementation for `{}`", self_ty));
61+
}}
6262
}
6363
}
6464
}

src/utils/mod.rs

+8
Original file line numberDiff line numberDiff line change
@@ -740,3 +740,11 @@ pub fn return_ty(fun: ty::Ty) -> Option<ty::Ty> {
740740
None
741741
}
742742
}
743+
744+
/// Check if two types are the same.
745+
// FIXME: this works correctly for lifetimes bounds (`for <'a> Foo<'a>` == `for <'b> Foo<'b>` but
746+
// not for type parameters.
747+
pub fn same_tys<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, a: ty::Ty<'tcx>, b: ty::Ty<'tcx>) -> bool {
748+
let infcx = infer::new_infer_ctxt(cx.tcx, &cx.tcx.tables, None);
749+
infcx.can_equate(&cx.tcx.erase_regions(&a), &cx.tcx.erase_regions(&b)).is_ok()
750+
}

tests/compile-fail/methods.rs

+19
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,25 @@ impl T {
2828
//~| ERROR methods called `new` usually return `Self`
2929
}
3030

31+
struct Lt<'a> {
32+
foo: &'a u32,
33+
}
34+
35+
impl<'a> Lt<'a> {
36+
// The lifetime is different, but that’s irrelevant, see #734
37+
#[allow(needless_lifetimes)]
38+
pub fn new<'b>(s: &'b str) -> Lt<'b> { unimplemented!() }
39+
}
40+
41+
struct Lt2<'a> {
42+
foo: &'a u32,
43+
}
44+
45+
impl<'a> Lt2<'a> {
46+
// The lifetime is different, but that’s irrelevant, see #734
47+
pub fn new(s: &str) -> Lt2 { unimplemented!() }
48+
}
49+
3150
#[derive(Clone,Copy)]
3251
struct U;
3352

tests/compile-fail/new_without_default.rs

+9
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,13 @@ impl Params {
3232
fn new(_: u32) -> Self { Params }
3333
}
3434

35+
struct Generics<'a, T> {
36+
foo: &'a bool,
37+
bar: T,
38+
}
39+
40+
impl<'c, V> Generics<'c, V> {
41+
fn new<'b>() -> Generics<'b, V> { unimplemented!() } //~ERROR: you should consider adding a `Default` implementation for
42+
}
43+
3544
fn main() {}

0 commit comments

Comments
 (0)