Merge pull request #803 from Manishearth/fixes

ICE fixes and other things
This commit is contained in:
Manish Goregaokar 2016-03-27 04:31:02 +05:30
commit 12f374f788
6 changed files with 76 additions and 34 deletions

View File

@ -43,20 +43,21 @@ impl EnumGlobUse {
}
if let ItemUse(ref item_use) = item.node {
if let ViewPath_::ViewPathGlob(_) = item_use.node {
let def = cx.tcx.def_map.borrow()[&item.id];
if let Some(node_id) = cx.tcx.map.as_local_node_id(def.def_id()) {
if let Some(NodeItem(it)) = cx.tcx.map.find(node_id) {
if let ItemEnum(..) = it.node {
span_lint(cx, ENUM_GLOB_USE, item.span, "don't use glob imports for enum variants");
}
}
} else {
if let Some(dp) = cx.sess().cstore.def_path(def.def_id()).last() {
if let DefPathData::Type(_) = dp.data {
if let TyEnum(..) = cx.sess().cstore.item_type(&cx.tcx, def.def_id()).ty.sty {
if let Some(def) = cx.tcx.def_map.borrow().get(&item.id) {
if let Some(node_id) = cx.tcx.map.as_local_node_id(def.def_id()) {
if let Some(NodeItem(it)) = cx.tcx.map.find(node_id) {
if let ItemEnum(..) = it.node {
span_lint(cx, ENUM_GLOB_USE, item.span, "don't use glob imports for enum variants");
}
}
} else {
if let Some(dp) = cx.sess().cstore.def_path(def.def_id()).last() {
if let DefPathData::Type(_) = dp.data {
if let TyEnum(..) = cx.sess().cstore.item_type(&cx.tcx, def.def_id()).ty.sty {
span_lint(cx, ENUM_GLOB_USE, item.span, "don't use glob imports for enum variants");
}
}
}
}
}
}

View File

@ -402,8 +402,8 @@ impl LateLintPass for MethodsPass {
}
}
let ret_ty = return_ty(cx.tcx.node_id_to_type(implitem.id));
if &name.as_str() == &"new" && !ret_ty.map_or(false, |ret_ty| ret_ty.walk().any(|t| same_tys(cx, t, ty))) {
let ret_ty = return_ty(cx, implitem.id);
if &name.as_str() == &"new" && !ret_ty.map_or(false, |ret_ty| ret_ty.walk().any(|t| same_tys(cx, t, ty, implitem.id))) {
span_lint(cx,
NEW_RET_NO_SELF,
sig.explicit_self.span,

View File

@ -52,8 +52,8 @@ impl LateLintPass for NewWithoutDefault {
if_let_chain!{[
self_ty.walk_shallow().next().is_none(), // implements_trait does not work with generics
let Some(ret_ty) = return_ty(cx.tcx.node_id_to_type(id)),
same_tys(cx, self_ty, ret_ty),
let Some(ret_ty) = return_ty(cx, id),
same_tys(cx, self_ty, ret_ty, id),
let Some(default_trait_id) = get_trait_def_id(cx, &DEFAULT_TRAIT_PATH),
!implements_trait(cx, self_ty, default_trait_id, Vec::new())
], {

View File

@ -1,7 +1,6 @@
use reexport::*;
use rustc::lint::*;
use rustc::middle::const_eval;
use rustc::middle::ty;
use rustc::middle::{const_eval, def, ty};
use rustc_front::hir::*;
use rustc_front::intravisit::{FnKind, Visitor, walk_ty};
use rustc_front::util::{is_comparison_binop, binop_to_string};
@ -53,21 +52,34 @@ impl LateLintPass for TypePass {
if in_macro(cx, ast_ty.span) {
return;
}
if let Some(ty) = cx.tcx.ast_ty_to_ty_cache.borrow().get(&ast_ty.id) {
if let ty::TyBox(ref inner) = ty.sty {
if match_type(cx, inner, &VEC_PATH) {
if let Some(did) = cx.tcx.def_map.borrow().get(&ast_ty.id) {
if let def::Def::Struct(..) = did.full_def() {
if Some(did.def_id()) == cx.tcx.lang_items.owned_box() {
if_let_chain! {
[
let TyPath(_, ref path) = ast_ty.node,
let Some(ref last) = path.segments.last(),
let PathParameters::AngleBracketedParameters(ref ag) = last.parameters,
let Some(ref vec) = ag.types.get(0),
let Some(did) = cx.tcx.def_map.borrow().get(&vec.id),
let def::Def::Struct(..) = did.full_def(),
match_def_path(cx, did.def_id(), &VEC_PATH),
],
{
span_help_and_lint(cx,
BOX_VEC,
ast_ty.span,
"you seem to be trying to use `Box<Vec<T>>`. Consider using just `Vec<T>`",
"`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation.");
}
}
} else if match_def_path(cx, did.def_id(), &LL_PATH) {
span_help_and_lint(cx,
BOX_VEC,
LINKEDLIST,
ast_ty.span,
"you seem to be trying to use `Box<Vec<T>>`. Consider using just `Vec<T>`",
"`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation.");
"I see you're using a LinkedList! Perhaps you meant some other data structure?",
"a VecDeque might work");
}
} else if match_type(cx, ty, &LL_PATH) {
span_help_and_lint(cx,
LINKEDLIST,
ast_ty.span,
"I see you're using a LinkedList! Perhaps you meant some other data structure?",
"a VecDeque might work");
}
}
}

View File

@ -4,6 +4,7 @@ use rustc::lint::{LintContext, LateContext, Level, Lint};
use rustc::middle::def_id::DefId;
use rustc::middle::traits::ProjectionMode;
use rustc::middle::{cstore, def, infer, ty, traits};
use rustc::middle::subst::Subst;
use rustc::session::Session;
use rustc_front::hir::*;
use std::borrow::Cow;
@ -54,6 +55,7 @@ pub const STRING_PATH: [&'static str; 3] = ["collections", "string", "String"];
pub const TRANSMUTE_PATH: [&'static str; 3] = ["core", "intrinsics", "transmute"];
pub const VEC_FROM_ELEM_PATH: [&'static str; 3] = ["std", "vec", "from_elem"];
pub const VEC_PATH: [&'static str; 3] = ["collections", "vec", "Vec"];
pub const BOX_PATH: [&'static str; 3] = ["std", "boxed", "Box"];
/// Produce a nested chain of if-lets and ifs from the patterns:
///
@ -89,6 +91,11 @@ macro_rules! if_let_chain {
$block
}
};
([let $pat:pat = $expr:expr,], $block:block) => {
if let $pat = $expr {
$block
}
};
([$expr:expr, $($tt:tt)+], $block:block) => {
if $expr {
if_let_chain!{ [$($tt)+], $block }
@ -99,6 +106,11 @@ macro_rules! if_let_chain {
$block
}
};
([$expr:expr,], $block:block) => {
if $expr {
$block
}
};
}
/// Returns true if the two spans come from differing expansions (i.e. one is from a macro and one
@ -764,8 +776,13 @@ pub fn unsugar_range(expr: &Expr) -> Option<UnsugaredRange> {
}
/// Convenience function to get the return type of a function or `None` if the function diverges.
pub fn return_ty(fun: ty::Ty) -> Option<ty::Ty> {
if let ty::FnConverging(ret_ty) = fun.fn_sig().skip_binder().output {
pub fn return_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, fn_item: NodeId) -> Option<ty::Ty<'tcx>> {
let parameter_env = ty::ParameterEnvironment::for_item(cx.tcx, fn_item);
let infcx = infer::new_infer_ctxt(cx.tcx, &cx.tcx.tables, Some(parameter_env), ProjectionMode::Any);
let fn_sig = cx.tcx.node_id_to_type(fn_item).fn_sig().subst(infcx.tcx, &infcx.parameter_environment.free_substs);
let fn_sig = infcx.tcx.liberate_late_bound_regions(infcx.parameter_environment.free_id_outlive, &fn_sig);
if let ty::FnConverging(ret_ty) = fn_sig.output {
Some(ret_ty)
} else {
None
@ -775,7 +792,10 @@ pub fn return_ty(fun: ty::Ty) -> Option<ty::Ty> {
/// Check if two types are the same.
// FIXME: this works correctly for lifetimes bounds (`for <'a> Foo<'a>` == `for <'b> Foo<'b>` but
// not for type parameters.
pub fn same_tys<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, a: ty::Ty<'tcx>, b: ty::Ty<'tcx>) -> bool {
let infcx = infer::new_infer_ctxt(cx.tcx, &cx.tcx.tables, None, ProjectionMode::Any);
infcx.can_equate(&cx.tcx.erase_regions(&a), &cx.tcx.erase_regions(&b)).is_ok()
pub fn same_tys<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, a: ty::Ty<'tcx>, b: ty::Ty<'tcx>, parameter_item: NodeId) -> bool {
let parameter_env = ty::ParameterEnvironment::for_item(cx.tcx, parameter_item);
let infcx = infer::new_infer_ctxt(cx.tcx, &cx.tcx.tables, Some(parameter_env), ProjectionMode::Any);
let new_a = a.subst(infcx.tcx, &infcx.parameter_environment.free_substs);
let new_b = b.subst(infcx.tcx, &infcx.parameter_environment.free_substs);
infcx.can_equate(&new_a, &new_b).is_ok()
}

View File

@ -47,6 +47,15 @@ impl<'a> Lt2<'a> {
pub fn new(s: &str) -> Lt2 { unimplemented!() }
}
struct Lt3<'a> {
foo: &'a u32,
}
impl<'a> Lt3<'a> {
// The lifetime is different, but thats irrelevant, see #734
pub fn new() -> Lt3<'static> { unimplemented!() }
}
#[derive(Clone,Copy)]
struct U;