Add trivial bounds lint

This commit is contained in:
Matthew Jasper 2018-05-06 22:52:58 +01:00
parent 27183a9030
commit dabb820b00
5 changed files with 177 additions and 0 deletions

View file

@ -1591,3 +1591,61 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExternCrate {
self.0 += 1;
}
}
/// Lint for trait and lifetime bounds that don't depend on type parameters
/// which either do nothing, or stop the item from being used.
pub struct TrivialConstraints;
declare_lint! {
TRIVIAL_BOUNDS,
Warn,
"these bounds don't depend on an type parameters"
}
impl LintPass for TrivialConstraints {
fn get_lints(&self) -> LintArray {
lint_array!(TRIVIAL_BOUNDS)
}
}
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints {
fn check_item(
&mut self,
cx: &LateContext<'a, 'tcx>,
item: &'tcx hir::Item,
) {
use rustc::ty::fold::TypeFoldable;
use rustc::ty::Predicate::*;
if cx.tcx.features().trivial_bounds {
let def_id = cx.tcx.hir.local_def_id(item.id);
let predicates = cx.tcx.predicates_of(def_id);
for predicate in &predicates.predicates {
let predicate_kind_name = match *predicate {
Trait(..) => "Trait",
TypeOutlives(..) |
RegionOutlives(..) => "Lifetime",
// Ignore projections, as they can only be global
// if the trait bound is global
Projection(..) |
// Ignore bounds that a user can't type
WellFormed(..) |
ObjectSafe(..) |
ClosureKind(..) |
Subtype(..) |
ConstEvaluatable(..) => continue,
};
if !predicate.is_global() {
cx.span_lint(
TRIVIAL_BOUNDS,
item.span,
&format!("{} bound {} does not depend on any type \
or lifetime parameters", predicate_kind_name, predicate),
);
}
}
}
}
}

View file

@ -137,6 +137,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
UnreachablePub,
TypeAliasBounds,
UnusedBrokenConst,
TrivialConstraints,
);
add_builtin_with_new!(sess,

View file

@ -0,0 +1,18 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// run-pass
#![allow(unused)]
#![deny(trivial_bounds)] // Ignored without the trivial_bounds feature flag.
struct A where i32: Copy;
fn main() {}

View file

@ -0,0 +1,50 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(trivial_bounds)]
#![allow(unused)]
#![deny(trivial_bounds)]
struct A where i32: Copy; //~ ERROR
trait X<T: Copy> {}
trait Y<T>: Copy {}
trait Z {
type S: Copy;
}
// Check only the bound the user writes trigger the lint
fn trivial_elaboration<T>() where T: X<i32> + Z<S = i32>, i32: Y<T> {} // OK
fn global_param() where i32: X<()> {} //~ ERROR
// Should only error on the trait bound, not the implicit
// projection bound <i32 as Z>::S == i32.
fn global_projection() where i32: Z<S = i32> {} //~ ERROR
impl A {
fn new() -> A { A }
}
// Lifetime bounds should be linted as well
fn global_lifetimes() where i32: 'static, &'static str: 'static {}
//~^ ERROR
//~| ERROR
fn local_lifetimes<'a>() where i32: 'a, &'a str: 'a {} // OK
fn global_outlives() where 'static: 'static {} //~ ERROR
// Check that each bound is checked individually
fn mixed_bounds<T: Copy>() where i32: X<T> + Copy {} //~ ERROR
fn main() {}

View file

@ -0,0 +1,50 @@
error: Trait bound i32: std::marker::Copy does not depend on any type or lifetime parameters
--> $DIR/trivial-bounds-lint.rs:15:1
|
LL | struct A where i32: Copy; //~ ERROR
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: lint level defined here
--> $DIR/trivial-bounds-lint.rs:13:9
|
LL | #![deny(trivial_bounds)]
| ^^^^^^^^^^^^^^
error: Trait bound i32: X<()> does not depend on any type or lifetime parameters
--> $DIR/trivial-bounds-lint.rs:28:1
|
LL | fn global_param() where i32: X<()> {} //~ ERROR
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: Trait bound i32: Z does not depend on any type or lifetime parameters
--> $DIR/trivial-bounds-lint.rs:32:1
|
LL | fn global_projection() where i32: Z<S = i32> {} //~ ERROR
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: Lifetime bound i32 : 'static does not depend on any type or lifetime parameters
--> $DIR/trivial-bounds-lint.rs:39:1
|
LL | fn global_lifetimes() where i32: 'static, &'static str: 'static {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: Lifetime bound &'static str : 'static does not depend on any type or lifetime parameters
--> $DIR/trivial-bounds-lint.rs:39:1
|
LL | fn global_lifetimes() where i32: 'static, &'static str: 'static {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: Lifetime bound 'static : 'static does not depend on any type or lifetime parameters
--> $DIR/trivial-bounds-lint.rs:45:1
|
LL | fn global_outlives() where 'static: 'static {} //~ ERROR
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: Trait bound i32: std::marker::Copy does not depend on any type or lifetime parameters
--> $DIR/trivial-bounds-lint.rs:48:1
|
LL | fn mixed_bounds<T: Copy>() where i32: X<T> + Copy {} //~ ERROR
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 7 previous errors