rust/src/librustc/traits/error_reporting.rs

1720 lines
74 KiB
Rust
Raw Normal View History

use super::{
FulfillmentError,
FulfillmentErrorCode,
MismatchedProjectionTypes,
Obligation,
ObligationCause,
ObligationCauseCode,
OnUnimplementedDirective,
OnUnimplementedNote,
OutputTypeParameterMismatch,
TraitNotObjectSafe,
ConstEvalFailure,
PredicateObligation,
SelectionContext,
SelectionError,
ObjectSafetyViolation,
Overflow,
};
2014-12-06 16:39:25 +00:00
2019-02-05 17:20:45 +00:00
use crate::hir;
use crate::hir::Node;
use crate::hir::def_id::DefId;
use crate::infer::{self, InferCtxt};
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
2019-02-05 17:20:45 +00:00
use crate::session::DiagnosticMessageId;
use crate::ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
use crate::ty::GenericParamDefKind;
use crate::ty::error::ExpectedFound;
use crate::ty::fast_reject;
use crate::ty::fold::TypeFolder;
use crate::ty::subst::Subst;
use crate::ty::SubtypePredicate;
use crate::util::nodemap::{FxHashMap, FxHashSet};
2019-02-09 02:24:02 +00:00
use errors::{Applicability, DiagnosticBuilder};
use std::fmt;
use syntax::ast;
use syntax::symbol::sym;
use syntax_pos::{DUMMY_SP, Span, ExpnInfo, ExpnKind};
2019-06-13 21:48:52 +00:00
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn report_fulfillment_errors(&self,
errors: &[FulfillmentError<'tcx>],
body_id: Option<hir::BodyId>,
fallback_has_occurred: bool) {
#[derive(Debug)]
struct ErrorDescriptor<'tcx> {
predicate: ty::Predicate<'tcx>,
index: Option<usize>, // None if this is an old error
}
2014-12-06 16:39:25 +00:00
let mut error_map: FxHashMap<_, Vec<_>> =
self.reported_trait_errors.borrow().iter().map(|(&span, predicates)| {
(span, predicates.iter().map(|predicate| ErrorDescriptor {
predicate: predicate.clone(),
index: None
}).collect())
}).collect();
for (index, error) in errors.iter().enumerate() {
// We want to ignore desugarings here: spans are equivalent even
// if one is the result of a desugaring and the other is not.
let mut span = error.obligation.cause.span;
if let Some(ExpnInfo { kind: ExpnKind::Desugaring(_), def_site, .. })
= span.ctxt().outer_expn_info() {
span = def_site;
}
error_map.entry(span).or_default().push(
ErrorDescriptor {
predicate: error.obligation.predicate.clone(),
index: Some(index)
}
);
self.reported_trait_errors.borrow_mut()
.entry(span).or_default()
.push(error.obligation.predicate.clone());
}
// We do this in 2 passes because we want to display errors in order, though
// maybe it *is* better to sort errors by span or something.
let mut is_suppressed = vec![false; errors.len()];
for (_, error_set) in error_map.iter() {
// We want to suppress "duplicate" errors with the same span.
for error in error_set {
if let Some(index) = error.index {
// Suppress errors that are either:
// 1) strictly implied by another error.
// 2) implied by an error with a smaller index.
for error2 in error_set {
if error2.index.map_or(false, |index2| is_suppressed[index2]) {
// Avoid errors being suppressed by already-suppressed
// errors, to prevent all errors from being suppressed
// at once.
continue
}
if self.error_implies(&error2.predicate, &error.predicate) &&
!(error2.index >= error.index &&
self.error_implies(&error.predicate, &error2.predicate))
{
info!("skipping {:?} (implied by {:?})", error, error2);
is_suppressed[index] = true;
break
2017-04-11 21:37:40 +00:00
}
}
}
2017-04-11 21:37:40 +00:00
}
}
for (error, suppressed) in errors.iter().zip(is_suppressed) {
if !suppressed {
self.report_fulfillment_error(error, body_id, fallback_has_occurred);
}
}
}
// returns if `cond` not occurring implies that `error` does not occur - i.e., that
2017-08-11 18:34:14 +00:00
// `error` occurring implies that `cond` occurs.
fn error_implies(&self,
cond: &ty::Predicate<'tcx>,
error: &ty::Predicate<'tcx>)
-> bool
{
if cond == error {
return true
2017-04-11 21:37:40 +00:00
}
let (cond, error) = match (cond, error) {
(&ty::Predicate::Trait(..), &ty::Predicate::Trait(ref error))
=> (cond, error),
_ => {
// FIXME: make this work in other cases too.
return false
}
};
for implication in super::elaborate_predicates(self.tcx, vec![cond.clone()]) {
if let ty::Predicate::Trait(implication) = implication {
let error = error.to_poly_trait_ref();
let implication = implication.to_poly_trait_ref();
// FIXME: I'm just not taking associated types at all here.
// Eventually I'll need to implement param-env-aware
// `Γ₁ ⊦ φ₁ => Γ₂ ⊦ φ₂` logic.
let param_env = ty::ParamEnv::empty();
if self.can_sub(param_env, error, implication).is_ok() {
debug!("error_implies: {:?} -> {:?} -> {:?}", cond, error, implication);
return true
}
}
}
false
2014-12-06 16:39:25 +00:00
}
fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>,
body_id: Option<hir::BodyId>,
fallback_has_occurred: bool) {
debug!("report_fulfillment_errors({:?})", error);
match error.code {
FulfillmentErrorCode::CodeSelectionError(ref e) => {
self.report_selection_error(&error.obligation, e, fallback_has_occurred);
}
FulfillmentErrorCode::CodeProjectionError(ref e) => {
self.report_projection_error(&error.obligation, e);
}
FulfillmentErrorCode::CodeAmbiguity => {
self.maybe_report_ambiguity(&error.obligation, body_id);
}
2017-03-10 02:47:09 +00:00
FulfillmentErrorCode::CodeSubtypeError(ref expected_found, ref err) => {
self.report_mismatched_types(&error.obligation.cause,
expected_found.expected,
expected_found.found,
err.clone())
.emit();
}
2014-12-06 16:39:25 +00:00
}
}
fn report_projection_error(&self,
obligation: &PredicateObligation<'tcx>,
error: &MismatchedProjectionTypes<'tcx>)
{
let predicate =
self.resolve_vars_if_possible(&obligation.predicate);
if predicate.references_error() {
return
}
self.probe(|_| {
let err_buf;
let mut err = &error.err;
let mut values = None;
// try to find the mismatched types to report the error with.
//
// this can fail if the problem was higher-ranked, in which
// cause I have no idea for a good error message.
if let ty::Predicate::Projection(ref data) = predicate {
let mut selcx = SelectionContext::new(self);
let (data, _) = self.replace_bound_vars_with_fresh_vars(
obligation.cause.span,
infer::LateBoundRegionConversionTime::HigherRankedType,
data
);
let mut obligations = vec![];
let normalized_ty = super::normalize_projection_type(
&mut selcx,
2017-05-23 08:19:47 +00:00
obligation.param_env,
data.projection_ty,
obligation.cause.clone(),
0,
&mut obligations
);
if let Err(error) = self.at(&obligation.cause, obligation.param_env)
.eq(normalized_ty, data.ty) {
values = Some(infer::ValuePairs::Types(ExpectedFound {
expected: normalized_ty,
found: data.ty,
}));
err_buf = error;
err = &err_buf;
}
}
let msg = format!("type mismatch resolving `{}`", predicate);
let error_id = (DiagnosticMessageId::ErrorId(271),
2018-10-25 18:11:11 +00:00
Some(obligation.cause.span), msg);
let fresh = self.tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id);
if fresh {
let mut diag = struct_span_err!(
self.tcx.sess, obligation.cause.span, E0271,
"type mismatch resolving `{}`", predicate
);
self.note_type_err(&mut diag, &obligation.cause, None, values, err);
self.note_obligation_cause(&mut diag, obligation);
diag.emit();
}
});
}
fn fuzzy_match_tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
/// returns the fuzzy category of a given type, or None
/// if the type can be equated to any type.
2019-06-21 16:12:39 +00:00
fn type_category(t: Ty<'_>) -> Option<u32> {
match t.sty {
ty::Bool => Some(0),
ty::Char => Some(1),
ty::Str => Some(2),
ty::Int(..) | ty::Uint(..) | ty::Infer(ty::IntVar(..)) => Some(3),
ty::Float(..) | ty::Infer(ty::FloatVar(..)) => Some(4),
ty::Ref(..) | ty::RawPtr(..) => Some(5),
ty::Array(..) | ty::Slice(..) => Some(6),
ty::FnDef(..) | ty::FnPtr(..) => Some(7),
ty::Dynamic(..) => Some(8),
ty::Closure(..) => Some(9),
ty::Tuple(..) => Some(10),
ty::Projection(..) => Some(11),
ty::Param(..) => Some(12),
ty::Opaque(..) => Some(13),
ty::Never => Some(14),
ty::Adt(adt, ..) => match adt.adt_kind() {
AdtKind::Struct => Some(15),
AdtKind::Union => Some(16),
AdtKind::Enum => Some(17),
},
ty::Generator(..) => Some(18),
ty::Foreign(..) => Some(19),
ty::GeneratorWitness(..) => Some(20),
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error => None,
ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
}
}
match (type_category(a), type_category(b)) {
(Some(cat_a), Some(cat_b)) => match (&a.sty, &b.sty) {
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => def_a == def_b,
_ => cat_a == cat_b
},
// infer and error can be equated to all types
_ => true
}
}
fn impl_similar_to(&self,
trait_ref: ty::PolyTraitRef<'tcx>,
obligation: &PredicateObligation<'tcx>)
-> Option<DefId>
{
let tcx = self.tcx;
2017-05-23 08:19:47 +00:00
let param_env = obligation.param_env;
let trait_ref = tcx.erase_late_bound_regions(&trait_ref);
let trait_self_ty = trait_ref.self_ty();
let mut self_match_impls = vec![];
let mut fuzzy_match_impls = vec![];
2016-05-16 20:16:52 +00:00
self.tcx.for_each_relevant_impl(
trait_ref.def_id, trait_self_ty, |def_id| {
let impl_substs = self.fresh_substs_for_item(obligation.cause.span, def_id);
let impl_trait_ref = tcx
.impl_trait_ref(def_id)
.unwrap()
.subst(tcx, impl_substs);
let impl_self_ty = impl_trait_ref.self_ty();
2016-05-16 20:16:52 +00:00
if let Ok(..) = self.can_eq(param_env, trait_self_ty, impl_self_ty) {
self_match_impls.push(def_id);
if trait_ref.substs.types().skip(1)
.zip(impl_trait_ref.substs.types().skip(1))
.all(|(u,v)| self.fuzzy_match_tys(u, v))
{
fuzzy_match_impls.push(def_id);
}
2016-05-11 12:33:14 +00:00
}
});
2016-05-11 12:33:14 +00:00
let impl_def_id = if self_match_impls.len() == 1 {
self_match_impls[0]
} else if fuzzy_match_impls.len() == 1 {
fuzzy_match_impls[0]
2016-05-16 20:16:52 +00:00
} else {
return None
};
if tcx.has_attr(impl_def_id, sym::rustc_on_unimplemented) {
Some(impl_def_id)
} else {
None
2016-05-11 12:33:14 +00:00
}
}
fn on_unimplemented_note(
&self,
trait_ref: ty::PolyTraitRef<'tcx>,
obligation: &PredicateObligation<'tcx>,
) -> OnUnimplementedNote {
let def_id = self.impl_similar_to(trait_ref, obligation)
.unwrap_or_else(|| trait_ref.def_id());
let trait_ref = *trait_ref.skip_binder();
let mut flags = vec![];
match obligation.cause.code {
ObligationCauseCode::BuiltinDerivedObligation(..) |
ObligationCauseCode::ImplDerivedObligation(..) => {}
_ => {
// this is a "direct", user-specified, rather than derived,
// obligation.
flags.push((sym::direct, None));
}
}
if let ObligationCauseCode::ItemObligation(item) = obligation.cause.code {
// FIXME: maybe also have some way of handling methods
// from other traits? That would require name resolution,
// which we might want to be some sort of hygienic.
//
// Currently I'm leaving it for what I need for `try`.
if self.tcx.trait_of_item(item) == Some(trait_ref.def_id) {
let method = self.tcx.item_name(item);
flags.push((sym::from_method, None));
flags.push((sym::from_method, Some(method.to_string())));
}
}
2018-10-11 00:30:10 +00:00
if let Some(t) = self.get_parent_trait_ref(&obligation.cause.code) {
flags.push((sym::parent_trait, Some(t)));
2018-10-11 00:30:10 +00:00
}
if let Some(k) = obligation.cause.span.desugaring_kind() {
flags.push((sym::from_desugaring, None));
flags.push((sym::from_desugaring, Some(format!("{:?}", k))));
}
let generics = self.tcx.generics_of(def_id);
let self_ty = trait_ref.self_ty();
// This is also included through the generics list as `Self`,
// but the parser won't allow you to use it
flags.push((sym::_Self, Some(self_ty.to_string())));
if let Some(def) = self_ty.ty_adt_def() {
// We also want to be able to select self's original
// signature with no type arguments resolved
flags.push((sym::_Self, Some(self.tcx.type_of(def.did).to_string())));
}
2018-05-10 22:02:41 +00:00
for param in generics.params.iter() {
let value = match param.kind {
GenericParamDefKind::Type { .. } |
GenericParamDefKind::Const => {
2018-05-14 11:49:32 +00:00
trait_ref.substs[param.index as usize].to_string()
2018-05-10 22:02:41 +00:00
},
2018-05-10 22:46:57 +00:00
GenericParamDefKind::Lifetime => continue,
2018-05-10 22:02:41 +00:00
};
let name = param.name.as_symbol();
2018-05-14 11:49:32 +00:00
flags.push((name, Some(value)));
}
2018-07-14 15:22:53 +00:00
if let Some(true) = self_ty.ty_adt_def().map(|def| def.did.is_local()) {
flags.push((sym::crate_local, None));
}
2018-10-22 16:21:55 +00:00
// Allow targeting all integers using `{integral}`, even if the exact type was resolved
if self_ty.is_integral() {
flags.push((sym::_Self, Some("{integral}".to_owned())));
}
if let ty::Array(aty, len) = self_ty.sty {
flags.push((sym::_Self, Some("[]".to_owned())));
flags.push((sym::_Self, Some(format!("[{}]", aty))));
if let Some(def) = aty.ty_adt_def() {
// We also want to be able to select the array's type's original
// signature with no type arguments resolved
flags.push((
sym::_Self,
Some(format!("[{}]", self.tcx.type_of(def.did).to_string())),
));
2018-10-15 17:12:29 +00:00
let tcx = self.tcx;
if let Some(len) = len.try_eval_usize(tcx) {
flags.push((
sym::_Self,
Some(format!("[{}; {}]", self.tcx.type_of(def.did).to_string(), len)),
));
} else {
flags.push((
sym::_Self,
Some(format!("[{}; _]", self.tcx.type_of(def.did).to_string())),
));
}
}
}
if let Ok(Some(command)) = OnUnimplementedDirective::of_item(
self.tcx, trait_ref.def_id, def_id
) {
command.evaluate(self.tcx, trait_ref, &flags[..])
} else {
OnUnimplementedNote::empty()
}
2015-01-11 19:03:20 +00:00
}
2016-05-11 12:33:14 +00:00
fn find_similar_impl_candidates(&self,
trait_ref: ty::PolyTraitRef<'tcx>)
-> Vec<ty::TraitRef<'tcx>>
{
let simp = fast_reject::simplify_type(self.tcx,
trait_ref.skip_binder().self_ty(),
true);
let all_impls = self.tcx.all_impls(trait_ref.def_id());
2016-05-11 12:33:14 +00:00
match simp {
Some(simp) => all_impls.iter().filter_map(|&def_id| {
2016-05-11 12:33:14 +00:00
let imp = self.tcx.impl_trait_ref(def_id).unwrap();
let imp_simp = fast_reject::simplify_type(self.tcx,
imp.self_ty(),
true);
if let Some(imp_simp) = imp_simp {
if simp != imp_simp {
return None
2016-05-11 12:33:14 +00:00
}
}
Some(imp)
}).collect(),
None => all_impls.iter().map(|&def_id|
self.tcx.impl_trait_ref(def_id).unwrap()
).collect()
}
2016-05-11 12:33:14 +00:00
}
fn report_similar_impl_candidates(&self,
impl_candidates: Vec<ty::TraitRef<'tcx>>,
err: &mut DiagnosticBuilder<'_>)
{
if impl_candidates.is_empty() {
return;
}
let len = impl_candidates.len();
let end = if impl_candidates.len() <= 5 {
impl_candidates.len()
} else {
4
};
let normalize = |candidate| self.tcx.global_tcx().infer_ctxt().enter(|ref infcx| {
let normalized = infcx
.at(&ObligationCause::dummy(), ty::ParamEnv::empty())
.normalize(candidate)
.ok();
match normalized {
Some(normalized) => format!("\n {:?}", normalized.value),
None => format!("\n {:?}", candidate),
}
});
// Sort impl candidates so that ordering is consistent for UI tests.
let mut normalized_impl_candidates = impl_candidates
.iter()
.map(normalize)
.collect::<Vec<String>>();
// Sort before taking the `..end` range,
// because the ordering of `impl_candidates` may not be deterministic:
// https://github.com/rust-lang/rust/pull/57475#issuecomment-455519507
normalized_impl_candidates.sort();
err.help(&format!("the following implementations were found:{}{}",
normalized_impl_candidates[..end].join(""),
if len > 5 {
format!("\nand {} others", len - 4)
} else {
String::new()
}
));
}
/// Reports that an overflow has occurred and halts compilation. We
/// halt compilation unconditionally because it is important that
/// overflows never be masked -- they basically represent computations
/// whose result could not be truly determined and thus we can't say
/// if the program type checks or not -- and they are unusual
/// occurrences in any case.
pub fn report_overflow_error<T>(&self,
obligation: &Obligation<'tcx, T>,
suggest_increasing_limit: bool) -> !
where T: fmt::Display + TypeFoldable<'tcx>
{
let predicate =
self.resolve_vars_if_possible(&obligation.predicate);
let mut err = struct_span_err!(self.tcx.sess, obligation.cause.span, E0275,
"overflow evaluating the requirement `{}`",
predicate);
if suggest_increasing_limit {
self.suggest_new_overflow_limit(&mut err);
}
self.note_obligation_cause(&mut err, obligation);
err.emit();
self.tcx.sess.abort_if_errors();
bug!();
}
/// Reports that a cycle was detected which led to overflow and halts
/// compilation. This is equivalent to `report_overflow_error` except
/// that we can give a more helpful error message (and, in particular,
/// we do not suggest increasing the overflow limit, which is not
/// going to help).
pub fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! {
let cycle = self.resolve_vars_if_possible(&cycle.to_owned());
2016-05-07 21:52:45 +00:00
assert!(cycle.len() > 0);
debug!("report_overflow_error_cycle: cycle={:?}", cycle);
self.report_overflow_error(&cycle[0], false);
}
pub fn report_extra_impl_obligation(&self,
error_span: Span,
item_name: ast::Name,
_impl_item_def_id: DefId,
trait_item_def_id: DefId,
2018-02-23 17:53:00 +00:00
requirement: &dyn fmt::Display)
-> DiagnosticBuilder<'tcx>
{
rustc: Rearchitect lints to be emitted more eagerly In preparation for incremental compilation this commit refactors the lint handling infrastructure in the compiler to be more "eager" and overall more incremental-friendly. Many passes of the compiler can emit lints at various points but before this commit all lints were buffered in a table to be emitted at the very end of compilation. This commit changes these lints to be emitted immediately during compilation using pre-calculated lint level-related data structures. Linting today is split into two phases, one set of "early" lints run on the `syntax::ast` and a "late" set of lints run on the HIR. This commit moves the "early" lints to running as late as possible in compilation, just before HIR lowering. This notably means that we're catching resolve-related lints just before HIR lowering. The early linting remains a pass very similar to how it was before, maintaining context of the current lint level as it walks the tree. Post-HIR, however, linting is structured as a method on the `TyCtxt` which transitively executes a query to calculate lint levels. Each request to lint on a `TyCtxt` will query the entire crate's 'lint level data structure' and then go from there about whether the lint should be emitted or not. The query depends on the entire HIR crate but should be very quick to calculate (just a quick walk of the HIR) and the red-green system should notice that the lint level data structure rarely changes, and should hopefully preserve incrementality. Overall this resulted in a pretty big change to the test suite now that lints are emitted much earlier in compilation (on-demand vs only at the end). This in turn necessitated the addition of many `#![allow(warnings)]` directives throughout the compile-fail test suite and a number of updates to the UI test suite.
2017-07-27 04:51:09 +00:00
let msg = "impl has stricter requirements than trait";
2018-08-18 10:14:09 +00:00
let sp = self.tcx.sess.source_map().def_span(error_span);
let mut err = struct_span_err!(self.tcx.sess, sp, E0276, "{}", msg);
if let Some(trait_item_span) = self.tcx.hir().span_if_local(trait_item_def_id) {
2018-08-18 10:14:09 +00:00
let span = self.tcx.sess.source_map().def_span(trait_item_span);
err.span_label(span, format!("definition of `{}` from trait", item_name));
}
err.span_label(sp, format!("impl has extra requirement {}", requirement));
err
}
2016-12-12 22:51:40 +00:00
2019-02-08 13:53:55 +00:00
/// Gets the parent trait chain start
2016-12-12 22:51:40 +00:00
fn get_parent_trait_ref(&self, code: &ObligationCauseCode<'tcx>) -> Option<String> {
match code {
&ObligationCauseCode::BuiltinDerivedObligation(ref data) => {
let parent_trait_ref = self.resolve_vars_if_possible(
2016-12-12 22:51:40 +00:00
&data.parent_trait_ref);
match self.get_parent_trait_ref(&data.parent_code) {
Some(t) => Some(t),
2018-07-27 09:11:18 +00:00
None => Some(parent_trait_ref.skip_binder().self_ty().to_string()),
2016-12-12 22:51:40 +00:00
}
}
_ => None,
}
}
pub fn report_selection_error(
&self,
obligation: &PredicateObligation<'tcx>,
error: &SelectionError<'tcx>,
fallback_has_occurred: bool,
) {
let span = obligation.cause.span;
2016-12-12 22:51:40 +00:00
let mut err = match *error {
SelectionError::Unimplemented => {
if let ObligationCauseCode::CompareImplMethodObligation {
item_name, impl_item_def_id, trait_item_def_id,
} = obligation.cause.code {
self.report_extra_impl_obligation(
span,
item_name,
impl_item_def_id,
trait_item_def_id,
&format!("`{}`", obligation.predicate))
.emit();
return;
2017-02-19 03:48:36 +00:00
}
match obligation.predicate {
ty::Predicate::Trait(ref trait_predicate) => {
let trait_predicate =
self.resolve_vars_if_possible(trait_predicate);
2017-02-19 03:48:36 +00:00
if self.tcx.sess.has_errors() && trait_predicate.references_error() {
return;
2017-02-19 15:46:43 +00:00
}
let trait_ref = trait_predicate.to_poly_trait_ref();
let (post_message, pre_message) =
self.get_parent_trait_ref(&obligation.cause.code)
.map(|t| (format!(" in `{}`", t), format!("within `{}`, ", t)))
.unwrap_or_default();
let OnUnimplementedNote { message, label, note }
= self.on_unimplemented_note(trait_ref, obligation);
let have_alt_message = message.is_some() || label.is_some();
let is_try = self.tcx.sess.source_map().span_to_snippet(span)
.map(|s| &s == "?")
.unwrap_or(false);
let is_from = format!("{}", trait_ref).starts_with("std::convert::From<");
let (message, note) = if is_try && is_from {
(Some(format!(
"`?` couldn't convert the error to `{}`",
trait_ref.self_ty(),
)), Some(
"the question mark operation (`?`) implicitly performs a \
conversion on the error value using the `From` trait".to_owned()
))
} else {
(message, note)
};
2017-02-19 15:46:43 +00:00
let mut err = struct_span_err!(
self.tcx.sess,
span,
E0277,
"{}",
message.unwrap_or_else(||
format!("the trait bound `{}` is not satisfied{}",
trait_ref.to_predicate(), post_message)
));
2017-02-19 15:46:43 +00:00
let explanation =
if obligation.cause.code == ObligationCauseCode::MainFunctionType {
"consider using `()`, or a `Result`".to_owned()
} else {
format!("{}the trait `{}` is not implemented for `{}`",
pre_message,
trait_ref,
trait_ref.self_ty())
};
if let Some(ref s) = label {
// If it has a custom `#[rustc_on_unimplemented]`
// error message, let's display it as the label!
err.span_label(span, s.as_str());
err.help(&explanation);
} else {
err.span_label(span, explanation);
}
if let Some(ref s) = note {
// If it has a custom `#[rustc_on_unimplemented]` note, let's display it
err.note(s.as_str());
}
self.suggest_borrow_on_unsized_slice(&obligation.cause.code, &mut err);
self.suggest_remove_reference(&obligation, &mut err, &trait_ref);
self.suggest_semicolon_removal(&obligation, &mut err, span, &trait_ref);
2017-02-19 15:46:43 +00:00
// Try to report a help message
if !trait_ref.has_infer_types() &&
2017-05-23 08:19:47 +00:00
self.predicate_can_apply(obligation.param_env, trait_ref) {
2017-02-19 15:46:43 +00:00
// If a where-clause may be useful, remind the
// user that they can add it.
//
// don't display an on-unimplemented note, as
// these notes will often be of the form
// "the type `T` can't be frobnicated"
// which is somewhat confusing.
err.help(&format!("consider adding a `where {}` bound",
trait_ref.to_predicate()));
} else if !have_alt_message {
// Can't show anything else useful, try to find similar impls.
let impl_candidates = self.find_similar_impl_candidates(trait_ref);
self.report_similar_impl_candidates(impl_candidates, &mut err);
}
2018-03-14 04:03:33 +00:00
// If this error is due to `!: Trait` not implemented but `(): Trait` is
2018-08-19 13:30:23 +00:00
// implemented, and fallback has occurred, then it could be due to a
2018-03-14 04:03:33 +00:00
// variable that used to fallback to `()` now falling back to `!`. Issue a
// note informing about the change in behaviour.
if trait_predicate.skip_binder().self_ty().is_never()
&& fallback_has_occurred
{
let predicate = trait_predicate.map_bound(|mut trait_pred| {
trait_pred.trait_ref.substs = self.tcx.mk_substs_trait(
2018-09-10 02:07:13 +00:00
self.tcx.mk_unit(),
&trait_pred.trait_ref.substs[1..],
);
trait_pred
});
let unit_obligation = Obligation {
2018-03-14 04:03:33 +00:00
predicate: ty::Predicate::Trait(predicate),
.. obligation.clone()
};
if self.predicate_may_hold(&unit_obligation) {
err.note("the trait is implemented for `()`. \
Possibly this error has been caused by changes to \
Rust's type-inference algorithm \
(see: https://github.com/rust-lang/rust/issues/48950 \
for more info). Consider whether you meant to use the \
type `()` here instead.");
}
}
2017-02-19 15:46:43 +00:00
err
2017-02-19 03:48:36 +00:00
}
2017-03-10 02:47:09 +00:00
ty::Predicate::Subtype(ref predicate) => {
// Errors for Subtype predicates show up as
// `FulfillmentErrorCode::CodeSubtypeError`,
// not selection error.
span_bug!(span, "subtype requirement gave wrong error: `{:?}`", predicate)
2017-03-10 02:47:09 +00:00
}
2017-02-19 03:48:36 +00:00
ty::Predicate::RegionOutlives(ref predicate) => {
let predicate = self.resolve_vars_if_possible(predicate);
let err = self.region_outlives_predicate(&obligation.cause,
&predicate).err().unwrap();
struct_span_err!(
self.tcx.sess, span, E0279,
"the requirement `{}` is not satisfied (`{}`)",
predicate, err,
)
2017-02-19 03:48:36 +00:00
}
2017-02-19 03:48:36 +00:00
ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => {
let predicate =
self.resolve_vars_if_possible(&obligation.predicate);
2017-02-19 03:48:36 +00:00
struct_span_err!(self.tcx.sess, span, E0280,
"the requirement `{}` is not satisfied",
predicate)
}
2017-02-19 03:48:36 +00:00
ty::Predicate::ObjectSafe(trait_def_id) => {
let violations = self.tcx.global_tcx()
.object_safety_violations(trait_def_id);
if let Some(err) = self.tcx.report_object_safety_error(
span,
trait_def_id,
violations,
) {
err
} else {
return;
}
2017-02-19 03:48:36 +00:00
}
ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
let found_kind = self.closure_kind(closure_def_id, closure_substs).unwrap();
2018-08-18 10:14:09 +00:00
let closure_span = self.tcx.sess.source_map()
.def_span(self.tcx.hir().span_if_local(closure_def_id).unwrap());
let hir_id = self.tcx.hir().as_local_hir_id(closure_def_id).unwrap();
2017-02-19 03:48:36 +00:00
let mut err = struct_span_err!(
self.tcx.sess, closure_span, E0525,
"expected a closure that implements the `{}` trait, \
but this closure only implements `{}`",
2017-02-19 03:48:36 +00:00
kind,
found_kind);
err.span_label(
closure_span,
format!("this closure implements `{}`, not `{}`", found_kind, kind));
2017-06-07 20:26:28 +00:00
err.span_label(
obligation.cause.span,
format!("the requirement to implement `{}` derives from here", kind));
// Additional context information explaining why the closure only implements
// a particular trait.
if let Some(tables) = self.in_progress_tables {
let tables = tables.borrow();
match (found_kind, tables.closure_kind_origins().get(hir_id)) {
(ty::ClosureKind::FnOnce, Some((span, name))) => {
err.span_label(*span, format!(
"closure is `FnOnce` because it moves the \
variable `{}` out of its environment", name));
},
(ty::ClosureKind::FnMut, Some((span, name))) => {
err.span_label(*span, format!(
"closure is `FnMut` because it mutates the \
variable `{}` here", name));
},
_ => {}
}
}
2017-02-19 03:48:36 +00:00
err.emit();
return;
}
2017-02-19 03:48:36 +00:00
ty::Predicate::WellFormed(ty) => {
2018-11-24 19:18:16 +00:00
if !self.tcx.sess.opts.debugging_opts.chalk {
// WF predicates cannot themselves make
// errors. They can only block due to
// ambiguity; otherwise, they always
// degenerate into other obligations
// (which may fail).
span_bug!(span, "WF predicate not satisfied for {:?}", ty);
} else {
// FIXME: we'll need a better message which takes into account
// which bounds actually failed to hold.
self.tcx.sess.struct_span_err(
span,
&format!("the type `{}` is not well-formed (chalk)", ty)
)
}
}
ty::Predicate::ConstEvaluatable(..) => {
// Errors for `ConstEvaluatable` predicates show up as
// `SelectionError::ConstEvalFailure`,
// not `Unimplemented`.
span_bug!(span,
"const-evaluatable requirement gave wrong error: `{:?}`", obligation)
}
2014-12-06 16:39:25 +00:00
}
}
2017-10-06 15:26:41 +00:00
OutputTypeParameterMismatch(ref found_trait_ref, ref expected_trait_ref, _) => {
let found_trait_ref = self.resolve_vars_if_possible(&*found_trait_ref);
let expected_trait_ref = self.resolve_vars_if_possible(&*expected_trait_ref);
2017-10-06 15:26:41 +00:00
if expected_trait_ref.self_ty().references_error() {
return;
}
2017-10-06 15:26:41 +00:00
let found_trait_ty = found_trait_ref.self_ty();
2018-07-14 15:22:53 +00:00
let found_did = match found_trait_ty.sty {
ty::Closure(did, _) | ty::Foreign(did) | ty::FnDef(did, _) => Some(did),
ty::Adt(def, _) => Some(def.did),
2018-07-14 15:22:53 +00:00
_ => None,
};
let found_span = found_did.and_then(|did|
self.tcx.hir().span_if_local(did)
).map(|sp| self.tcx.sess.source_map().def_span(sp)); // the sp could be an fn def
2017-04-24 00:54:32 +00:00
let found = match found_trait_ref.skip_binder().substs.type_at(1).sty {
ty::Tuple(ref tys) => vec![ArgKind::empty(); tys.len()],
_ => vec![ArgKind::empty()],
};
let expected_ty = expected_trait_ref.skip_binder().substs.type_at(1);
let expected = match expected_ty.sty {
ty::Tuple(ref tys) => tys.iter()
2019-04-25 23:27:33 +00:00
.map(|t| ArgKind::from_expected_ty(t.expect_ty(), Some(span))).collect(),
_ => vec![ArgKind::Arg("_".to_owned(), expected_ty.to_string())],
};
if found.len() == expected.len() {
self.report_closure_arg_mismatch(span,
found_span,
2017-10-06 15:26:41 +00:00
found_trait_ref,
expected_trait_ref)
2017-04-23 22:36:35 +00:00
} else {
let (closure_span, found) = found_did
.and_then(|did| self.tcx.hir().get_if_local(did))
.map(|node| {
let (found_span, found) = self.get_fn_like_arguments(node);
(Some(found_span), found)
}).unwrap_or((found_span, found));
self.report_arg_count_mismatch(span,
closure_span,
expected,
found,
found_trait_ty.is_closure())
2017-04-23 22:36:35 +00:00
}
}
TraitNotObjectSafe(did) => {
let violations = self.tcx.global_tcx().object_safety_violations(did);
if let Some(err) = self.tcx.report_object_safety_error(span, did, violations) {
err
} else {
return;
}
}
// already reported in the query
ConstEvalFailure(err) => {
self.tcx.sess.delay_span_bug(
span,
&format!("constant in type had an ignored error: {:?}", err),
);
return;
}
Overflow => {
bug!("overflow should be handled before the `report_selection_error` path");
}
};
self.note_obligation_cause(&mut err, obligation);
err.emit();
}
2017-04-24 00:54:32 +00:00
/// When encountering an assignment of an unsized trait, like `let x = ""[..];`, provide a
/// suggestion to borrow the initializer in order to use have a slice instead.
fn suggest_borrow_on_unsized_slice(
&self,
code: &ObligationCauseCode<'tcx>,
err: &mut DiagnosticBuilder<'tcx>,
) {
if let &ObligationCauseCode::VariableType(hir_id) = code {
let parent_node = self.tcx.hir().get_parent_node(hir_id);
2019-06-24 07:58:49 +00:00
if let Some(Node::Local(ref local)) = self.tcx.hir().find(parent_node) {
if let Some(ref expr) = local.init {
2018-07-11 12:05:29 +00:00
if let hir::ExprKind::Index(_, _) = expr.node {
2018-08-18 10:14:09 +00:00
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(expr.span) {
err.span_suggestion(
suggestion applicabilities for libsyntax and librustc, run-rustfix tests Consider this a down payment on #50723. To recap, an `Applicability` enum was recently (#50204) added, to convey to Rustfix and other tools whether we think it's OK for them to blindly apply the suggestion, or whether to prompt a human for guidance (because the suggestion might contain placeholders that we can't infer, or because we think it has a sufficiently high probability of being wrong even though it's— presumably—right often enough to be worth emitting in the first place). When a suggestion is marked as `MaybeIncorrect`, we try to use comments to indicate precisely why (although there are a few places where we just say `// speculative` because the present author's subjective judgement balked at the idea that the suggestion has no false positives). The `run-rustfix` directive is opporunistically set on some relevant UI tests (and a couple tests that were in the `test/ui/suggestions` directory, even if the suggestions didn't originate in librustc or libsyntax). This is less trivial than it sounds, because a surprising number of test files aren't equipped to be tested as fixed even when they contain successfully fixable errors, because, e.g., there are more, not-directly-related errors after fixing. Some test files need an attribute or underscore to avoid unused warnings tripping up the "fixed code is still producing diagnostics" check despite the fixes being correct; this is an interesting contrast-to/inconsistency-with the behavior of UI tests (which secretly pass `-A unused`), a behavior which we probably ought to resolve one way or the other (filed issue #50926). A few suggestion labels are reworded (e.g., to avoid phrasing it as a question, which which is discouraged by the style guidelines listed in `.span_suggestion`'s doc-comment).
2018-05-19 21:52:24 +00:00
expr.span,
"consider borrowing here",
format!("&{}", snippet),
Applicability::MachineApplicable
);
}
}
}
}
}
}
/// Whenever references are used by mistake, like `for (i, e) in &vec.iter().enumerate()`,
/// suggest removing these references until we reach a type that implements the trait.
fn suggest_remove_reference(
&self,
obligation: &PredicateObligation<'tcx>,
err: &mut DiagnosticBuilder<'tcx>,
trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
) {
let trait_ref = trait_ref.skip_binder();
let span = obligation.cause.span;
2018-08-18 10:14:09 +00:00
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
2018-03-11 05:21:38 +00:00
let refs_number = snippet.chars()
.filter(|c| !c.is_whitespace())
.take_while(|c| *c == '&')
.count();
2018-03-11 05:21:38 +00:00
let mut trait_type = trait_ref.self_ty();
for refs_remaining in 0..refs_number {
2018-08-22 01:08:01 +00:00
if let ty::Ref(_, t_type, _) = trait_type.sty {
trait_type = t_type;
let substs = self.tcx.mk_substs_trait(trait_type, &[]);
let new_trait_ref = ty::TraitRef::new(trait_ref.def_id, substs);
let new_obligation = Obligation::new(ObligationCause::dummy(),
obligation.param_env,
new_trait_ref.to_predicate());
if self.predicate_may_hold(&new_obligation) {
2018-08-18 10:14:09 +00:00
let sp = self.tcx.sess.source_map()
.span_take_while(span, |c| c.is_whitespace() || *c == '&');
2018-03-11 05:21:38 +00:00
let remove_refs = refs_remaining + 1;
let format_str = format!("consider removing {} leading `&`-references",
remove_refs);
2018-03-11 05:21:38 +00:00
err.span_suggestion_short(
sp, &format_str, String::new(), Applicability::MachineApplicable
suggestion applicabilities for libsyntax and librustc, run-rustfix tests Consider this a down payment on #50723. To recap, an `Applicability` enum was recently (#50204) added, to convey to Rustfix and other tools whether we think it's OK for them to blindly apply the suggestion, or whether to prompt a human for guidance (because the suggestion might contain placeholders that we can't infer, or because we think it has a sufficiently high probability of being wrong even though it's— presumably—right often enough to be worth emitting in the first place). When a suggestion is marked as `MaybeIncorrect`, we try to use comments to indicate precisely why (although there are a few places where we just say `// speculative` because the present author's subjective judgement balked at the idea that the suggestion has no false positives). The `run-rustfix` directive is opporunistically set on some relevant UI tests (and a couple tests that were in the `test/ui/suggestions` directory, even if the suggestions didn't originate in librustc or libsyntax). This is less trivial than it sounds, because a surprising number of test files aren't equipped to be tested as fixed even when they contain successfully fixable errors, because, e.g., there are more, not-directly-related errors after fixing. Some test files need an attribute or underscore to avoid unused warnings tripping up the "fixed code is still producing diagnostics" check despite the fixes being correct; this is an interesting contrast-to/inconsistency-with the behavior of UI tests (which secretly pass `-A unused`), a behavior which we probably ought to resolve one way or the other (filed issue #50926). A few suggestion labels are reworded (e.g., to avoid phrasing it as a question, which which is discouraged by the style guidelines listed in `.span_suggestion`'s doc-comment).
2018-05-19 21:52:24 +00:00
);
2018-03-11 05:21:38 +00:00
break;
}
} else {
break;
}
2018-03-11 05:21:38 +00:00
}
}
}
fn suggest_semicolon_removal(
&self,
obligation: &PredicateObligation<'tcx>,
err: &mut DiagnosticBuilder<'tcx>,
span: Span,
trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
) {
let hir = self.tcx.hir();
let parent_node = hir.get_parent_node(obligation.cause.body_id);
2019-06-24 07:58:49 +00:00
let node = hir.find(parent_node);
if let Some(hir::Node::Item(hir::Item {
node: hir::ItemKind::Fn(decl, _, _, body_id),
..
})) = node {
let body = hir.body(*body_id);
if let hir::ExprKind::Block(blk, _) = &body.value.node {
if decl.output.span().overlaps(span) && blk.expr.is_none() &&
"()" == &trait_ref.self_ty().to_string()
{
// FIXME(estebank): When encountering a method with a trait
// bound not satisfied in the return type with a body that has
// no return, suggest removal of semicolon on last statement.
// Once that is added, close #54771.
if let Some(ref stmt) = blk.stmts.last() {
let sp = self.tcx.sess.source_map().end_point(stmt.span);
err.span_label(sp, "consider removing this semicolon");
}
}
}
}
}
/// Given some node representing a fn-like thing in the HIR map,
/// returns a span and `ArgKind` information that describes the
/// arguments it expects. This can be supplied to
/// `report_arg_count_mismatch`.
pub fn get_fn_like_arguments(&self, node: Node<'_>) -> (Span, Vec<ArgKind>) {
match node {
2018-08-25 14:56:16 +00:00
Node::Expr(&hir::Expr {
2018-07-11 12:05:29 +00:00
node: hir::ExprKind::Closure(_, ref _decl, id, span, _),
..
}) => {
(self.tcx.sess.source_map().def_span(span), self.tcx.hir().body(id).arguments.iter()
.map(|arg| {
if let hir::Pat {
2019-06-12 08:43:15 +00:00
node: hir::PatKind::Tuple(ref args, _),
span,
..
2019-06-12 08:43:15 +00:00
} = *arg.pat {
ArgKind::Tuple(
Some(span),
args.iter().map(|pat| {
2018-08-18 10:14:09 +00:00
let snippet = self.tcx.sess.source_map()
.span_to_snippet(pat.span).unwrap();
(snippet, "_".to_owned())
}).collect::<Vec<_>>(),
)
} else {
2018-08-18 10:14:09 +00:00
let name = self.tcx.sess.source_map()
.span_to_snippet(arg.pat.span).unwrap();
ArgKind::Arg(name, "_".to_owned())
}
})
.collect::<Vec<ArgKind>>())
}
2018-08-25 14:56:16 +00:00
Node::Item(&hir::Item {
span,
2018-07-11 15:36:06 +00:00
node: hir::ItemKind::Fn(ref decl, ..),
..
}) |
2018-08-25 14:56:16 +00:00
Node::ImplItem(&hir::ImplItem {
span,
node: hir::ImplItemKind::Method(hir::MethodSig { ref decl, .. }, _),
..
}) |
2018-08-25 14:56:16 +00:00
Node::TraitItem(&hir::TraitItem {
span,
node: hir::TraitItemKind::Method(hir::MethodSig { ref decl, .. }, _),
..
}) => {
2018-08-18 10:14:09 +00:00
(self.tcx.sess.source_map().def_span(span), decl.inputs.iter()
.map(|arg| match arg.clone().node {
2018-07-11 14:41:03 +00:00
hir::TyKind::Tup(ref tys) => ArgKind::Tuple(
Some(arg.span),
vec![("_".to_owned(), "_".to_owned()); tys.len()]
),
_ => ArgKind::empty()
}).collect::<Vec<ArgKind>>())
}
Node::Ctor(ref variant_data) => {
let span = variant_data.ctor_hir_id()
.map(|hir_id| self.tcx.hir().span(hir_id))
.unwrap_or(DUMMY_SP);
let span = self.tcx.sess.source_map().def_span(span);
(span, vec![ArgKind::empty(); variant_data.fields().len()])
}
_ => panic!("non-FnLike node found: {:?}", node),
}
}
/// Reports an error when the number of arguments needed by a
/// trait match doesn't match the number that the expression
/// provides.
pub fn report_arg_count_mismatch(
2017-10-07 06:12:56 +00:00
&self,
span: Span,
found_span: Option<Span>,
expected_args: Vec<ArgKind>,
found_args: Vec<ArgKind>,
is_closure: bool,
2017-10-07 06:12:56 +00:00
) -> DiagnosticBuilder<'tcx> {
let kind = if is_closure { "closure" } else { "function" };
let args_str = |arguments: &[ArgKind], other: &[ArgKind]| {
let arg_length = arguments.len();
let distinct = match &other[..] {
&[ArgKind::Tuple(..)] => true,
_ => false,
};
match (arg_length, arguments.get(0)) {
(1, Some(&ArgKind::Tuple(_, ref fields))) => {
format!("a single {}-tuple as argument", fields.len())
}
_ => format!("{} {}argument{}",
arg_length,
if distinct && arg_length > 1 { "distinct " } else { "" },
if arg_length == 1 { "" } else { "s" }),
2017-10-13 00:56:50 +00:00
}
};
let expected_str = args_str(&expected_args, &found_args);
let found_str = args_str(&found_args, &expected_args);
2017-10-13 00:56:50 +00:00
let mut err = struct_span_err!(
self.tcx.sess,
span,
E0593,
2017-10-10 02:03:23 +00:00
"{} is expected to take {}, but it takes {}",
kind,
2017-10-13 00:56:50 +00:00
expected_str,
found_str,
2017-10-10 02:03:23 +00:00
);
err.span_label(span, format!("expected {} that takes {}", kind, expected_str));
if let Some(found_span) = found_span {
2018-07-23 14:45:37 +00:00
err.span_label(found_span, format!("takes {}", found_str));
2018-11-15 08:35:23 +00:00
// move |_| { ... }
// ^^^^^^^^-- def_span
//
// move |_| { ... }
// ^^^^^-- prefix
let prefix_span = self.tcx.sess.source_map().span_until_non_whitespace(found_span);
2018-11-15 08:35:23 +00:00
// move |_| { ... }
// ^^^-- pipe_span
let pipe_span = if let Some(span) = found_span.trim_start(prefix_span) {
span
} else {
found_span
};
// Suggest to take and ignore the arguments with expected_args_length `_`s if
2018-07-25 01:30:10 +00:00
// found arguments is empty (assume the user just wants to ignore args in this case).
// For example, if `expected_args_length` is 2, suggest `|_, _|`.
if found_args.is_empty() && is_closure {
let underscores = vec!["_"; expected_args.len()].join(", ");
err.span_suggestion(
2018-11-15 08:35:23 +00:00
pipe_span,
2018-07-25 01:30:10 +00:00
&format!(
"consider changing the closure to take and ignore the expected argument{}",
if expected_args.len() < 2 {
""
} else {
"s"
}
2018-07-23 14:45:37 +00:00
),
format!("|{}|", underscores),
2018-07-23 14:45:37 +00:00
Applicability::MachineApplicable,
);
}
if let &[ArgKind::Tuple(_, ref fields)] = &found_args[..] {
if fields.len() == expected_args.len() {
let sugg = fields.iter()
.map(|(name, _)| name.to_owned())
.collect::<Vec<String>>()
.join(", ");
err.span_suggestion(
found_span,
"change the closure to take multiple arguments instead of a single tuple",
format!("|{}|", sugg),
Applicability::MachineApplicable,
);
}
}
if let &[ArgKind::Tuple(_, ref fields)] = &expected_args[..] {
if fields.len() == found_args.len() && is_closure {
let sugg = format!(
"|({}){}|",
found_args.iter()
.map(|arg| match arg {
ArgKind::Arg(name, _) => name.to_owned(),
_ => "_".to_owned(),
})
.collect::<Vec<String>>()
.join(", "),
// add type annotations if available
if found_args.iter().any(|arg| match arg {
ArgKind::Arg(_, ty) => ty != "_",
_ => false,
}) {
format!(": ({})",
fields.iter()
.map(|(_, ty)| ty.to_owned())
.collect::<Vec<String>>()
.join(", "))
} else {
String::new()
},
);
err.span_suggestion(
suggestion applicabilities for libsyntax and librustc, run-rustfix tests Consider this a down payment on #50723. To recap, an `Applicability` enum was recently (#50204) added, to convey to Rustfix and other tools whether we think it's OK for them to blindly apply the suggestion, or whether to prompt a human for guidance (because the suggestion might contain placeholders that we can't infer, or because we think it has a sufficiently high probability of being wrong even though it's— presumably—right often enough to be worth emitting in the first place). When a suggestion is marked as `MaybeIncorrect`, we try to use comments to indicate precisely why (although there are a few places where we just say `// speculative` because the present author's subjective judgement balked at the idea that the suggestion has no false positives). The `run-rustfix` directive is opporunistically set on some relevant UI tests (and a couple tests that were in the `test/ui/suggestions` directory, even if the suggestions didn't originate in librustc or libsyntax). This is less trivial than it sounds, because a surprising number of test files aren't equipped to be tested as fixed even when they contain successfully fixable errors, because, e.g., there are more, not-directly-related errors after fixing. Some test files need an attribute or underscore to avoid unused warnings tripping up the "fixed code is still producing diagnostics" check despite the fixes being correct; this is an interesting contrast-to/inconsistency-with the behavior of UI tests (which secretly pass `-A unused`), a behavior which we probably ought to resolve one way or the other (filed issue #50926). A few suggestion labels are reworded (e.g., to avoid phrasing it as a question, which which is discouraged by the style guidelines listed in `.span_suggestion`'s doc-comment).
2018-05-19 21:52:24 +00:00
found_span,
"change the closure to accept a tuple instead of individual arguments",
suggestion applicabilities for libsyntax and librustc, run-rustfix tests Consider this a down payment on #50723. To recap, an `Applicability` enum was recently (#50204) added, to convey to Rustfix and other tools whether we think it's OK for them to blindly apply the suggestion, or whether to prompt a human for guidance (because the suggestion might contain placeholders that we can't infer, or because we think it has a sufficiently high probability of being wrong even though it's— presumably—right often enough to be worth emitting in the first place). When a suggestion is marked as `MaybeIncorrect`, we try to use comments to indicate precisely why (although there are a few places where we just say `// speculative` because the present author's subjective judgement balked at the idea that the suggestion has no false positives). The `run-rustfix` directive is opporunistically set on some relevant UI tests (and a couple tests that were in the `test/ui/suggestions` directory, even if the suggestions didn't originate in librustc or libsyntax). This is less trivial than it sounds, because a surprising number of test files aren't equipped to be tested as fixed even when they contain successfully fixable errors, because, e.g., there are more, not-directly-related errors after fixing. Some test files need an attribute or underscore to avoid unused warnings tripping up the "fixed code is still producing diagnostics" check despite the fixes being correct; this is an interesting contrast-to/inconsistency-with the behavior of UI tests (which secretly pass `-A unused`), a behavior which we probably ought to resolve one way or the other (filed issue #50926). A few suggestion labels are reworded (e.g., to avoid phrasing it as a question, which which is discouraged by the style guidelines listed in `.span_suggestion`'s doc-comment).
2018-05-19 21:52:24 +00:00
sugg,
Applicability::MachineApplicable,
suggestion applicabilities for libsyntax and librustc, run-rustfix tests Consider this a down payment on #50723. To recap, an `Applicability` enum was recently (#50204) added, to convey to Rustfix and other tools whether we think it's OK for them to blindly apply the suggestion, or whether to prompt a human for guidance (because the suggestion might contain placeholders that we can't infer, or because we think it has a sufficiently high probability of being wrong even though it's— presumably—right often enough to be worth emitting in the first place). When a suggestion is marked as `MaybeIncorrect`, we try to use comments to indicate precisely why (although there are a few places where we just say `// speculative` because the present author's subjective judgement balked at the idea that the suggestion has no false positives). The `run-rustfix` directive is opporunistically set on some relevant UI tests (and a couple tests that were in the `test/ui/suggestions` directory, even if the suggestions didn't originate in librustc or libsyntax). This is less trivial than it sounds, because a surprising number of test files aren't equipped to be tested as fixed even when they contain successfully fixable errors, because, e.g., there are more, not-directly-related errors after fixing. Some test files need an attribute or underscore to avoid unused warnings tripping up the "fixed code is still producing diagnostics" check despite the fixes being correct; this is an interesting contrast-to/inconsistency-with the behavior of UI tests (which secretly pass `-A unused`), a behavior which we probably ought to resolve one way or the other (filed issue #50926). A few suggestion labels are reworded (e.g., to avoid phrasing it as a question, which which is discouraged by the style guidelines listed in `.span_suggestion`'s doc-comment).
2018-05-19 21:52:24 +00:00
);
}
2017-10-07 06:12:56 +00:00
}
2017-04-24 00:54:32 +00:00
}
2017-04-24 00:54:32 +00:00
err
}
fn report_closure_arg_mismatch(
&self,
span: Span,
found_span: Option<Span>,
expected_ref: ty::PolyTraitRef<'tcx>,
found: ty::PolyTraitRef<'tcx>,
) -> DiagnosticBuilder<'tcx> {
fn build_fn_sig_string<'tcx>(tcx: TyCtxt<'tcx>, trait_ref: &ty::TraitRef<'tcx>) -> String {
let inputs = trait_ref.substs.type_at(1);
let sig = if let ty::Tuple(inputs) = inputs.sty {
tcx.mk_fn_sig(
2019-04-25 23:27:33 +00:00
inputs.iter().map(|k| k.expect_ty()),
tcx.mk_ty_infer(ty::TyVar(ty::TyVid { index: 0 })),
false,
hir::Unsafety::Normal,
::rustc_target::spec::abi::Abi::Rust
)
} else {
tcx.mk_fn_sig(
::std::iter::once(inputs),
tcx.mk_ty_infer(ty::TyVar(ty::TyVid { index: 0 })),
false,
hir::Unsafety::Normal,
::rustc_target::spec::abi::Abi::Rust
)
};
2018-07-27 09:11:18 +00:00
ty::Binder::bind(sig).to_string()
}
let argument_is_closure = expected_ref.skip_binder().substs.type_at(0).is_closure();
let mut err = struct_span_err!(self.tcx.sess, span, E0631,
"type mismatch in {} arguments",
if argument_is_closure { "closure" } else { "function" });
let found_str = format!(
"expected signature of `{}`",
build_fn_sig_string(self.tcx, found.skip_binder())
);
err.span_label(span, found_str);
let found_span = found_span.unwrap_or(span);
let expected_str = format!(
"found signature of `{}`",
build_fn_sig_string(self.tcx, expected_ref.skip_binder())
);
err.span_label(found_span, expected_str);
err
}
}
2019-06-13 21:48:52 +00:00
impl<'tcx> TyCtxt<'tcx> {
pub fn recursive_type_with_infinite_size_error(self,
type_def_id: DefId)
-> DiagnosticBuilder<'tcx>
{
assert!(type_def_id.is_local());
let span = self.hir().span_if_local(type_def_id).unwrap();
2018-08-18 10:14:09 +00:00
let span = self.sess.source_map().def_span(span);
let mut err = struct_span_err!(self.sess, span, E0072,
"recursive type `{}` has infinite size",
self.def_path_str(type_def_id));
err.span_label(span, "recursive type has infinite size");
err.help(&format!("insert indirection (e.g., a `Box`, `Rc`, or `&`) \
at some point to make `{}` representable",
self.def_path_str(type_def_id)));
err
}
pub fn report_object_safety_error(
self,
span: Span,
trait_def_id: DefId,
violations: Vec<ObjectSafetyViolation>,
) -> Option<DiagnosticBuilder<'tcx>> {
if self.sess.trait_methods_not_found.borrow().contains(&span) {
// Avoid emitting error caused by non-existing method (#58734)
return None;
}
let trait_str = self.def_path_str(trait_def_id);
2018-08-18 10:14:09 +00:00
let span = self.sess.source_map().def_span(span);
let mut err = struct_span_err!(
self.sess, span, E0038,
"the trait `{}` cannot be made into an object",
trait_str);
err.span_label(span, format!("the trait `{}` cannot be made into an object", trait_str));
let mut reported_violations = FxHashSet::default();
for violation in violations {
if reported_violations.insert(violation.clone()) {
err.note(&violation.error_msg());
}
}
Some(err)
2014-12-06 16:39:25 +00:00
}
}
2014-12-06 16:39:25 +00:00
2019-06-13 21:48:52 +00:00
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>,
body_id: Option<hir::BodyId>) {
// Unable to successfully determine, probably means
// insufficient type information, but could mean
// ambiguous impls. The latter *ought* to be a
// coherence violation, so we don't report it here.
let predicate = self.resolve_vars_if_possible(&obligation.predicate);
2017-04-11 21:37:40 +00:00
let span = obligation.cause.span;
debug!("maybe_report_ambiguity(predicate={:?}, obligation={:?})",
predicate,
obligation);
// Ambiguity errors are often caused as fallout from earlier
// errors. So just ignore them if this infcx is tainted.
if self.is_tainted_by_errors() {
return;
}
match predicate {
ty::Predicate::Trait(ref data) => {
let trait_ref = data.to_poly_trait_ref();
let self_ty = trait_ref.self_ty();
if predicate.references_error() {
return;
}
// Typically, this ambiguity should only happen if
// there are unresolved type inference variables
// (otherwise it would suggest a coherence
// failure). But given #21974 that is not necessarily
// the case -- we can have multiple where clauses that
// are only distinguished by a region, which results
// in an ambiguity even when all types are fully
// known, since we don't dispatch based on region
// relationships.
// This is kind of a hack: it frequently happens that some earlier
// error prevents types from being fully inferred, and then we get
// a bunch of uninteresting errors saying something like "<generic
// #0> doesn't implement Sized". It may even be true that we
// could just skip over all checks where the self-ty is an
// inference variable, but I was afraid that there might be an
// inference variable created, registered as an obligation, and
// then never forced by writeback, and hence by skipping here we'd
// be ignoring the fact that we don't KNOW the type works
// out. Though even that would probably be harmless, given that
// we're only talking about builtin traits, which are known to be
// inhabited. But in any case I just threw in this check for
// has_errors() to be sure that compilation isn't happening
// anyway. In that case, why inundate the user.
if !self.tcx.sess.has_errors() {
if
self.tcx.lang_items().sized_trait()
.map_or(false, |sized_id| sized_id == trait_ref.def_id())
{
self.need_type_info_err(body_id, span, self_ty).emit();
} else {
let mut err = struct_span_err!(self.tcx.sess,
span, E0283,
"type annotations required: \
cannot resolve `{}`",
predicate);
self.note_obligation_cause(&mut err, obligation);
err.emit();
}
}
}
ty::Predicate::WellFormed(ty) => {
// Same hacky approach as above to avoid deluging user
// with error messages.
if !ty.references_error() && !self.tcx.sess.has_errors() {
self.need_type_info_err(body_id, span, ty).emit();
}
}
2017-03-10 02:47:09 +00:00
ty::Predicate::Subtype(ref data) => {
if data.references_error() || self.tcx.sess.has_errors() {
// no need to overload user in such cases
} else {
let &SubtypePredicate { a_is_expected: _, a, b } = data.skip_binder();
// both must be type variables, or the other would've been instantiated
assert!(a.is_ty_var() && b.is_ty_var());
self.need_type_info_err(body_id,
obligation.cause.span,
a).emit();
2017-03-10 02:47:09 +00:00
}
}
_ => {
if !self.tcx.sess.has_errors() {
let mut err = struct_span_err!(self.tcx.sess,
obligation.cause.span, E0284,
"type annotations required: \
cannot resolve `{}`",
predicate);
self.note_obligation_cause(&mut err, obligation);
err.emit();
}
2014-12-06 16:39:25 +00:00
}
}
}
2019-02-08 13:53:55 +00:00
/// Returns `true` if the trait predicate may apply for *some* assignment
/// to the type parameters.
fn predicate_can_apply(
&self,
param_env: ty::ParamEnv<'tcx>,
pred: ty::PolyTraitRef<'tcx>,
) -> bool {
struct ParamToVarFolder<'a, 'tcx> {
2019-06-13 21:48:52 +00:00
infcx: &'a InferCtxt<'a, 'tcx>,
var_map: FxHashMap<Ty<'tcx>, Ty<'tcx>>,
}
2019-06-13 21:48:52 +00:00
impl<'a, 'tcx> TypeFolder<'tcx> for ParamToVarFolder<'a, 'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { self.infcx.tcx }
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
if let ty::Param(ty::ParamTy {name, .. }) = ty.sty {
let infcx = self.infcx;
self.var_map.entry(ty).or_insert_with(||
infcx.next_ty_var(
TypeVariableOrigin {
kind: TypeVariableOriginKind::TypeParameterDefinition(name),
span: DUMMY_SP,
}
)
)
} else {
ty.super_fold_with(self)
}
}
}
self.probe(|_| {
let mut selcx = SelectionContext::new(self);
let cleaned_pred = pred.fold_with(&mut ParamToVarFolder {
infcx: self,
var_map: Default::default()
});
let cleaned_pred = super::project::normalize(
&mut selcx,
2017-05-23 08:19:47 +00:00
param_env,
ObligationCause::dummy(),
&cleaned_pred
).value;
let obligation = Obligation::new(
ObligationCause::dummy(),
2017-05-23 08:19:47 +00:00
param_env,
cleaned_pred.to_predicate()
);
self.predicate_may_hold(&obligation)
})
}
fn note_obligation_cause<T>(&self,
err: &mut DiagnosticBuilder<'_>,
obligation: &Obligation<'tcx, T>)
where T: fmt::Display
{
self.note_obligation_cause_code(err,
&obligation.predicate,
&obligation.cause.code,
&mut vec![]);
}
2014-12-06 16:39:25 +00:00
fn note_obligation_cause_code<T>(&self,
err: &mut DiagnosticBuilder<'_>,
predicate: &T,
cause_code: &ObligationCauseCode<'tcx>,
obligated_types: &mut Vec<&ty::TyS<'tcx>>)
where T: fmt::Display
{
let tcx = self.tcx;
match *cause_code {
ObligationCauseCode::ExprAssignable |
ObligationCauseCode::MatchExpressionArm { .. } |
ObligationCauseCode::MatchExpressionArmPattern { .. } |
ObligationCauseCode::IfExpression { .. } |
ObligationCauseCode::IfExpressionWithNoElse |
ObligationCauseCode::MainFunctionType |
ObligationCauseCode::StartFunctionType |
ObligationCauseCode::IntrinsicType |
ObligationCauseCode::MethodReceiver |
ObligationCauseCode::ReturnNoExpression |
ObligationCauseCode::MiscObligation => {}
ObligationCauseCode::SliceOrArrayElem => {
err.note("slice and array elements must have `Sized` type");
}
ObligationCauseCode::TupleElem => {
2017-06-08 05:49:54 +00:00
err.note("only the last element of a tuple may have a dynamically sized type");
}
ObligationCauseCode::ProjectionWf(data) => {
err.note(&format!("required so that the projection `{}` is well-formed",
data));
}
ObligationCauseCode::ReferenceOutlivesReferent(ref_ty) => {
err.note(&format!("required so that reference `{}` does not outlive its referent",
ref_ty));
}
ObligationCauseCode::ObjectTypeBound(object_ty, region) => {
err.note(&format!("required so that the lifetime bound of `{}` for `{}` \
is satisfied",
region, object_ty));
}
ObligationCauseCode::ItemObligation(item_def_id) => {
let item_name = tcx.def_path_str(item_def_id);
let msg = format!("required by `{}`", item_name);
if let Some(sp) = tcx.hir().span_if_local(item_def_id) {
2018-08-18 10:14:09 +00:00
let sp = tcx.sess.source_map().def_span(sp);
err.span_note(sp, &msg);
} else {
err.note(&msg);
}
}
ObligationCauseCode::ObjectCastObligation(object_ty) => {
err.note(&format!("required for the cast to the object type `{}`",
self.ty_to_string(object_ty)));
}
ObligationCauseCode::RepeatVec => {
err.note("the `Copy` trait is required because the \
repeated element will be copied");
}
ObligationCauseCode::VariableType(_) => {
err.note("all local variables must have a statically known size");
2018-05-28 15:11:34 +00:00
if !self.tcx.features().unsized_locals {
err.help("unsized locals are gated as an unstable feature");
}
}
2018-05-29 15:25:56 +00:00
ObligationCauseCode::SizedArgumentType => {
err.note("all function arguments must have a statically known size");
2018-05-28 15:11:34 +00:00
if !self.tcx.features().unsized_locals {
err.help("unsized locals are gated as an unstable feature");
}
}
ObligationCauseCode::SizedReturnType => {
err.note("the return type of a function must have a \
statically known size");
}
2018-01-28 19:23:49 +00:00
ObligationCauseCode::SizedYieldType => {
err.note("the yield type of a generator must have a \
statically known size");
}
ObligationCauseCode::AssignmentLhsSized => {
err.note("the left-hand-side of an assignment must have a statically known size");
}
ObligationCauseCode::TupleInitializerSized => {
err.note("tuples must have a statically known size to be initialized");
}
ObligationCauseCode::StructInitializerSized => {
err.note("structs must have a statically known size to be initialized");
}
ObligationCauseCode::FieldSized { adt_kind: ref item, last } => {
match *item {
AdtKind::Struct => {
if last {
err.note("the last field of a packed struct may only have a \
dynamically sized type if it does not need drop to be run");
} else {
err.note("only the last field of a struct may have a dynamically \
sized type");
}
}
AdtKind::Union => {
err.note("no field of a union may have a dynamically sized type");
}
AdtKind::Enum => {
err.note("no field of an enum variant may have a dynamically sized type");
}
}
}
ObligationCauseCode::ConstSized => {
err.note("constant expressions must have a statically known size");
}
ObligationCauseCode::SharedStatic => {
err.note("shared static variables must have a type that implements `Sync`");
}
ObligationCauseCode::BuiltinDerivedObligation(ref data) => {
let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref);
let ty = parent_trait_ref.skip_binder().self_ty();
err.note(&format!("required because it appears within the type `{}`", ty));
obligated_types.push(ty);
let parent_predicate = parent_trait_ref.to_predicate();
if !self.is_recursive_obligation(obligated_types, &data.parent_code) {
self.note_obligation_cause_code(err,
&parent_predicate,
&data.parent_code,
obligated_types);
}
}
ObligationCauseCode::ImplDerivedObligation(ref data) => {
let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref);
err.note(
&format!("required because of the requirements on the impl of `{}` for `{}`",
parent_trait_ref,
parent_trait_ref.skip_binder().self_ty()));
let parent_predicate = parent_trait_ref.to_predicate();
self.note_obligation_cause_code(err,
&parent_predicate,
&data.parent_code,
obligated_types);
}
ObligationCauseCode::CompareImplMethodObligation { .. } => {
err.note(
&format!("the requirement `{}` appears on the impl method \
but not on the corresponding trait method",
predicate));
}
ObligationCauseCode::ReturnType(_) |
ObligationCauseCode::BlockTailExpression(_) => (),
2018-05-06 21:50:35 +00:00
ObligationCauseCode::TrivialBound => {
err.help("see issue #48214");
if tcx.sess.opts.unstable_features.is_nightly_build() {
err.help("add `#![feature(trivial_bounds)]` to the \
2018-05-06 21:50:35 +00:00
crate attributes to enable",
);
}
}
}
2014-12-06 16:39:25 +00:00
}
fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>) {
let current_limit = self.tcx.sess.recursion_limit.get();
let suggested_limit = current_limit * 2;
err.help(&format!("consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
suggested_limit));
}
fn is_recursive_obligation(&self,
obligated_types: &mut Vec<&ty::TyS<'tcx>>,
cause_code: &ObligationCauseCode<'tcx>) -> bool {
if let ObligationCauseCode::BuiltinDerivedObligation(ref data) = cause_code {
let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref);
if obligated_types.iter().any(|ot| ot == &parent_trait_ref.skip_binder().self_ty()) {
return true;
}
}
false
}
}
/// Summarizes information
#[derive(Clone)]
pub enum ArgKind {
/// An argument of non-tuple type. Parameters are (name, ty)
Arg(String, String),
/// An argument of tuple type. For a "found" argument, the span is
/// the locationo in the source of the pattern. For a "expected"
/// argument, it will be None. The vector is a list of (name, ty)
/// strings for the components of the tuple.
Tuple(Option<Span>, Vec<(String, String)>),
}
impl ArgKind {
fn empty() -> ArgKind {
ArgKind::Arg("_".to_owned(), "_".to_owned())
}
/// Creates an `ArgKind` from the expected type of an
/// argument. It has no name (`_`) and an optional source span.
pub fn from_expected_ty(t: Ty<'_>, span: Option<Span>) -> ArgKind {
match t.sty {
ty::Tuple(ref tys) => ArgKind::Tuple(
span,
tys.iter()
.map(|ty| ("_".to_owned(), ty.to_string()))
.collect::<Vec<_>>()
),
_ => ArgKind::Arg("_".to_owned(), t.to_string()),
}
}
}