compare-method lint
This commit is contained in:
parent
f652651275
commit
ddabd509a8
24 changed files with 152 additions and 67 deletions
|
|
@ -646,13 +646,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
};
|
||||
|
||||
if let SubregionOrigin::CompareImplMethodObligation {
|
||||
span, item_name, impl_item_def_id, trait_item_def_id
|
||||
span, item_name, impl_item_def_id, trait_item_def_id, lint_id
|
||||
} = origin {
|
||||
self.report_extra_impl_obligation(span,
|
||||
item_name,
|
||||
impl_item_def_id,
|
||||
trait_item_def_id,
|
||||
&format!("`{}: {}`", bound_kind, sub))
|
||||
&format!("`{}: {}`", bound_kind, sub),
|
||||
lint_id)
|
||||
.emit();
|
||||
return;
|
||||
}
|
||||
|
|
@ -977,12 +978,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
infer::CompareImplMethodObligation { span,
|
||||
item_name,
|
||||
impl_item_def_id,
|
||||
trait_item_def_id } => {
|
||||
trait_item_def_id,
|
||||
lint_id } => {
|
||||
self.report_extra_impl_obligation(span,
|
||||
item_name,
|
||||
impl_item_def_id,
|
||||
trait_item_def_id,
|
||||
&format!("`{}: {}`", sup, sub))
|
||||
&format!("`{}: {}`", sup, sub),
|
||||
lint_id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -368,6 +368,10 @@ pub enum SubregionOrigin<'tcx> {
|
|||
item_name: ast::Name,
|
||||
impl_item_def_id: DefId,
|
||||
trait_item_def_id: DefId,
|
||||
|
||||
// this is `Some(_)` if this error arises from the bug fix for
|
||||
// #18937. This is a temporary measure.
|
||||
lint_id: Option<ast::NodeId>,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -1816,12 +1820,14 @@ impl<'tcx> SubregionOrigin<'tcx> {
|
|||
|
||||
traits::ObligationCauseCode::CompareImplMethodObligation { item_name,
|
||||
impl_item_def_id,
|
||||
trait_item_def_id } =>
|
||||
trait_item_def_id,
|
||||
lint_id } =>
|
||||
SubregionOrigin::CompareImplMethodObligation {
|
||||
span: cause.span,
|
||||
item_name: item_name,
|
||||
impl_item_def_id: impl_item_def_id,
|
||||
trait_item_def_id: trait_item_def_id,
|
||||
lint_id: lint_id,
|
||||
},
|
||||
|
||||
_ => default(),
|
||||
|
|
|
|||
|
|
@ -198,6 +198,12 @@ declare_lint! {
|
|||
"patterns in functions without body were erroneously allowed"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
pub EXTRA_REQUIREMENT_IN_IMPL,
|
||||
Warn,
|
||||
"detects extra requirements in impls that were erroneously allowed"
|
||||
}
|
||||
|
||||
/// Does nothing as a lint pass, but registers some `Lint`s
|
||||
/// which are used by other parts of the compiler.
|
||||
#[derive(Copy, Clone)]
|
||||
|
|
@ -235,7 +241,8 @@ impl LintPass for HardwiredLints {
|
|||
HR_LIFETIME_IN_ASSOC_TYPE,
|
||||
LIFETIME_UNDERSCORE,
|
||||
SAFE_EXTERN_STATICS,
|
||||
PATTERNS_IN_FNS_WITHOUT_BODY
|
||||
PATTERNS_IN_FNS_WITHOUT_BODY,
|
||||
EXTRA_REQUIREMENT_IN_IMPL
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ use std::fmt;
|
|||
use syntax::attr;
|
||||
use syntax::parse::token::InternedString;
|
||||
use syntax::ast;
|
||||
use syntax_pos::Span;
|
||||
use syntax_pos::{MultiSpan, Span};
|
||||
use errors::{self, Diagnostic, DiagnosticBuilder};
|
||||
use hir;
|
||||
use hir::intravisit as hir_visit;
|
||||
|
|
@ -107,9 +107,12 @@ impl fmt::Debug for EarlyLint {
|
|||
}
|
||||
|
||||
impl EarlyLint {
|
||||
pub fn new(id: LintId, span: Span, msg: String) -> Self {
|
||||
let mut diagnostic = Diagnostic::new(errors::Level::Warning, &msg);
|
||||
diagnostic.set_span(span);
|
||||
pub fn new<M: EarlyLintMessage>(id: LintId, span: Span, msg: M) -> Self {
|
||||
let diagnostic = msg.into_diagnostic(span);
|
||||
EarlyLint { id: id, span: span, diagnostic: diagnostic }
|
||||
}
|
||||
|
||||
pub fn with_diagnostic(id: LintId, span: Span, diagnostic: Diagnostic) -> Self {
|
||||
EarlyLint { id: id, span: span, diagnostic: diagnostic }
|
||||
}
|
||||
|
||||
|
|
@ -120,7 +123,23 @@ impl EarlyLint {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait EarlyLintMessage {
|
||||
fn into_diagnostic(self, span: Span) -> Diagnostic;
|
||||
}
|
||||
|
||||
impl EarlyLintMessage for String {
|
||||
fn into_diagnostic(self, span: Span) -> Diagnostic {
|
||||
let mut diagnostic = Diagnostic::new(errors::Level::Warning, &self);
|
||||
diagnostic.set_span(span);
|
||||
diagnostic
|
||||
}
|
||||
}
|
||||
|
||||
impl EarlyLintMessage for Diagnostic {
|
||||
fn into_diagnostic(self, _span: Span) -> Diagnostic {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Extra information for a future incompatibility lint. See the call
|
||||
/// to `register_future_incompatible` in `librustc_lint/lib.rs` for
|
||||
|
|
@ -439,13 +458,15 @@ pub fn raw_emit_lint(sess: &Session,
|
|||
raw_struct_lint(sess, lints, lint, lvlsrc, span, msg).emit();
|
||||
}
|
||||
|
||||
pub fn raw_struct_lint<'a>(sess: &'a Session,
|
||||
lints: &LintStore,
|
||||
lint: &'static Lint,
|
||||
lvlsrc: LevelSource,
|
||||
span: Option<Span>,
|
||||
msg: &str)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
pub fn raw_struct_lint<'a, S>(sess: &'a Session,
|
||||
lints: &LintStore,
|
||||
lint: &'static Lint,
|
||||
lvlsrc: LevelSource,
|
||||
span: Option<S>,
|
||||
msg: &str)
|
||||
-> DiagnosticBuilder<'a>
|
||||
where S: Into<MultiSpan>
|
||||
{
|
||||
let (mut level, source) = lvlsrc;
|
||||
if level == Allow {
|
||||
return sess.diagnostic().struct_dummy();
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ use hir;
|
|||
|
||||
pub use lint::context::{LateContext, EarlyContext, LintContext, LintStore,
|
||||
raw_emit_lint, check_crate, check_ast_crate, gather_attrs,
|
||||
raw_struct_lint, FutureIncompatibleInfo, EarlyLint};
|
||||
raw_struct_lint, FutureIncompatibleInfo, EarlyLint, EarlyLintMessage};
|
||||
|
||||
/// Specification of a single lint.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
|
|
|||
|
|
@ -258,11 +258,11 @@ impl Session {
|
|||
pub fn unimpl(&self, msg: &str) -> ! {
|
||||
self.diagnostic().unimpl(msg)
|
||||
}
|
||||
pub fn add_lint(&self,
|
||||
lint: &'static lint::Lint,
|
||||
id: ast::NodeId,
|
||||
sp: Span,
|
||||
msg: String) {
|
||||
pub fn add_lint<M: lint::EarlyLintMessage>(&self,
|
||||
lint: &'static lint::Lint,
|
||||
id: ast::NodeId,
|
||||
sp: Span,
|
||||
msg: M) {
|
||||
let lint_id = lint::LintId::of(lint);
|
||||
let mut lints = self.lints.borrow_mut();
|
||||
let early_lint = lint::EarlyLint::new(lint_id, sp, msg);
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ use super::{
|
|||
use fmt_macros::{Parser, Piece, Position};
|
||||
use hir::def_id::DefId;
|
||||
use infer::{self, InferCtxt, TypeOrigin};
|
||||
use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL;
|
||||
use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
|
||||
use ty::error::ExpectedFound;
|
||||
use ty::fast_reject;
|
||||
|
|
@ -423,9 +424,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
item_name: ast::Name,
|
||||
_impl_item_def_id: DefId,
|
||||
trait_item_def_id: DefId,
|
||||
requirement: &fmt::Display)
|
||||
requirement: &fmt::Display,
|
||||
lint_id: Option<ast::NodeId>) // (*)
|
||||
-> DiagnosticBuilder<'tcx>
|
||||
{
|
||||
// (*) This parameter is temporary and used only for phasing
|
||||
// in the bug fix to #18937. If it is `Some`, it has a kind of
|
||||
// weird effect -- the diagnostic is reported as a lint, and
|
||||
// the builder which is returned is marked as canceled.
|
||||
|
||||
let mut err =
|
||||
struct_span_err!(self.tcx.sess,
|
||||
error_span,
|
||||
|
|
@ -441,6 +448,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
error_span,
|
||||
&format!("impl has extra requirement {}", requirement));
|
||||
|
||||
if let Some(node_id) = lint_id {
|
||||
let diagnostic = (*err).clone();
|
||||
self.tcx.sess.add_lint(EXTRA_REQUIREMENT_IN_IMPL, node_id, error_span, diagnostic);
|
||||
err.cancel();
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
|
|
@ -452,14 +465,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
let mut err = match *error {
|
||||
SelectionError::Unimplemented => {
|
||||
if let ObligationCauseCode::CompareImplMethodObligation {
|
||||
item_name, impl_item_def_id, trait_item_def_id
|
||||
item_name, impl_item_def_id, trait_item_def_id, lint_id
|
||||
} = obligation.cause.code {
|
||||
self.report_extra_impl_obligation(
|
||||
span,
|
||||
item_name,
|
||||
impl_item_def_id,
|
||||
trait_item_def_id,
|
||||
&format!("`{}`", obligation.predicate))
|
||||
&format!("`{}`", obligation.predicate),
|
||||
lint_id)
|
||||
.emit();
|
||||
return;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -138,10 +138,12 @@ pub enum ObligationCauseCode<'tcx> {
|
|||
|
||||
ImplDerivedObligation(DerivedObligationCause<'tcx>),
|
||||
|
||||
// error derived when matching traits/impls; see ObligationCause for more details
|
||||
CompareImplMethodObligation {
|
||||
item_name: ast::Name,
|
||||
impl_item_def_id: DefId,
|
||||
trait_item_def_id: DefId
|
||||
trait_item_def_id: DefId,
|
||||
lint_id: Option<ast::NodeId>,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -197,11 +197,13 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
|
|||
}
|
||||
super::CompareImplMethodObligation { item_name,
|
||||
impl_item_def_id,
|
||||
trait_item_def_id } => {
|
||||
trait_item_def_id,
|
||||
lint_id } => {
|
||||
Some(super::CompareImplMethodObligation {
|
||||
item_name: item_name,
|
||||
impl_item_def_id: impl_item_def_id,
|
||||
trait_item_def_id: trait_item_def_id,
|
||||
lint_id: lint_id,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue