Refactor rustc lint API

This commit is contained in:
Maybe Waffle 2022-09-16 11:01:02 +04:00
parent 65445a571c
commit a8f7e244b7
64 changed files with 1760 additions and 1555 deletions

View file

@ -235,14 +235,18 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
.emit()
}
Err(ErrorHandled::TooGeneric) => Err(if uv.has_infer_types_or_consts() {
NotConstEvaluatable::MentionsInfer
Err(ErrorHandled::TooGeneric) => {
let err = if uv.has_infer_types_or_consts() {
NotConstEvaluatable::MentionsInfer
} else if uv.has_param_types_or_consts() {
NotConstEvaluatable::MentionsParam
} else {
let guar = infcx.tcx.sess.delay_span_bug(span, format!("Missing value for constant, but no error reported?"));
NotConstEvaluatable::Error(guar)
}),
NotConstEvaluatable::MentionsParam
} else {
let guar = infcx.tcx.sess.delay_span_bug(span, format!("Missing value for constant, but no error reported?"));
NotConstEvaluatable::Error(guar)
};
Err(err)
},
Err(ErrorHandled::Linted) => {
let reported =
infcx.tcx.sess.delay_span_bug(span, "constant in type had error reported as lint");
@ -250,23 +254,23 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
}
Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)),
Ok(_) => {
if uv.substs.has_param_types_or_consts() {
assert!(matches!(infcx.tcx.def_kind(uv.def.did), DefKind::AnonConst));
let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(uv.def);
if uv.substs.has_param_types_or_consts() {
assert!(matches!(infcx.tcx.def_kind(uv.def.did), DefKind::AnonConst));
let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(uv.def);
if mir_body.is_polymorphic {
let Some(local_def_id) = uv.def.did.as_local() else { return Ok(()) };
tcx.struct_span_lint_hir(
lint::builtin::CONST_EVALUATABLE_UNCHECKED,
tcx.hir().local_def_id_to_hir_id(local_def_id),
span,
|err| {
err.build("cannot use constants which depend on generic parameters in types").emit();
})
}
}
if mir_body.is_polymorphic {
let Some(local_def_id) = uv.def.did.as_local() else { return Ok(()) };
tcx.struct_span_lint_hir(
lint::builtin::CONST_EVALUATABLE_UNCHECKED,
tcx.hir().local_def_id_to_hir_id(local_def_id),
span,
"cannot use constants which depend on generic parameters in types",
|err| err
)
}
}
Ok(())
Ok(())
},
}
}

View file

@ -14,7 +14,7 @@ use crate::infer::TyCtxtInferExt;
use crate::traits::query::evaluate_obligation::InferCtxtExt;
use crate::traits::{self, Obligation, ObligationCause};
use hir::def::DefKind;
use rustc_errors::{FatalError, MultiSpan};
use rustc_errors::{DelayDm, FatalError, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::abstract_const::{walk_abstract_const, AbstractConst};
@ -164,37 +164,42 @@ fn lint_object_unsafe_trait(
) {
// Using `CRATE_NODE_ID` is wrong, but it's hard to get a more precise id.
// It's also hard to get a use site span, so we use the method definition span.
tcx.struct_span_lint_hir(WHERE_CLAUSES_OBJECT_SAFETY, hir::CRATE_HIR_ID, span, |lint| {
let mut err = lint.build(&format!(
"the trait `{}` cannot be made into an object",
tcx.def_path_str(trait_def_id)
));
let node = tcx.hir().get_if_local(trait_def_id);
let mut spans = MultiSpan::from_span(span);
if let Some(hir::Node::Item(item)) = node {
spans.push_span_label(item.ident.span, "this trait cannot be made into an object...");
spans.push_span_label(span, format!("...because {}", violation.error_msg()));
} else {
spans.push_span_label(
span,
format!(
"the trait cannot be made into an object because {}",
violation.error_msg()
),
tcx.struct_span_lint_hir(
WHERE_CLAUSES_OBJECT_SAFETY,
hir::CRATE_HIR_ID,
span,
DelayDm(|| format!("the trait `{}` cannot be made into an object", tcx.def_path_str(trait_def_id))),
|err| {
let node = tcx.hir().get_if_local(trait_def_id);
let mut spans = MultiSpan::from_span(span);
if let Some(hir::Node::Item(item)) = node {
spans.push_span_label(
item.ident.span,
"this trait cannot be made into an object...",
);
spans.push_span_label(span, format!("...because {}", violation.error_msg()));
} else {
spans.push_span_label(
span,
format!(
"the trait cannot be made into an object because {}",
violation.error_msg()
),
);
};
err.span_note(
spans,
"for a trait to be \"object safe\" it needs to allow building a vtable to allow the \
call to be resolvable dynamically; for more information visit \
<https://doc.rust-lang.org/reference/items/traits.html#object-safety>",
);
};
err.span_note(
spans,
"for a trait to be \"object safe\" it needs to allow building a vtable to allow the \
call to be resolvable dynamically; for more information visit \
<https://doc.rust-lang.org/reference/items/traits.html#object-safety>",
);
if node.is_some() {
// Only provide the help if its a local trait, otherwise it's not
violation.solution(&mut err);
}
err.emit();
});
if node.is_some() {
// Only provide the help if its a local trait, otherwise it's not
violation.solution(err);
}
err
},
);
}
fn sized_trait_bound_spans<'tcx>(

View file

@ -6,6 +6,7 @@
//!
//! [rustc dev guide]:https://rustc-dev-guide.rust-lang.org/traits/resolution.html#candidate-assembly
use hir::LangItem;
use rustc_errors::DelayDm;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_infer::traits::ObligationCause;
@ -825,13 +826,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
DEREF_INTO_DYN_SUPERTRAIT,
obligation.cause.body_id,
obligation.cause.span,
|lint| {
lint.build(&format!(
"`{}` implements `Deref` with supertrait `{}` as output",
source,
deref_output_ty
)).emit();
},
DelayDm(|| format!(
"`{}` implements `Deref` with supertrait `{}` as output",
source, deref_output_ty
)),
|lint| lint,
);
return;
}

View file

@ -17,7 +17,7 @@ use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt};
use crate::traits::select::IntercrateAmbiguityCause;
use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause};
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_errors::{struct_span_err, EmissionGuarantee, LintDiagnosticBuilder};
use rustc_errors::{struct_span_err, DiagnosticBuilder, EmissionGuarantee};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::ty::{self, ImplSubject, TyCtxt};
use rustc_middle::ty::{InternalSubsts, SubstsRef};
@ -350,26 +350,12 @@ fn report_conflicting_impls(
// Work to be done after we've built the DiagnosticBuilder. We have to define it
// now because the struct_lint methods don't return back the DiagnosticBuilder
// that's passed in.
fn decorate<G: EmissionGuarantee>(
fn decorate<'a, 'b, G: EmissionGuarantee>(
tcx: TyCtxt<'_>,
overlap: OverlapError,
used_to_be_allowed: Option<FutureCompatOverlapErrorKind>,
impl_span: Span,
err: LintDiagnosticBuilder<'_, G>,
) -> G {
let msg = format!(
"conflicting implementations of trait `{}`{}{}",
overlap.trait_desc,
overlap
.self_desc
.clone()
.map_or_else(String::new, |ty| { format!(" for type `{}`", ty) }),
match used_to_be_allowed {
Some(FutureCompatOverlapErrorKind::Issue33140) => ": (E0119)",
_ => "",
}
);
let mut err = err.build(&msg);
err: &'b mut DiagnosticBuilder<'a, G>,
) -> &'b mut DiagnosticBuilder<'a, G> {
match tcx.span_of_impl(overlap.with_impl) {
Ok(span) => {
err.span_label(span, "first implementation here");
@ -384,7 +370,9 @@ fn report_conflicting_impls(
}
Err(cname) => {
let msg = match to_pretty_impl_header(tcx, overlap.with_impl) {
Some(s) => format!("conflicting implementation in crate `{}`:\n- {}", cname, s),
Some(s) => {
format!("conflicting implementation in crate `{}`:\n- {}", cname, s)
}
None => format!("conflicting implementation in crate `{}`", cname),
};
err.note(&msg);
@ -392,28 +380,33 @@ fn report_conflicting_impls(
}
for cause in &overlap.intercrate_ambiguity_causes {
cause.add_intercrate_ambiguity_hint(&mut err);
cause.add_intercrate_ambiguity_hint(err);
}
if overlap.involves_placeholder {
coherence::add_placeholder_note(&mut err);
coherence::add_placeholder_note(err);
}
err.emit()
err
}
let msg = format!(
"conflicting implementations of trait `{}`{}{}",
overlap.trait_desc,
overlap.self_desc.as_deref().map_or_else(String::new, |ty| format!(" for type `{ty}`")),
match used_to_be_allowed {
Some(FutureCompatOverlapErrorKind::Issue33140) => ": (E0119)",
_ => "",
}
);
match used_to_be_allowed {
None => {
let reported = if overlap.with_impl.is_local()
|| tcx.orphan_check_impl(impl_def_id).is_ok()
{
let err = struct_span_err!(tcx.sess, impl_span, E0119, "");
Some(decorate(
tcx,
overlap,
used_to_be_allowed,
impl_span,
LintDiagnosticBuilder::new(err),
))
let mut err = struct_span_err!(tcx.sess, impl_span, E0119, "{msg}",);
decorate(tcx, overlap, impl_span, &mut err);
Some(err.emit())
} else {
Some(tcx.sess.delay_span_bug(impl_span, "impl should have failed the orphan check"))
};
@ -428,9 +421,8 @@ fn report_conflicting_impls(
lint,
tcx.hir().local_def_id_to_hir_id(impl_def_id),
impl_span,
|ldb| {
decorate(tcx, overlap, used_to_be_allowed, impl_span, ldb);
},
msg,
|err| decorate(tcx, overlap, impl_span, err),
);
}
};