2014-12-17 19:16:28 +00:00
|
|
|
use super::{
|
2019-08-24 21:45:03 +00:00
|
|
|
ConstEvalFailure,
|
|
|
|
EvaluationResult,
|
2014-12-17 19:16:28 +00:00
|
|
|
FulfillmentError,
|
|
|
|
FulfillmentErrorCode,
|
|
|
|
MismatchedProjectionTypes,
|
2019-08-24 21:45:03 +00:00
|
|
|
ObjectSafetyViolation,
|
2015-03-20 10:48:40 +00:00
|
|
|
Obligation,
|
2016-03-29 17:12:31 +00:00
|
|
|
ObligationCause,
|
2014-12-17 19:16:28 +00:00
|
|
|
ObligationCauseCode,
|
2017-08-30 20:40:43 +00:00
|
|
|
OnUnimplementedDirective,
|
|
|
|
OnUnimplementedNote,
|
2014-12-17 19:16:28 +00:00
|
|
|
OutputTypeParameterMismatch,
|
2019-08-24 21:45:03 +00:00
|
|
|
Overflow,
|
2014-12-17 19:16:28 +00:00
|
|
|
PredicateObligation,
|
2016-03-29 17:12:31 +00:00
|
|
|
SelectionContext,
|
2014-12-17 19:16:28 +00:00
|
|
|
SelectionError,
|
2019-08-24 21:45:03 +00:00
|
|
|
TraitNotObjectSafe,
|
2014-12-17 19:16:28 +00:00
|
|
|
};
|
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};
|
2019-03-21 00:00:24 +00:00
|
|
|
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
2019-02-05 17:20:45 +00:00
|
|
|
use crate::session::DiagnosticMessageId;
|
2019-09-25 12:58:41 +00:00
|
|
|
use crate::ty::{self, AdtKind, DefIdTree, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
|
2019-02-05 17:20:45 +00:00
|
|
|
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};
|
2015-09-24 23:40:57 +00:00
|
|
|
|
2019-11-06 18:39:57 +00:00
|
|
|
use errors::{Applicability, DiagnosticBuilder, pluralize, Style};
|
2019-02-09 02:24:02 +00:00
|
|
|
use std::fmt;
|
|
|
|
use syntax::ast;
|
2019-08-24 21:45:03 +00:00
|
|
|
use syntax::symbol::{sym, kw};
|
2019-09-25 12:58:41 +00:00
|
|
|
use syntax_pos::{DUMMY_SP, Span, ExpnKind, MultiSpan};
|
2019-11-03 22:06:48 +00:00
|
|
|
use rustc::hir::def_id::LOCAL_CRATE;
|
2019-11-24 05:44:28 +00:00
|
|
|
use syntax_pos::source_map::SourceMap;
|
2017-03-09 23:51:47 +00:00
|
|
|
|
2019-11-11 21:46:56 +00:00
|
|
|
use rustc_error_codes::*;
|
|
|
|
|
2019-06-13 21:48:52 +00:00
|
|
|
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
2019-09-04 17:17:59 +00:00
|
|
|
pub fn report_fulfillment_errors(
|
|
|
|
&self,
|
|
|
|
errors: &[FulfillmentError<'tcx>],
|
|
|
|
body_id: Option<hir::BodyId>,
|
|
|
|
fallback_has_occurred: bool,
|
|
|
|
) {
|
2017-05-08 16:45:27 +00:00
|
|
|
#[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
|
|
|
|
2018-09-12 14:57:19 +00:00
|
|
|
let mut error_map: FxHashMap<_, Vec<_>> =
|
2017-05-08 16:45:27 +00:00
|
|
|
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() {
|
2018-10-04 13:48:32 +00:00
|
|
|
// 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;
|
2019-08-13 20:56:42 +00:00
|
|
|
let expn_data = span.ctxt().outer_expn_data();
|
|
|
|
if let ExpnKind::Desugaring(_) = expn_data.kind {
|
|
|
|
span = expn_data.call_site;
|
2018-10-04 13:48:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
error_map.entry(span).or_default().push(
|
2017-05-08 16:45:27 +00:00
|
|
|
ErrorDescriptor {
|
|
|
|
predicate: error.obligation.predicate.clone(),
|
|
|
|
index: Some(index)
|
2018-10-04 13:48:32 +00:00
|
|
|
}
|
|
|
|
);
|
2015-09-24 16:58:00 +00:00
|
|
|
|
2017-05-08 16:45:27 +00:00
|
|
|
self.reported_trait_errors.borrow_mut()
|
2018-10-04 13:48:32 +00:00
|
|
|
.entry(span).or_default()
|
2017-05-08 16:45:27 +00:00
|
|
|
.push(error.obligation.predicate.clone());
|
2015-09-24 16:58:00 +00:00
|
|
|
}
|
|
|
|
|
2018-10-04 13:48:32 +00:00
|
|
|
// We do this in 2 passes because we want to display errors in order, though
|
2017-05-08 16:45:27 +00:00
|
|
|
// maybe it *is* better to sort errors by span or something.
|
2018-09-12 14:57:19 +00:00
|
|
|
let mut is_suppressed = vec![false; errors.len()];
|
2017-05-08 16:45:27 +00:00
|
|
|
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
|
|
|
|
}
|
2017-01-24 15:19:36 +00:00
|
|
|
|
2017-05-08 16:45:27 +00:00
|
|
|
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-05-08 16:45:27 +00:00
|
|
|
}
|
2017-04-11 21:37:40 +00:00
|
|
|
}
|
generalize type variables too
When we are generalizing a super/sub-type, we have to replace type
variables with a fresh variable (and not just region variables). So if
we know that `Box<?T> <: ?U`, for example, we instantiate `?U` with
`Box<?V>` and then relate `Box<?T>` to `Box<?V>` (and hence require that
`?T <: ?V`).
This change has some complex interactions, however:
First, the occurs check must be updated to detect constraints like `?T
<: ?U` and `?U <: Box<?T>`. If we're not careful, we'll create a
never-ending sequence of new variables. To address this, we add a second
unification set into `type_variables` that tracks type variables related
through **either** equality **or** subtyping, and use that during the
occurs-check.
Second, the "fudge regions if ok" code was expecting no new type
variables to be created. It must be updated to create new type variables
outside of the probe. This is relatively straight-forward under the new
scheme, since type variables are now independent from one another, and
any relations are moderated by pending subtype obliations and so forth.
This part would be tricky to backport though.
cc #18653
cc #40951
2017-04-11 21:17:58 +00:00
|
|
|
}
|
|
|
|
|
2017-05-08 16:45:27 +00:00
|
|
|
for (error, suppressed) in errors.iter().zip(is_suppressed) {
|
|
|
|
if !suppressed {
|
2018-03-12 04:15:06 +00:00
|
|
|
self.report_fulfillment_error(error, body_id, fallback_has_occurred);
|
2017-05-08 16:45:27 +00:00
|
|
|
}
|
|
|
|
}
|
2017-01-24 15:19:36 +00:00
|
|
|
}
|
|
|
|
|
2018-11-27 02:59:49 +00:00
|
|
|
// 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.
|
2019-09-16 22:54:31 +00:00
|
|
|
fn error_implies(
|
|
|
|
&self,
|
|
|
|
cond: &ty::Predicate<'tcx>,
|
|
|
|
error: &ty::Predicate<'tcx>,
|
|
|
|
) -> bool {
|
2017-05-08 16:45:27 +00:00
|
|
|
if cond == error {
|
|
|
|
return true
|
2017-04-11 21:37:40 +00:00
|
|
|
}
|
2017-01-24 15:19:36 +00:00
|
|
|
|
2017-05-08 16:45:27 +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
|
2017-01-24 15:19:36 +00:00
|
|
|
}
|
2017-05-08 16:45:27 +00:00
|
|
|
};
|
2017-01-24 15:19:36 +00:00
|
|
|
|
2017-05-08 16:45:27 +00:00
|
|
|
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.
|
2018-02-10 18:18:02 +00:00
|
|
|
let param_env = ty::ParamEnv::empty();
|
2018-07-27 11:20:13 +00:00
|
|
|
if self.can_sub(param_env, error, implication).is_ok() {
|
2017-05-08 16:45:27 +00:00
|
|
|
debug!("error_implies: {:?} -> {:?} -> {:?}", cond, error, implication);
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
2016-05-11 05:48:12 +00:00
|
|
|
}
|
2017-05-08 16:45:27 +00:00
|
|
|
|
|
|
|
false
|
2014-12-06 16:39:25 +00:00
|
|
|
}
|
|
|
|
|
2019-09-16 22:54:31 +00:00
|
|
|
fn report_fulfillment_error(
|
|
|
|
&self,
|
|
|
|
error: &FulfillmentError<'tcx>,
|
|
|
|
body_id: Option<hir::BodyId>,
|
|
|
|
fallback_has_occurred: bool,
|
|
|
|
) {
|
2019-11-24 13:31:19 +00:00
|
|
|
debug!("report_fulfillment_error({:?})", error);
|
2016-05-11 05:48:12 +00:00
|
|
|
match error.code {
|
2019-09-16 22:54:31 +00:00
|
|
|
FulfillmentErrorCode::CodeSelectionError(ref selection_error) => {
|
|
|
|
self.report_selection_error(
|
|
|
|
&error.obligation,
|
|
|
|
selection_error,
|
|
|
|
fallback_has_occurred,
|
|
|
|
error.points_at_arg_span,
|
|
|
|
);
|
2016-05-11 05:48:12 +00:00
|
|
|
}
|
|
|
|
FulfillmentErrorCode::CodeProjectionError(ref e) => {
|
2016-09-01 10:34:56 +00:00
|
|
|
self.report_projection_error(&error.obligation, e);
|
2016-05-11 05:48:12 +00:00
|
|
|
}
|
|
|
|
FulfillmentErrorCode::CodeAmbiguity => {
|
2017-06-28 16:26:36 +00:00
|
|
|
self.maybe_report_ambiguity(&error.obligation, body_id);
|
2016-05-11 05:48:12 +00:00
|
|
|
}
|
2017-03-10 02:47:09 +00:00
|
|
|
FulfillmentErrorCode::CodeSubtypeError(ref expected_found, ref err) => {
|
2019-09-16 22:54:31 +00:00
|
|
|
self.report_mismatched_types(
|
|
|
|
&error.obligation.cause,
|
|
|
|
expected_found.expected,
|
|
|
|
expected_found.found,
|
|
|
|
err.clone(),
|
|
|
|
).emit();
|
2017-03-10 02:47:09 +00:00
|
|
|
}
|
2014-12-06 16:39:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-16 22:54:31 +00:00
|
|
|
fn report_projection_error(
|
|
|
|
&self,
|
|
|
|
obligation: &PredicateObligation<'tcx>,
|
|
|
|
error: &MismatchedProjectionTypes<'tcx>,
|
|
|
|
) {
|
2019-10-11 02:33:05 +00:00
|
|
|
let predicate = self.resolve_vars_if_possible(&obligation.predicate);
|
2016-05-11 05:48:12 +00:00
|
|
|
|
2016-07-20 23:13:14 +00:00
|
|
|
if predicate.references_error() {
|
|
|
|
return
|
|
|
|
}
|
2016-09-01 10:34:56 +00:00
|
|
|
|
2016-07-20 23:13:14 +00:00
|
|
|
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);
|
2018-11-01 14:30:37 +00:00
|
|
|
let (data, _) = self.replace_bound_vars_with_fresh_vars(
|
2016-05-11 05:48:12 +00:00
|
|
|
obligation.cause.span,
|
2016-07-20 23:13:14 +00:00
|
|
|
infer::LateBoundRegionConversionTime::HigherRankedType,
|
2018-11-01 14:30:37 +00:00
|
|
|
data
|
|
|
|
);
|
2018-05-16 21:58:08 +00:00
|
|
|
let mut obligations = vec![];
|
|
|
|
let normalized_ty = super::normalize_projection_type(
|
2016-07-20 23:13:14 +00:00
|
|
|
&mut selcx,
|
2017-05-23 08:19:47 +00:00
|
|
|
obligation.param_env,
|
2016-07-20 23:13:14 +00:00
|
|
|
data.projection_ty,
|
|
|
|
obligation.cause.clone(),
|
2018-05-16 21:58:08 +00:00
|
|
|
0,
|
|
|
|
&mut obligations
|
2016-07-20 23:13:14 +00:00
|
|
|
);
|
2019-10-30 15:53:41 +00:00
|
|
|
|
|
|
|
debug!("report_projection_error obligation.cause={:?} obligation.param_env={:?}",
|
|
|
|
obligation.cause, obligation.param_env);
|
|
|
|
|
|
|
|
debug!("report_projection_error normalized_ty={:?} data.ty={:?}",
|
|
|
|
normalized_ty, data.ty);
|
|
|
|
|
|
|
|
let is_normalized_ty_expected = match &obligation.cause.code {
|
|
|
|
ObligationCauseCode::ItemObligation(_) |
|
|
|
|
ObligationCauseCode::BindingObligation(_, _) |
|
|
|
|
ObligationCauseCode::ObjectCastObligation(_) => false,
|
|
|
|
_ => true,
|
|
|
|
};
|
|
|
|
|
2017-05-24 13:43:20 +00:00
|
|
|
if let Err(error) = self.at(&obligation.cause, obligation.param_env)
|
2019-10-30 15:53:41 +00:00
|
|
|
.eq_exp(is_normalized_ty_expected, normalized_ty, data.ty)
|
2019-10-11 02:33:05 +00:00
|
|
|
{
|
2019-10-30 15:53:41 +00:00
|
|
|
values = Some(infer::ValuePairs::Types(
|
|
|
|
ExpectedFound::new(is_normalized_ty_expected, normalized_ty, data.ty)));
|
|
|
|
|
2016-07-20 23:13:14 +00:00
|
|
|
err_buf = error;
|
|
|
|
err = &err_buf;
|
|
|
|
}
|
2016-05-11 05:48:12 +00:00
|
|
|
}
|
2016-07-20 23:13:14 +00:00
|
|
|
|
2017-11-13 03:13:07 +00:00
|
|
|
let msg = format!("type mismatch resolving `{}`", predicate);
|
2019-10-11 02:33:05 +00:00
|
|
|
let error_id = (
|
|
|
|
DiagnosticMessageId::ErrorId(271),
|
|
|
|
Some(obligation.cause.span),
|
|
|
|
msg,
|
|
|
|
);
|
2017-11-13 03:13:07 +00:00
|
|
|
let fresh = self.tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id);
|
|
|
|
if fresh {
|
|
|
|
let mut diag = struct_span_err!(
|
2019-10-11 02:33:05 +00:00
|
|
|
self.tcx.sess,
|
|
|
|
obligation.cause.span,
|
|
|
|
E0271,
|
|
|
|
"type mismatch resolving `{}`",
|
|
|
|
predicate
|
2017-11-13 03:13:07 +00:00
|
|
|
);
|
|
|
|
self.note_type_err(&mut diag, &obligation.cause, None, values, err);
|
|
|
|
self.note_obligation_cause(&mut diag, obligation);
|
|
|
|
diag.emit();
|
|
|
|
}
|
2016-07-20 23:13:14 +00:00
|
|
|
});
|
2014-12-17 19:16:28 +00:00
|
|
|
}
|
|
|
|
|
2016-05-17 18:55:34 +00:00
|
|
|
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> {
|
2019-09-16 18:08:35 +00:00
|
|
|
match t.kind {
|
2018-08-22 00:35:55 +00:00
|
|
|
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),
|
2018-08-22 00:35:02 +00:00
|
|
|
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),
|
2018-08-22 00:35:29 +00:00
|
|
|
ty::Param(..) => Some(12),
|
2018-08-23 19:51:32 +00:00
|
|
|
ty::Opaque(..) => Some(13),
|
2018-08-22 00:35:02 +00:00
|
|
|
ty::Never => Some(14),
|
|
|
|
ty::Adt(adt, ..) => match adt.adt_kind() {
|
2016-09-05 22:26:02 +00:00
|
|
|
AdtKind::Struct => Some(15),
|
|
|
|
AdtKind::Union => Some(16),
|
|
|
|
AdtKind::Enum => Some(17),
|
|
|
|
},
|
2018-08-22 00:35:02 +00:00
|
|
|
ty::Generator(..) => Some(18),
|
2018-08-22 00:35:29 +00:00
|
|
|
ty::Foreign(..) => Some(19),
|
2018-08-22 00:35:02 +00:00
|
|
|
ty::GeneratorWitness(..) => Some(20),
|
2018-11-02 17:48:24 +00:00
|
|
|
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error => None,
|
2018-10-03 15:06:28 +00:00
|
|
|
ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
|
2016-05-17 18:55:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
match (type_category(a), type_category(b)) {
|
2019-09-16 18:08:35 +00:00
|
|
|
(Some(cat_a), Some(cat_b)) => match (&a.kind, &b.kind) {
|
2018-08-22 00:35:02 +00:00
|
|
|
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => def_a == def_b,
|
2016-05-17 18:55:34 +00:00
|
|
|
_ => 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>
|
2016-05-14 06:01:57 +00:00
|
|
|
{
|
|
|
|
let tcx = self.tcx;
|
2017-05-23 08:19:47 +00:00
|
|
|
let param_env = obligation.param_env;
|
2016-05-17 18:55:34 +00:00
|
|
|
let trait_ref = tcx.erase_late_bound_regions(&trait_ref);
|
|
|
|
let trait_self_ty = trait_ref.self_ty();
|
2016-05-14 06:01:57 +00:00
|
|
|
|
2016-05-17 18:55:34 +00:00
|
|
|
let mut self_match_impls = vec![];
|
|
|
|
let mut fuzzy_match_impls = vec![];
|
2016-05-16 20:16:52 +00:00
|
|
|
|
2017-08-07 20:50:34 +00:00
|
|
|
self.tcx.for_each_relevant_impl(
|
|
|
|
trait_ref.def_id, trait_self_ty, |def_id| {
|
2018-03-06 16:07:27 +00:00
|
|
|
let impl_substs = self.fresh_substs_for_item(obligation.cause.span, def_id);
|
2016-05-17 18:55:34 +00:00
|
|
|
let impl_trait_ref = tcx
|
2016-05-14 06:01:57 +00:00
|
|
|
.impl_trait_ref(def_id)
|
|
|
|
.unwrap()
|
2016-08-17 00:56:18 +00:00
|
|
|
.subst(tcx, impl_substs);
|
2016-05-14 06:01:57 +00:00
|
|
|
|
2016-05-17 18:55:34 +00:00
|
|
|
let impl_self_ty = impl_trait_ref.self_ty();
|
2016-05-16 20:16:52 +00:00
|
|
|
|
2017-05-24 13:43:20 +00:00
|
|
|
if let Ok(..) = self.can_eq(param_env, trait_self_ty, impl_self_ty) {
|
2016-05-17 18:55:34 +00:00
|
|
|
self_match_impls.push(def_id);
|
|
|
|
|
2016-08-18 05:32:50 +00:00
|
|
|
if trait_ref.substs.types().skip(1)
|
|
|
|
.zip(impl_trait_ref.substs.types().skip(1))
|
2016-05-17 18:55:34 +00:00
|
|
|
.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-14 06:01:57 +00:00
|
|
|
});
|
2016-05-11 12:33:14 +00:00
|
|
|
|
2016-05-17 18:55:34 +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 {
|
2016-05-17 18:55:34 +00:00
|
|
|
return None
|
|
|
|
};
|
|
|
|
|
2019-05-08 03:21:18 +00:00
|
|
|
if tcx.has_attr(impl_def_id, sym::rustc_on_unimplemented) {
|
2016-05-17 18:55:34 +00:00
|
|
|
Some(impl_def_id)
|
|
|
|
} else {
|
|
|
|
None
|
2016-05-11 12:33:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-28 19:04:15 +00:00
|
|
|
fn describe_generator(&self, body_id: hir::BodyId) -> Option<&'static str> {
|
|
|
|
self.tcx.hir().body(body_id).generator_kind.map(|gen_kind| {
|
|
|
|
match gen_kind {
|
|
|
|
hir::GeneratorKind::Gen => "a generator",
|
|
|
|
hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) => "an async block",
|
|
|
|
hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn) => "an async function",
|
|
|
|
hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Closure) => "an async closure",
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Used to set on_unimplemented's `ItemContext`
|
|
|
|
/// to be the enclosing (async) block/function/closure
|
|
|
|
fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str> {
|
|
|
|
let hir = &self.tcx.hir();
|
|
|
|
let node = hir.find(hir_id)?;
|
|
|
|
if let hir::Node::Item(
|
2019-11-07 11:57:52 +00:00
|
|
|
hir::Item{kind: hir::ItemKind::Fn(sig, _, body_id), .. }) = &node {
|
2019-10-28 19:04:15 +00:00
|
|
|
self.describe_generator(*body_id).or_else(||
|
2019-11-07 11:57:52 +00:00
|
|
|
Some(if let hir::FnHeader{ asyncness: hir::IsAsync::Async, .. } = sig.header {
|
2019-10-28 19:04:15 +00:00
|
|
|
"an async function"
|
|
|
|
} else {
|
|
|
|
"a function"
|
|
|
|
})
|
|
|
|
)
|
|
|
|
} else if let hir::Node::Expr(hir::Expr {
|
|
|
|
kind: hir::ExprKind::Closure(_is_move, _, body_id, _, gen_movability), .. }) = &node {
|
|
|
|
self.describe_generator(*body_id).or_else(||
|
|
|
|
Some(if gen_movability.is_some() {
|
|
|
|
"an async closure"
|
|
|
|
} else {
|
|
|
|
"a closure"
|
|
|
|
})
|
|
|
|
)
|
|
|
|
} else if let hir::Node::Expr(hir::Expr { .. }) = &node {
|
|
|
|
let parent_hid = hir.get_parent_node(hir_id);
|
|
|
|
if parent_hid != hir_id {
|
|
|
|
return self.describe_enclosure(parent_hid);
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-30 20:40:43 +00:00
|
|
|
fn on_unimplemented_note(
|
|
|
|
&self,
|
|
|
|
trait_ref: ty::PolyTraitRef<'tcx>,
|
2018-10-10 01:44:07 +00:00
|
|
|
obligation: &PredicateObligation<'tcx>,
|
|
|
|
) -> OnUnimplementedNote {
|
2018-10-11 19:11:23 +00:00
|
|
|
let def_id = self.impl_similar_to(trait_ref, obligation)
|
2018-10-12 14:16:00 +00:00
|
|
|
.unwrap_or_else(|| trait_ref.def_id());
|
2017-08-30 20:40:43 +00:00
|
|
|
let trait_ref = *trait_ref.skip_binder();
|
2016-05-14 06:01:57 +00:00
|
|
|
|
2017-08-30 21:12:34 +00:00
|
|
|
let mut flags = vec![];
|
2019-10-28 19:04:15 +00:00
|
|
|
flags.push((sym::item_context,
|
|
|
|
self.describe_enclosure(obligation.cause.body_id).map(|s|s.to_owned())));
|
|
|
|
|
2018-02-11 21:39:32 +00:00
|
|
|
match obligation.cause.code {
|
2017-08-30 21:12:34 +00:00
|
|
|
ObligationCauseCode::BuiltinDerivedObligation(..) |
|
2018-02-11 21:39:32 +00:00
|
|
|
ObligationCauseCode::ImplDerivedObligation(..) => {}
|
|
|
|
_ => {
|
|
|
|
// this is a "direct", user-specified, rather than derived,
|
|
|
|
// obligation.
|
2019-06-04 02:47:42 +00:00
|
|
|
flags.push((sym::direct, None));
|
2018-02-11 21:39:32 +00:00
|
|
|
}
|
2017-08-30 21:12:34 +00:00
|
|
|
}
|
|
|
|
|
2017-08-31 18:46:03 +00:00
|
|
|
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) {
|
2018-02-11 21:39:32 +00:00
|
|
|
let method = self.tcx.item_name(item);
|
2019-06-04 02:47:42 +00:00
|
|
|
flags.push((sym::from_method, None));
|
|
|
|
flags.push((sym::from_method, Some(method.to_string())));
|
2017-08-31 18:46:03 +00:00
|
|
|
}
|
|
|
|
}
|
2018-10-11 00:30:10 +00:00
|
|
|
if let Some(t) = self.get_parent_trait_ref(&obligation.cause.code) {
|
2019-06-04 02:47:42 +00:00
|
|
|
flags.push((sym::parent_trait, Some(t)));
|
2018-10-11 00:30:10 +00:00
|
|
|
}
|
2017-08-31 18:46:03 +00:00
|
|
|
|
2019-06-18 22:08:45 +00:00
|
|
|
if let Some(k) = obligation.cause.span.desugaring_kind() {
|
2019-06-04 02:47:42 +00:00
|
|
|
flags.push((sym::from_desugaring, None));
|
2019-07-07 10:02:05 +00:00
|
|
|
flags.push((sym::from_desugaring, Some(format!("{:?}", k))));
|
2018-01-20 03:57:10 +00:00
|
|
|
}
|
|
|
|
let generics = self.tcx.generics_of(def_id);
|
|
|
|
let self_ty = trait_ref.self_ty();
|
2018-02-11 21:39:32 +00:00
|
|
|
// This is also included through the generics list as `Self`,
|
|
|
|
// but the parser won't allow you to use it
|
2019-06-04 02:47:42 +00:00
|
|
|
flags.push((sym::_Self, Some(self_ty.to_string())));
|
2018-02-11 21:39:32 +00:00
|
|
|
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
|
2019-06-04 02:47:42 +00:00
|
|
|
flags.push((sym::_Self, Some(self.tcx.type_of(def.did).to_string())));
|
2018-02-11 21:39:32 +00:00
|
|
|
}
|
2018-01-20 03:57:10 +00:00
|
|
|
|
2018-05-10 22:02:41 +00:00
|
|
|
for param in generics.params.iter() {
|
|
|
|
let value = match param.kind {
|
2019-02-20 01:20:06 +00:00
|
|
|
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
|
|
|
};
|
2019-10-18 02:22:50 +00:00
|
|
|
let name = param.name;
|
2018-05-14 11:49:32 +00:00
|
|
|
flags.push((name, Some(value)));
|
2017-08-30 21:12:34 +00:00
|
|
|
}
|
|
|
|
|
2018-07-14 15:22:53 +00:00
|
|
|
if let Some(true) = self_ty.ty_adt_def().map(|def| def.did.is_local()) {
|
2019-06-04 02:47:42 +00:00
|
|
|
flags.push((sym::crate_local, None));
|
2017-08-30 21:12:34 +00:00
|
|
|
}
|
|
|
|
|
2018-10-22 16:21:55 +00:00
|
|
|
// Allow targeting all integers using `{integral}`, even if the exact type was resolved
|
2018-10-10 01:44:07 +00:00
|
|
|
if self_ty.is_integral() {
|
2019-06-04 02:47:42 +00:00
|
|
|
flags.push((sym::_Self, Some("{integral}".to_owned())));
|
2018-10-10 01:44:07 +00:00
|
|
|
}
|
|
|
|
|
2019-09-16 18:08:35 +00:00
|
|
|
if let ty::Array(aty, len) = self_ty.kind {
|
2019-06-04 02:47:42 +00:00
|
|
|
flags.push((sym::_Self, Some("[]".to_owned())));
|
|
|
|
flags.push((sym::_Self, Some(format!("[{}]", aty))));
|
2018-10-10 01:44:07 +00:00
|
|
|
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((
|
2019-06-04 02:47:42 +00:00
|
|
|
sym::_Self,
|
2018-10-10 01:44:07 +00:00
|
|
|
Some(format!("[{}]", self.tcx.type_of(def.did).to_string())),
|
|
|
|
));
|
2018-10-15 17:12:29 +00:00
|
|
|
let tcx = self.tcx;
|
2019-03-25 23:13:09 +00:00
|
|
|
if let Some(len) = len.try_eval_usize(tcx, ty::ParamEnv::empty()) {
|
2018-10-10 01:44:07 +00:00
|
|
|
flags.push((
|
2019-06-04 02:47:42 +00:00
|
|
|
sym::_Self,
|
2018-10-10 01:44:07 +00:00
|
|
|
Some(format!("[{}; {}]", self.tcx.type_of(def.did).to_string(), len)),
|
|
|
|
));
|
|
|
|
} else {
|
|
|
|
flags.push((
|
2019-06-04 02:47:42 +00:00
|
|
|
sym::_Self,
|
2018-10-10 01:44:07 +00:00
|
|
|
Some(format!("[{}; _]", self.tcx.type_of(def.did).to_string())),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-30 20:40:43 +00:00
|
|
|
if let Ok(Some(command)) = OnUnimplementedDirective::of_item(
|
|
|
|
self.tcx, trait_ref.def_id, def_id
|
2017-08-29 21:44:29 +00:00
|
|
|
) {
|
2018-01-20 03:57:10 +00:00
|
|
|
command.evaluate(self.tcx, trait_ref, &flags[..])
|
2017-08-30 20:40:43 +00:00
|
|
|
} else {
|
2019-11-22 04:34:10 +00:00
|
|
|
OnUnimplementedNote::default()
|
2015-01-10 18:21:27 +00:00
|
|
|
}
|
2015-01-11 19:03:20 +00:00
|
|
|
}
|
2015-01-10 18:21:27 +00:00
|
|
|
|
2019-10-04 00:10:37 +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);
|
2018-09-12 14:57:19 +00:00
|
|
|
let all_impls = self.tcx.all_impls(trait_ref.def_id());
|
2016-05-11 12:33:14 +00:00
|
|
|
|
|
|
|
match simp {
|
2018-09-12 14:57:19 +00:00
|
|
|
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();
|
2019-10-04 00:10:37 +00:00
|
|
|
let imp_simp = fast_reject::simplify_type(self.tcx, imp.self_ty(), true);
|
2016-05-11 12:33:14 +00:00
|
|
|
if let Some(imp_simp) = imp_simp {
|
|
|
|
if simp != imp_simp {
|
2018-09-12 14:57:19 +00:00
|
|
|
return None
|
2016-05-11 12:33:14 +00:00
|
|
|
}
|
|
|
|
}
|
2018-09-12 14:57:19 +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
|
|
|
}
|
|
|
|
|
2019-10-04 00:10:37 +00:00
|
|
|
fn report_similar_impl_candidates(
|
|
|
|
&self,
|
|
|
|
impl_candidates: Vec<ty::TraitRef<'tcx>>,
|
|
|
|
err: &mut DiagnosticBuilder<'_>,
|
|
|
|
) {
|
2016-05-11 05:48:12 +00:00
|
|
|
if impl_candidates.is_empty() {
|
|
|
|
return;
|
|
|
|
}
|
2016-03-16 22:15:31 +00:00
|
|
|
|
2018-08-09 12:37:27 +00:00
|
|
|
let len = impl_candidates.len();
|
2017-02-14 04:32:05 +00:00
|
|
|
let end = if impl_candidates.len() <= 5 {
|
|
|
|
impl_candidates.len()
|
|
|
|
} else {
|
|
|
|
4
|
|
|
|
};
|
2018-03-22 08:56:04 +00:00
|
|
|
|
2019-09-25 19:36:14 +00:00
|
|
|
let normalize = |candidate| self.tcx.infer_ctxt().enter(|ref infcx| {
|
2018-03-22 08:56:04 +00:00
|
|
|
let normalized = infcx
|
|
|
|
.at(&ObligationCause::dummy(), ty::ParamEnv::empty())
|
|
|
|
.normalize(candidate)
|
|
|
|
.ok();
|
|
|
|
match normalized {
|
|
|
|
Some(normalized) => format!("\n {:?}", normalized.value),
|
|
|
|
None => format!("\n {:?}", candidate),
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2018-08-09 12:37:27 +00:00
|
|
|
// Sort impl candidates so that ordering is consistent for UI tests.
|
2019-01-21 15:55:32 +00:00
|
|
|
let mut normalized_impl_candidates = impl_candidates
|
2018-08-09 12:37:27 +00:00
|
|
|
.iter()
|
|
|
|
.map(normalize)
|
|
|
|
.collect::<Vec<String>>();
|
2019-01-21 15:55:32 +00:00
|
|
|
|
|
|
|
// 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
|
2018-08-09 12:37:27 +00:00
|
|
|
normalized_impl_candidates.sort();
|
|
|
|
|
2017-01-13 19:40:44 +00:00
|
|
|
err.help(&format!("the following implementations were found:{}{}",
|
2019-01-21 15:55:32 +00:00
|
|
|
normalized_impl_candidates[..end].join(""),
|
2018-08-09 12:37:27 +00:00
|
|
|
if len > 5 {
|
|
|
|
format!("\nand {} others", len - 4)
|
2017-01-13 19:40:44 +00:00
|
|
|
} else {
|
2018-08-23 08:14:52 +00:00
|
|
|
String::new()
|
2017-01-13 19:40:44 +00:00
|
|
|
}
|
|
|
|
));
|
2016-04-05 20:19:29 +00:00
|
|
|
}
|
|
|
|
|
2016-05-11 05:48:12 +00:00
|
|
|
/// 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.
|
2019-10-11 02:33:05 +00:00
|
|
|
pub fn report_overflow_error<T>(
|
|
|
|
&self,
|
|
|
|
obligation: &Obligation<'tcx, T>,
|
|
|
|
suggest_increasing_limit: bool,
|
|
|
|
) -> !
|
2016-05-11 05:48:12 +00:00
|
|
|
where T: fmt::Display + TypeFoldable<'tcx>
|
|
|
|
{
|
|
|
|
let predicate =
|
2019-05-11 18:08:26 +00:00
|
|
|
self.resolve_vars_if_possible(&obligation.predicate);
|
2019-10-11 02:33:05 +00:00
|
|
|
let mut err = struct_span_err!(
|
|
|
|
self.tcx.sess,
|
|
|
|
obligation.cause.span,
|
|
|
|
E0275,
|
|
|
|
"overflow evaluating the requirement `{}`",
|
|
|
|
predicate
|
|
|
|
);
|
2015-03-20 10:48:40 +00:00
|
|
|
|
2016-05-11 05:48:12 +00:00
|
|
|
if suggest_increasing_limit {
|
|
|
|
self.suggest_new_overflow_limit(&mut err);
|
|
|
|
}
|
2015-03-20 10:48:40 +00:00
|
|
|
|
2019-10-11 02:33:05 +00:00
|
|
|
self.note_obligation_cause_code(
|
|
|
|
&mut err,
|
|
|
|
&obligation.predicate,
|
|
|
|
&obligation.cause.code,
|
|
|
|
&mut vec![],
|
|
|
|
);
|
2015-03-20 10:48:40 +00:00
|
|
|
|
2016-05-11 05:48:12 +00:00
|
|
|
err.emit();
|
|
|
|
self.tcx.sess.abort_if_errors();
|
|
|
|
bug!();
|
|
|
|
}
|
2016-01-09 02:41:37 +00:00
|
|
|
|
2016-05-11 05:48:12 +00:00
|
|
|
/// 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).
|
2016-05-05 09:31:45 +00:00
|
|
|
pub fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! {
|
2019-05-11 18:08:26 +00:00
|
|
|
let cycle = self.resolve_vars_if_possible(&cycle.to_owned());
|
2016-05-07 21:52:45 +00:00
|
|
|
assert!(cycle.len() > 0);
|
2016-01-09 02:41:37 +00:00
|
|
|
|
2016-05-11 05:48:12 +00:00
|
|
|
debug!("report_overflow_error_cycle: cycle={:?}", cycle);
|
2016-01-09 02:41:37 +00:00
|
|
|
|
2016-05-11 05:48:12 +00:00
|
|
|
self.report_overflow_error(&cycle[0], false);
|
2016-01-09 02:41:37 +00:00
|
|
|
}
|
|
|
|
|
2016-10-05 14:17:14 +00:00
|
|
|
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)
|
2016-10-05 14:17:14 +00:00
|
|
|
-> DiagnosticBuilder<'tcx>
|
|
|
|
{
|
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);
|
2017-12-18 06:33:56 +00:00
|
|
|
|
|
|
|
let mut err = struct_span_err!(self.tcx.sess, sp, E0276, "{}", msg);
|
2016-10-05 14:17:14 +00:00
|
|
|
|
2018-12-04 12:45:36 +00:00
|
|
|
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);
|
2017-05-04 12:17:23 +00:00
|
|
|
err.span_label(span, format!("definition of `{}` from trait", item_name));
|
2016-10-05 14:17:14 +00:00
|
|
|
}
|
|
|
|
|
2017-12-18 06:33:56 +00:00
|
|
|
err.span_label(sp, format!("impl has extra requirement {}", requirement));
|
2016-10-05 14:17:14 +00:00
|
|
|
|
|
|
|
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) => {
|
2019-05-11 18:08:26 +00:00
|
|
|
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,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-05 23:17:08 +00:00
|
|
|
pub fn report_selection_error(
|
|
|
|
&self,
|
|
|
|
obligation: &PredicateObligation<'tcx>,
|
|
|
|
error: &SelectionError<'tcx>,
|
|
|
|
fallback_has_occurred: bool,
|
2019-09-16 22:54:31 +00:00
|
|
|
points_at_arg: bool,
|
2019-02-05 23:17:08 +00:00
|
|
|
) {
|
2019-11-22 04:34:10 +00:00
|
|
|
let tcx = self.tcx;
|
2016-05-11 05:48:12 +00:00
|
|
|
let span = obligation.cause.span;
|
2016-12-12 22:51:40 +00:00
|
|
|
|
2016-05-11 05:48:12 +00:00
|
|
|
let mut err = match *error {
|
|
|
|
SelectionError::Unimplemented => {
|
2016-10-05 14:17:14 +00:00
|
|
|
if let ObligationCauseCode::CompareImplMethodObligation {
|
2017-11-01 18:23:30 +00:00
|
|
|
item_name, impl_item_def_id, trait_item_def_id,
|
2016-10-05 14:17:14 +00:00
|
|
|
} = obligation.cause.code {
|
|
|
|
self.report_extra_impl_obligation(
|
|
|
|
span,
|
|
|
|
item_name,
|
|
|
|
impl_item_def_id,
|
|
|
|
trait_item_def_id,
|
2017-11-01 18:23:30 +00:00
|
|
|
&format!("`{}`", obligation.predicate))
|
2016-10-05 14:17:14 +00:00
|
|
|
.emit();
|
2016-05-11 05:48:12 +00:00
|
|
|
return;
|
2017-02-19 03:48:36 +00:00
|
|
|
}
|
|
|
|
match obligation.predicate {
|
|
|
|
ty::Predicate::Trait(ref trait_predicate) => {
|
2019-10-16 01:27:42 +00:00
|
|
|
let trait_predicate = self.resolve_vars_if_possible(trait_predicate);
|
2015-08-07 14:28:51 +00:00
|
|
|
|
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();
|
2019-10-16 01:27:42 +00:00
|
|
|
let (
|
|
|
|
post_message,
|
|
|
|
pre_message,
|
|
|
|
) = self.get_parent_trait_ref(&obligation.cause.code)
|
2019-10-16 01:42:27 +00:00
|
|
|
.map(|t| (format!(" in `{}`", t), format!("within `{}`, ", t)))
|
2018-10-12 14:16:00 +00:00
|
|
|
.unwrap_or_default();
|
2017-08-30 20:40:43 +00:00
|
|
|
|
2019-10-16 01:27:42 +00:00
|
|
|
let OnUnimplementedNote {
|
|
|
|
message,
|
|
|
|
label,
|
|
|
|
note,
|
2019-11-22 04:34:10 +00:00
|
|
|
enclosing_scope,
|
2019-10-16 01:27:42 +00:00
|
|
|
} = self.on_unimplemented_note(trait_ref, obligation);
|
2017-08-30 20:40:43 +00:00
|
|
|
let have_alt_message = message.is_some() || label.is_some();
|
2019-04-18 02:50:50 +00:00
|
|
|
let is_try = self.tcx.sess.source_map().span_to_snippet(span)
|
|
|
|
.map(|s| &s == "?")
|
|
|
|
.unwrap_or(false);
|
2019-11-21 18:01:14 +00:00
|
|
|
let is_from =
|
|
|
|
format!("{}", trait_ref.print_only_trait_path())
|
|
|
|
.starts_with("std::convert::From<");
|
2019-05-17 19:18:56 +00:00
|
|
|
let (message, note) = if is_try && is_from {
|
|
|
|
(Some(format!(
|
2019-04-18 02:50:50 +00:00
|
|
|
"`?` couldn't convert the error to `{}`",
|
|
|
|
trait_ref.self_ty(),
|
2019-05-17 19:18:56 +00:00
|
|
|
)), Some(
|
|
|
|
"the question mark operation (`?`) implicitly performs a \
|
|
|
|
conversion on the error value using the `From` trait".to_owned()
|
2019-04-18 02:50:50 +00:00
|
|
|
))
|
|
|
|
} else {
|
2019-05-17 19:18:56 +00:00
|
|
|
(message, note)
|
2019-04-18 02:50:50 +00:00
|
|
|
};
|
2017-08-30 20:40:43 +00:00
|
|
|
|
2017-02-19 15:46:43 +00:00
|
|
|
let mut err = struct_span_err!(
|
|
|
|
self.tcx.sess,
|
|
|
|
span,
|
|
|
|
E0277,
|
2017-08-30 20:40:43 +00:00
|
|
|
"{}",
|
2019-08-24 21:44:43 +00:00
|
|
|
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
|
|
|
|
2018-03-22 04:28:48 +00:00
|
|
|
let explanation =
|
|
|
|
if obligation.cause.code == ObligationCauseCode::MainFunctionType {
|
2018-03-21 18:32:46 +00:00
|
|
|
"consider using `()`, or a `Result`".to_owned()
|
2018-03-22 04:28:48 +00:00
|
|
|
} else {
|
2019-08-24 21:44:43 +00:00
|
|
|
format!(
|
|
|
|
"{}the trait `{}` is not implemented for `{}`",
|
2019-08-24 21:45:03 +00:00
|
|
|
pre_message,
|
2019-11-21 18:01:14 +00:00
|
|
|
trait_ref.print_only_trait_path(),
|
2019-08-24 21:44:43 +00:00
|
|
|
trait_ref.self_ty(),
|
|
|
|
)
|
2018-03-22 04:28:48 +00:00
|
|
|
};
|
2018-03-21 18:32:46 +00:00
|
|
|
|
2019-10-16 03:35:54 +00:00
|
|
|
if self.suggest_add_reference_to_arg(
|
|
|
|
&obligation,
|
|
|
|
&mut err,
|
|
|
|
&trait_ref,
|
|
|
|
points_at_arg,
|
2019-10-27 20:42:20 +00:00
|
|
|
have_alt_message,
|
2019-10-16 03:35:54 +00:00
|
|
|
) {
|
|
|
|
self.note_obligation_cause(&mut err, obligation);
|
|
|
|
err.emit();
|
|
|
|
return;
|
|
|
|
}
|
2017-08-30 20:40:43 +00:00
|
|
|
if let Some(ref s) = label {
|
2019-02-28 22:43:53 +00:00
|
|
|
// If it has a custom `#[rustc_on_unimplemented]`
|
2017-04-26 16:42:27 +00:00
|
|
|
// error message, let's display it as the label!
|
|
|
|
err.span_label(span, s.as_str());
|
2018-03-21 18:32:46 +00:00
|
|
|
err.help(&explanation);
|
2017-04-26 16:42:27 +00:00
|
|
|
} else {
|
2018-03-21 18:32:46 +00:00
|
|
|
err.span_label(span, explanation);
|
2017-04-26 16:42:27 +00:00
|
|
|
}
|
2018-01-20 03:57:10 +00:00
|
|
|
if let Some(ref s) = note {
|
2019-02-28 22:43:53 +00:00
|
|
|
// If it has a custom `#[rustc_on_unimplemented]` note, let's display it
|
2018-01-20 03:57:10 +00:00
|
|
|
err.note(s.as_str());
|
|
|
|
}
|
2019-11-22 04:34:10 +00:00
|
|
|
if let Some(ref s) = enclosing_scope {
|
|
|
|
let enclosing_scope_span = tcx.def_span(
|
|
|
|
tcx.hir()
|
|
|
|
.opt_local_def_id(obligation.cause.body_id)
|
|
|
|
.unwrap_or_else(|| {
|
|
|
|
tcx.hir().body_owner_def_id(hir::BodyId {
|
|
|
|
hir_id: obligation.cause.body_id,
|
|
|
|
})
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
|
|
|
|
err.span_label(enclosing_scope_span, s.as_str());
|
|
|
|
}
|
2017-04-26 16:42:27 +00:00
|
|
|
|
2017-11-24 22:47:40 +00:00
|
|
|
self.suggest_borrow_on_unsized_slice(&obligation.cause.code, &mut err);
|
2019-09-16 22:54:31 +00:00
|
|
|
self.suggest_fn_call(&obligation, &mut err, &trait_ref, points_at_arg);
|
2018-02-09 18:04:12 +00:00
|
|
|
self.suggest_remove_reference(&obligation, &mut err, &trait_ref);
|
2019-03-04 21:39:52 +00:00
|
|
|
self.suggest_semicolon_removal(&obligation, &mut err, span, &trait_ref);
|
2019-11-03 22:06:48 +00:00
|
|
|
self.note_version_mismatch(&mut err, &trait_ref);
|
2017-11-24 22:47:40 +00:00
|
|
|
|
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.
|
2019-10-07 21:23:56 +00:00
|
|
|
self.suggest_restricting_param_bound(
|
|
|
|
&mut err,
|
|
|
|
&trait_ref,
|
|
|
|
obligation.cause.body_id,
|
|
|
|
);
|
2019-10-04 00:10:37 +00:00
|
|
|
} 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);
|
|
|
|
}
|
|
|
|
self.suggest_change_mut(
|
|
|
|
&obligation,
|
|
|
|
&mut err,
|
|
|
|
&trait_ref,
|
|
|
|
points_at_arg,
|
|
|
|
);
|
2016-01-21 09:57:21 +00:00
|
|
|
}
|
2017-04-10 21:17:49 +00:00
|
|
|
|
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
|
|
|
|
{
|
2018-03-12 04:15:06 +00:00
|
|
|
let predicate = trait_predicate.map_bound(|mut trait_pred| {
|
2018-05-16 06:34:09 +00:00
|
|
|
trait_pred.trait_ref.substs = self.tcx.mk_substs_trait(
|
2018-09-10 02:07:13 +00:00
|
|
|
self.tcx.mk_unit(),
|
2018-05-16 06:34:09 +00:00
|
|
|
&trait_pred.trait_ref.substs[1..],
|
|
|
|
);
|
2018-03-12 04:15:06 +00:00
|
|
|
trait_pred
|
|
|
|
});
|
|
|
|
let unit_obligation = Obligation {
|
2018-03-14 04:03:33 +00:00
|
|
|
predicate: ty::Predicate::Trait(predicate),
|
|
|
|
.. obligation.clone()
|
2018-03-12 04:15:06 +00:00
|
|
|
};
|
2018-04-08 06:56:27 +00:00
|
|
|
if self.predicate_may_hold(&unit_obligation) {
|
2018-03-12 04:15:06 +00:00
|
|
|
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
|
|
|
}
|
2016-01-21 09:57:21 +00:00
|
|
|
|
2017-03-10 02:47:09 +00:00
|
|
|
ty::Predicate::Subtype(ref predicate) => {
|
generalize type variables too
When we are generalizing a super/sub-type, we have to replace type
variables with a fresh variable (and not just region variables). So if
we know that `Box<?T> <: ?U`, for example, we instantiate `?U` with
`Box<?V>` and then relate `Box<?T>` to `Box<?V>` (and hence require that
`?T <: ?V`).
This change has some complex interactions, however:
First, the occurs check must be updated to detect constraints like `?T
<: ?U` and `?U <: Box<?T>`. If we're not careful, we'll create a
never-ending sequence of new variables. To address this, we add a second
unification set into `type_variables` that tracks type variables related
through **either** equality **or** subtyping, and use that during the
occurs-check.
Second, the "fudge regions if ok" code was expecting no new type
variables to be created. It must be updated to create new type variables
outside of the probe. This is relatively straight-forward under the new
scheme, since type variables are now independent from one another, and
any relations are moderated by pending subtype obliations and so forth.
This part would be tricky to backport though.
cc #18653
cc #40951
2017-04-11 21:17:58 +00:00
|
|
|
// 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) => {
|
2019-05-11 18:08:26 +00:00
|
|
|
let predicate = self.resolve_vars_if_possible(predicate);
|
2019-02-20 10:22:23 +00:00
|
|
|
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
|
|
|
}
|
2015-01-14 21:43:17 +00:00
|
|
|
|
2017-02-19 03:48:36 +00:00
|
|
|
ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => {
|
|
|
|
let predicate =
|
2019-05-11 18:08:26 +00:00
|
|
|
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)
|
|
|
|
}
|
2015-08-07 14:28:51 +00:00
|
|
|
|
2017-02-19 03:48:36 +00:00
|
|
|
ty::Predicate::ObjectSafe(trait_def_id) => {
|
2019-09-25 19:36:14 +00:00
|
|
|
let violations = self.tcx.object_safety_violations(trait_def_id);
|
2019-01-08 21:14:04 +00:00
|
|
|
self.tcx.report_object_safety_error(
|
2019-03-05 03:24:52 +00:00
|
|
|
span,
|
|
|
|
trait_def_id,
|
|
|
|
violations,
|
2019-01-08 21:14:04 +00:00
|
|
|
)
|
2017-02-19 03:48:36 +00:00
|
|
|
}
|
2015-08-07 14:28:51 +00:00
|
|
|
|
2017-11-08 14:45:48 +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()
|
2018-12-04 12:45:36 +00:00
|
|
|
.def_span(self.tcx.hir().span_if_local(closure_def_id).unwrap());
|
2019-03-04 08:00:30 +00:00
|
|
|
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, \
|
2018-09-12 14:57:19 +00:00
|
|
|
but this closure only implements `{}`",
|
2017-02-19 03:48:36 +00:00
|
|
|
kind,
|
|
|
|
found_kind);
|
2017-06-05 10:14:48 +00:00
|
|
|
|
2017-12-18 06:22:24 +00:00
|
|
|
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.
|
2017-06-09 07:55:16 +00:00
|
|
|
if let Some(tables) = self.in_progress_tables {
|
2017-08-07 13:50:13 +00:00
|
|
|
let tables = tables.borrow();
|
2019-03-04 08:00:30 +00:00
|
|
|
match (found_kind, tables.closure_kind_origins().get(hir_id)) {
|
2017-11-08 17:36:28 +00:00
|
|
|
(ty::ClosureKind::FnOnce, Some((span, name))) => {
|
2017-12-18 06:22:24 +00:00
|
|
|
err.span_label(*span, format!(
|
2017-06-06 08:06:56 +00:00
|
|
|
"closure is `FnOnce` because it moves the \
|
|
|
|
variable `{}` out of its environment", name));
|
|
|
|
},
|
2017-11-08 17:36:28 +00:00
|
|
|
(ty::ClosureKind::FnMut, Some((span, name))) => {
|
2017-12-18 06:22:24 +00:00
|
|
|
err.span_label(*span, format!(
|
2017-06-06 08:06:56 +00:00
|
|
|
"closure is `FnMut` because it mutates the \
|
|
|
|
variable `{}` here", name));
|
|
|
|
},
|
|
|
|
_ => {}
|
2017-06-05 10:14:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-19 03:48:36 +00:00
|
|
|
err.emit();
|
|
|
|
return;
|
|
|
|
}
|
2016-04-06 07:20:59 +00:00
|
|
|
|
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)
|
|
|
|
)
|
|
|
|
}
|
2016-05-01 06:59:28 +00:00
|
|
|
}
|
2017-08-07 05:08:53 +00:00
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
2015-01-14 21:43:17 +00:00
|
|
|
|
2017-10-06 15:26:41 +00:00
|
|
|
OutputTypeParameterMismatch(ref found_trait_ref, ref expected_trait_ref, _) => {
|
2019-05-11 18:08:26 +00:00
|
|
|
let found_trait_ref = self.resolve_vars_if_possible(&*found_trait_ref);
|
|
|
|
let expected_trait_ref = self.resolve_vars_if_possible(&*expected_trait_ref);
|
2018-09-12 14:57:19 +00:00
|
|
|
|
2017-10-06 15:26:41 +00:00
|
|
|
if expected_trait_ref.self_ty().references_error() {
|
2016-05-11 05:48:12 +00:00
|
|
|
return;
|
|
|
|
}
|
2018-09-12 14:57:19 +00:00
|
|
|
|
2017-10-06 15:26:41 +00:00
|
|
|
let found_trait_ty = found_trait_ref.self_ty();
|
2017-10-06 14:57:00 +00:00
|
|
|
|
2019-09-16 18:08:35 +00:00
|
|
|
let found_did = match found_trait_ty.kind {
|
2018-09-12 14:57:19 +00:00
|
|
|
ty::Closure(did, _) | ty::Foreign(did) | ty::FnDef(did, _) => Some(did),
|
2018-08-22 00:35:02 +00:00
|
|
|
ty::Adt(def, _) => Some(def.did),
|
2018-07-14 15:22:53 +00:00
|
|
|
_ => None,
|
|
|
|
};
|
2018-09-12 14:57:19 +00:00
|
|
|
|
|
|
|
let found_span = found_did.and_then(|did|
|
2018-12-04 12:45:36 +00:00
|
|
|
self.tcx.hir().span_if_local(did)
|
2018-09-12 14:57:19 +00:00
|
|
|
).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
|
|
|
|
2019-10-01 00:48:22 +00:00
|
|
|
if self.reported_closure_mismatch.borrow().contains(&(span, found_span)) {
|
|
|
|
// We check closures twice, with obligations flowing in different directions,
|
|
|
|
// but we want to complain about them only once.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
self.reported_closure_mismatch.borrow_mut().insert((span, found_span));
|
|
|
|
|
2019-09-16 18:08:35 +00:00
|
|
|
let found = match found_trait_ref.skip_binder().substs.type_at(1).kind {
|
2018-09-12 14:57:19 +00:00
|
|
|
ty::Tuple(ref tys) => vec![ArgKind::empty(); tys.len()],
|
2018-01-19 09:28:20 +00:00
|
|
|
_ => vec![ArgKind::empty()],
|
|
|
|
};
|
2018-09-12 14:57:19 +00:00
|
|
|
|
2018-12-07 17:14:30 +00:00
|
|
|
let expected_ty = expected_trait_ref.skip_binder().substs.type_at(1);
|
2019-09-16 18:08:35 +00:00
|
|
|
let expected = match expected_ty.kind {
|
2018-08-22 00:35:02 +00:00
|
|
|
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(),
|
2018-12-07 17:14:30 +00:00
|
|
|
_ => vec![ArgKind::Arg("_".to_owned(), expected_ty.to_string())],
|
2018-01-19 09:28:20 +00:00
|
|
|
};
|
2018-09-12 14:57:19 +00:00
|
|
|
|
2018-02-15 22:42:22 +00:00
|
|
|
if found.len() == expected.len() {
|
2017-09-23 01:15:30 +00:00
|
|
|
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 {
|
2018-01-19 09:28:20 +00:00
|
|
|
let (closure_span, found) = found_did
|
2018-12-04 12:45:36 +00:00
|
|
|
.and_then(|did| self.tcx.hir().get_if_local(did))
|
2018-02-07 07:34:45 +00:00
|
|
|
.map(|node| {
|
|
|
|
let (found_span, found) = self.get_fn_like_arguments(node);
|
|
|
|
(Some(found_span), found)
|
|
|
|
}).unwrap_or((found_span, found));
|
2018-01-19 09:28:20 +00:00
|
|
|
|
|
|
|
self.report_arg_count_mismatch(span,
|
|
|
|
closure_span,
|
|
|
|
expected,
|
|
|
|
found,
|
|
|
|
found_trait_ty.is_closure())
|
2017-04-23 22:36:35 +00:00
|
|
|
}
|
2016-05-11 05:48:12 +00:00
|
|
|
}
|
2015-04-14 23:57:29 +00:00
|
|
|
|
2016-05-11 05:48:12 +00:00
|
|
|
TraitNotObjectSafe(did) => {
|
2019-09-25 19:36:14 +00:00
|
|
|
let violations = self.tcx.object_safety_violations(did);
|
2019-01-08 21:14:04 +00:00
|
|
|
self.tcx.report_object_safety_error(span, did, violations)
|
2016-05-01 06:59:28 +00:00
|
|
|
}
|
2017-08-07 05:08:53 +00:00
|
|
|
|
2018-08-26 13:19:34 +00:00
|
|
|
// already reported in the query
|
2019-05-30 22:43:04 +00:00
|
|
|
ConstEvalFailure(err) => {
|
|
|
|
self.tcx.sess.delay_span_bug(
|
|
|
|
span,
|
|
|
|
&format!("constant in type had an ignored error: {:?}", err),
|
|
|
|
);
|
2018-08-26 13:19:34 +00:00
|
|
|
return;
|
2017-08-07 05:08:53 +00:00
|
|
|
}
|
2018-04-05 17:29:18 +00:00
|
|
|
|
2018-04-19 07:49:21 +00:00
|
|
|
Overflow => {
|
2018-04-05 17:29:18 +00:00
|
|
|
bug!("overflow should be handled before the `report_selection_error` path");
|
|
|
|
}
|
2016-05-11 05:48:12 +00:00
|
|
|
};
|
2019-09-25 12:58:41 +00:00
|
|
|
|
2016-05-11 05:48:12 +00:00
|
|
|
self.note_obligation_cause(&mut err, obligation);
|
2019-09-25 12:58:41 +00:00
|
|
|
|
2016-05-11 05:48:12 +00:00
|
|
|
err.emit();
|
|
|
|
}
|
2017-04-24 00:54:32 +00:00
|
|
|
|
2019-11-03 22:06:48 +00:00
|
|
|
/// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait
|
|
|
|
/// with the same path as `trait_ref`, a help message about
|
|
|
|
/// a probable version mismatch is added to `err`
|
|
|
|
fn note_version_mismatch(
|
|
|
|
&self,
|
|
|
|
err: &mut DiagnosticBuilder<'_>,
|
|
|
|
trait_ref: &ty::PolyTraitRef<'tcx>,
|
|
|
|
) {
|
|
|
|
let get_trait_impl = |trait_def_id| {
|
|
|
|
let mut trait_impl = None;
|
|
|
|
self.tcx.for_each_relevant_impl(trait_def_id, trait_ref.self_ty(), |impl_def_id| {
|
|
|
|
if trait_impl.is_none() {
|
|
|
|
trait_impl = Some(impl_def_id);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
trait_impl
|
|
|
|
};
|
|
|
|
let required_trait_path = self.tcx.def_path_str(trait_ref.def_id());
|
|
|
|
let all_traits = self.tcx.all_traits(LOCAL_CRATE);
|
|
|
|
let traits_with_same_path: std::collections::BTreeSet<_> = all_traits
|
|
|
|
.iter()
|
|
|
|
.filter(|trait_def_id| **trait_def_id != trait_ref.def_id())
|
|
|
|
.filter(|trait_def_id| self.tcx.def_path_str(**trait_def_id) == required_trait_path)
|
|
|
|
.collect();
|
|
|
|
for trait_with_same_path in traits_with_same_path {
|
|
|
|
if let Some(impl_def_id) = get_trait_impl(*trait_with_same_path) {
|
|
|
|
let impl_span = self.tcx.def_span(impl_def_id);
|
2019-11-24 12:01:24 +00:00
|
|
|
err.span_help(impl_span, "trait impl with same name found");
|
2019-11-03 22:06:48 +00:00
|
|
|
let trait_crate = self.tcx.crate_name(trait_with_same_path.krate);
|
|
|
|
let crate_msg = format!(
|
|
|
|
"Perhaps two different versions of crate `{}` are being used?",
|
|
|
|
trait_crate
|
|
|
|
);
|
|
|
|
err.note(&crate_msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-10-07 21:23:56 +00:00
|
|
|
fn suggest_restricting_param_bound(
|
|
|
|
&self,
|
2019-11-20 01:11:55 +00:00
|
|
|
mut err: &mut DiagnosticBuilder<'_>,
|
2019-10-07 21:23:56 +00:00
|
|
|
trait_ref: &ty::PolyTraitRef<'_>,
|
|
|
|
body_id: hir::HirId,
|
|
|
|
) {
|
2019-10-15 20:16:33 +00:00
|
|
|
let self_ty = trait_ref.self_ty();
|
|
|
|
let (param_ty, projection) = match &self_ty.kind {
|
|
|
|
ty::Param(_) => (true, None),
|
|
|
|
ty::Projection(projection) => (false, Some(projection)),
|
2019-10-10 20:17:51 +00:00
|
|
|
_ => return,
|
2019-10-08 22:22:27 +00:00
|
|
|
};
|
|
|
|
|
2019-11-20 01:11:55 +00:00
|
|
|
let suggest_restriction = |
|
|
|
|
generics: &hir::Generics,
|
|
|
|
msg,
|
|
|
|
err: &mut DiagnosticBuilder<'_>,
|
|
|
|
| {
|
2019-10-15 20:29:07 +00:00
|
|
|
let span = generics.where_clause.span_for_predicates_or_empty_place();
|
|
|
|
if !span.from_expansion() && span.desugaring_kind().is_none() {
|
|
|
|
err.span_suggestion(
|
|
|
|
generics.where_clause.span_for_predicates_or_empty_place().shrink_to_hi(),
|
|
|
|
&format!("consider further restricting {}", msg),
|
|
|
|
format!(
|
|
|
|
"{} {} ",
|
|
|
|
if !generics.where_clause.predicates.is_empty() {
|
|
|
|
","
|
|
|
|
} else {
|
|
|
|
" where"
|
|
|
|
},
|
|
|
|
trait_ref.to_predicate(),
|
|
|
|
),
|
|
|
|
Applicability::MachineApplicable,
|
|
|
|
);
|
|
|
|
}
|
2019-10-10 16:50:45 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// FIXME: Add check for trait bound that is already present, particularly `?Sized` so we
|
|
|
|
// don't suggest `T: Sized + ?Sized`.
|
2019-10-08 22:22:27 +00:00
|
|
|
let mut hir_id = body_id;
|
|
|
|
while let Some(node) = self.tcx.hir().find(hir_id) {
|
|
|
|
match node {
|
2019-10-08 23:03:38 +00:00
|
|
|
hir::Node::TraitItem(hir::TraitItem {
|
|
|
|
generics,
|
2019-10-10 16:50:45 +00:00
|
|
|
kind: hir::TraitItemKind::Method(..), ..
|
2019-10-15 20:16:33 +00:00
|
|
|
}) if param_ty && self_ty == self.tcx.types.self_param => {
|
2019-10-10 16:50:45 +00:00
|
|
|
// Restricting `Self` for a single method.
|
2019-11-20 01:11:55 +00:00
|
|
|
suggest_restriction(&generics, "`Self`", err);
|
2019-10-08 23:03:38 +00:00
|
|
|
return;
|
|
|
|
}
|
2019-10-10 16:50:45 +00:00
|
|
|
|
2019-10-09 22:07:22 +00:00
|
|
|
hir::Node::Item(hir::Item {
|
2019-11-07 11:57:52 +00:00
|
|
|
kind: hir::ItemKind::Fn(_, generics, _), ..
|
2019-10-09 22:07:22 +00:00
|
|
|
}) |
|
|
|
|
hir::Node::TraitItem(hir::TraitItem {
|
|
|
|
generics,
|
2019-10-10 16:50:45 +00:00
|
|
|
kind: hir::TraitItemKind::Method(..), ..
|
2019-10-09 22:07:22 +00:00
|
|
|
}) |
|
|
|
|
hir::Node::ImplItem(hir::ImplItem {
|
|
|
|
generics,
|
2019-10-10 16:50:45 +00:00
|
|
|
kind: hir::ImplItemKind::Method(..), ..
|
|
|
|
}) |
|
|
|
|
hir::Node::Item(hir::Item {
|
|
|
|
kind: hir::ItemKind::Trait(_, _, generics, _, _), ..
|
|
|
|
}) |
|
2019-10-09 22:54:23 +00:00
|
|
|
hir::Node::Item(hir::Item {
|
|
|
|
kind: hir::ItemKind::Impl(_, _, _, generics, ..), ..
|
|
|
|
}) if projection.is_some() => {
|
2019-10-10 16:50:45 +00:00
|
|
|
// Missing associated type bound.
|
2019-11-20 01:11:55 +00:00
|
|
|
suggest_restriction(&generics, "the associated type", err);
|
2019-10-09 22:54:23 +00:00
|
|
|
return;
|
|
|
|
}
|
2019-10-10 16:50:45 +00:00
|
|
|
|
2019-10-08 22:22:27 +00:00
|
|
|
hir::Node::Item(hir::Item { kind: hir::ItemKind::Struct(_, generics), span, .. }) |
|
|
|
|
hir::Node::Item(hir::Item { kind: hir::ItemKind::Enum(_, generics), span, .. }) |
|
|
|
|
hir::Node::Item(hir::Item { kind: hir::ItemKind::Union(_, generics), span, .. }) |
|
|
|
|
hir::Node::Item(hir::Item {
|
|
|
|
kind: hir::ItemKind::Trait(_, _, generics, ..), span, ..
|
|
|
|
}) |
|
|
|
|
hir::Node::Item(hir::Item {
|
|
|
|
kind: hir::ItemKind::Impl(_, _, _, generics, ..), span, ..
|
|
|
|
}) |
|
|
|
|
hir::Node::Item(hir::Item {
|
2019-11-07 11:57:52 +00:00
|
|
|
kind: hir::ItemKind::Fn(_, generics, _), span, ..
|
2019-10-08 22:22:27 +00:00
|
|
|
}) |
|
|
|
|
hir::Node::Item(hir::Item {
|
|
|
|
kind: hir::ItemKind::TyAlias(_, generics), span, ..
|
|
|
|
}) |
|
2019-10-08 23:13:20 +00:00
|
|
|
hir::Node::Item(hir::Item {
|
|
|
|
kind: hir::ItemKind::TraitAlias(generics, _), span, ..
|
|
|
|
}) |
|
2019-10-08 22:22:27 +00:00
|
|
|
hir::Node::Item(hir::Item {
|
|
|
|
kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }), span, ..
|
|
|
|
}) |
|
|
|
|
hir::Node::TraitItem(hir::TraitItem { generics, span, .. }) |
|
2019-10-09 22:07:22 +00:00
|
|
|
hir::Node::ImplItem(hir::ImplItem { generics, span, .. })
|
2019-10-15 20:16:33 +00:00
|
|
|
if param_ty => {
|
2019-10-10 16:50:45 +00:00
|
|
|
// Missing generic type parameter bound.
|
2019-10-15 20:16:33 +00:00
|
|
|
let param_name = self_ty.to_string();
|
2019-11-21 18:01:14 +00:00
|
|
|
let constraint = trait_ref.print_only_trait_path().to_string();
|
2019-11-24 05:44:28 +00:00
|
|
|
if suggest_constraining_type_param(
|
|
|
|
generics,
|
2019-11-20 01:11:55 +00:00
|
|
|
&mut err,
|
|
|
|
¶m_name,
|
|
|
|
&constraint,
|
|
|
|
self.tcx.sess.source_map(),
|
|
|
|
*span,
|
|
|
|
) {
|
2019-10-10 16:50:45 +00:00
|
|
|
return;
|
2019-10-07 21:23:56 +00:00
|
|
|
}
|
|
|
|
}
|
2019-10-10 16:50:45 +00:00
|
|
|
|
2019-10-08 22:22:27 +00:00
|
|
|
hir::Node::Crate => return,
|
2019-10-10 16:50:45 +00:00
|
|
|
|
2019-10-08 22:22:27 +00:00
|
|
|
_ => {}
|
2019-10-07 21:23:56 +00:00
|
|
|
}
|
2019-10-08 22:22:27 +00:00
|
|
|
|
|
|
|
hir_id = self.tcx.hir().get_parent_item(hir_id);
|
2019-10-07 21:23:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-24 22:47:40 +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.
|
2019-03-04 21:39:52 +00:00
|
|
|
fn suggest_borrow_on_unsized_slice(
|
|
|
|
&self,
|
|
|
|
code: &ObligationCauseCode<'tcx>,
|
|
|
|
err: &mut DiagnosticBuilder<'tcx>,
|
|
|
|
) {
|
2019-06-19 13:25:31 +00:00
|
|
|
if let &ObligationCauseCode::VariableType(hir_id) = code {
|
2019-06-24 07:46:38 +00:00
|
|
|
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) {
|
2017-11-24 22:47:40 +00:00
|
|
|
if let Some(ref expr) = local.init {
|
2019-09-26 13:39:48 +00:00
|
|
|
if let hir::ExprKind::Index(_, _) = expr.kind {
|
2018-08-18 10:14:09 +00:00
|
|
|
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(expr.span) {
|
2019-01-25 21:03:27 +00:00
|
|
|
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
|
|
|
|
);
|
2017-11-24 22:47:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-17 01:10:13 +00:00
|
|
|
fn mk_obligation_for_def_id(
|
|
|
|
&self,
|
|
|
|
def_id: DefId,
|
|
|
|
output_ty: Ty<'tcx>,
|
|
|
|
cause: ObligationCause<'tcx>,
|
|
|
|
param_env: ty::ParamEnv<'tcx>,
|
|
|
|
) -> PredicateObligation<'tcx> {
|
|
|
|
let new_trait_ref = ty::TraitRef {
|
|
|
|
def_id,
|
|
|
|
substs: self.tcx.mk_substs_trait(output_ty, &[]),
|
|
|
|
};
|
|
|
|
Obligation::new(cause, param_env, new_trait_ref.to_predicate())
|
|
|
|
}
|
|
|
|
|
2019-11-17 19:27:48 +00:00
|
|
|
/// Given a closure's `DefId`, return the given name of the closure.
|
|
|
|
///
|
|
|
|
/// This doesn't account for reassignments, but it's only used for suggestions.
|
|
|
|
fn get_closure_name(
|
|
|
|
&self,
|
|
|
|
def_id: DefId,
|
|
|
|
err: &mut DiagnosticBuilder<'_>,
|
|
|
|
msg: &str,
|
|
|
|
) -> Option<String> {
|
|
|
|
let get_name = |err: &mut DiagnosticBuilder<'_>, kind: &hir::PatKind| -> Option<String> {
|
|
|
|
// Get the local name of this closure. This can be inaccurate because
|
|
|
|
// of the possibility of reassignment, but this should be good enough.
|
|
|
|
match &kind {
|
|
|
|
hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, name, None) => {
|
|
|
|
Some(format!("{}", name))
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
err.note(&msg);
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let hir = self.tcx.hir();
|
|
|
|
let hir_id = hir.as_local_hir_id(def_id)?;
|
|
|
|
let parent_node = hir.get_parent_node(hir_id);
|
|
|
|
match hir.find(parent_node) {
|
|
|
|
Some(hir::Node::Stmt(hir::Stmt {
|
|
|
|
kind: hir::StmtKind::Local(local), ..
|
|
|
|
})) => get_name(err, &local.pat.kind),
|
|
|
|
// Different to previous arm because one is `&hir::Local` and the other
|
|
|
|
// is `P<hir::Local>`.
|
|
|
|
Some(hir::Node::Local(local)) => get_name(err, &local.pat.kind),
|
|
|
|
_ => return None,
|
|
|
|
}
|
|
|
|
}
|
2019-11-17 01:10:13 +00:00
|
|
|
|
|
|
|
/// We tried to apply the bound to an `fn` or closure. Check whether calling it would
|
|
|
|
/// evaluate to a type that *would* satisfy the trait binding. If it would, suggest calling
|
|
|
|
/// it: `bar(foo)` → `bar(foo())`. This case is *very* likely to be hit if `foo` is `async`.
|
2019-08-24 21:45:03 +00:00
|
|
|
fn suggest_fn_call(
|
|
|
|
&self,
|
|
|
|
obligation: &PredicateObligation<'tcx>,
|
2019-11-05 02:47:02 +00:00
|
|
|
err: &mut DiagnosticBuilder<'_>,
|
2019-08-24 21:45:03 +00:00
|
|
|
trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
|
2019-09-16 22:54:31 +00:00
|
|
|
points_at_arg: bool,
|
2019-08-24 21:45:03 +00:00
|
|
|
) {
|
|
|
|
let self_ty = trait_ref.self_ty();
|
2019-11-09 02:04:05 +00:00
|
|
|
let (def_id, output_ty, callable) = match self_ty.kind {
|
|
|
|
ty::Closure(def_id, substs) => {
|
|
|
|
(def_id, self.closure_sig(def_id, substs).output(), "closure")
|
|
|
|
}
|
2019-08-24 21:45:03 +00:00
|
|
|
ty::FnDef(def_id, _) => {
|
2019-11-09 02:04:05 +00:00
|
|
|
(def_id, self_ty.fn_sig(self.tcx).output(), "function")
|
|
|
|
}
|
|
|
|
_ => return,
|
|
|
|
};
|
|
|
|
let msg = format!("use parentheses to call the {}", callable);
|
|
|
|
|
2019-11-17 01:10:13 +00:00
|
|
|
let obligation = self.mk_obligation_for_def_id(
|
|
|
|
trait_ref.def_id(),
|
|
|
|
output_ty.skip_binder(),
|
2019-11-09 02:04:05 +00:00
|
|
|
obligation.cause.clone(),
|
|
|
|
obligation.param_env,
|
|
|
|
);
|
2019-11-17 01:10:13 +00:00
|
|
|
|
2019-11-09 02:04:05 +00:00
|
|
|
match self.evaluate_obligation(&obligation) {
|
|
|
|
Ok(EvaluationResult::EvaluatedToOk) |
|
|
|
|
Ok(EvaluationResult::EvaluatedToOkModuloRegions) |
|
2019-11-17 01:10:13 +00:00
|
|
|
Ok(EvaluationResult::EvaluatedToAmbig) => {}
|
|
|
|
_ => return,
|
|
|
|
}
|
|
|
|
let hir = self.tcx.hir();
|
|
|
|
// Get the name of the callable and the arguments to be used in the suggestion.
|
|
|
|
let snippet = match hir.get_if_local(def_id) {
|
|
|
|
Some(hir::Node::Expr(hir::Expr {
|
|
|
|
kind: hir::ExprKind::Closure(_, decl, _, span, ..),
|
|
|
|
..
|
|
|
|
})) => {
|
|
|
|
err.span_label(*span, "consider calling this closure");
|
2019-11-17 19:27:48 +00:00
|
|
|
let name = match self.get_closure_name(def_id, err, &msg) {
|
|
|
|
Some(name) => name,
|
2019-11-17 01:10:13 +00:00
|
|
|
None => return,
|
2019-08-24 21:45:03 +00:00
|
|
|
};
|
2019-11-17 01:10:13 +00:00
|
|
|
let args = decl.inputs.iter()
|
|
|
|
.map(|_| "_")
|
2019-11-17 19:27:48 +00:00
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join(", ");
|
2019-11-17 01:10:13 +00:00
|
|
|
format!("{}({})", name, args)
|
|
|
|
}
|
|
|
|
Some(hir::Node::Item(hir::Item {
|
|
|
|
ident,
|
|
|
|
kind: hir::ItemKind::Fn(.., body_id),
|
|
|
|
..
|
|
|
|
})) => {
|
|
|
|
err.span_label(ident.span, "consider calling this function");
|
|
|
|
let body = hir.body(*body_id);
|
|
|
|
let args = body.params.iter()
|
|
|
|
.map(|arg| match &arg.pat.kind {
|
|
|
|
hir::PatKind::Binding(_, _, ident, None)
|
2019-11-17 19:27:48 +00:00
|
|
|
// FIXME: provide a better suggestion when encountering `SelfLower`, it
|
|
|
|
// should suggest a method call.
|
2019-11-17 01:10:13 +00:00
|
|
|
if ident.name != kw::SelfLower => ident.to_string(),
|
|
|
|
_ => "_".to_string(),
|
2019-11-17 19:27:48 +00:00
|
|
|
})
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join(", ");
|
2019-11-17 01:10:13 +00:00
|
|
|
format!("{}({})", ident, args)
|
2019-08-24 21:45:03 +00:00
|
|
|
}
|
2019-11-17 01:10:13 +00:00
|
|
|
_ => return,
|
|
|
|
};
|
|
|
|
if points_at_arg {
|
|
|
|
// When the obligation error has been ensured to have been caused by
|
|
|
|
// an argument, the `obligation.cause.span` points at the expression
|
|
|
|
// of the argument, so we can provide a suggestion. This is signaled
|
|
|
|
// by `points_at_arg`. Otherwise, we give a more general note.
|
|
|
|
err.span_suggestion(
|
|
|
|
obligation.cause.span,
|
|
|
|
&msg,
|
|
|
|
snippet,
|
|
|
|
Applicability::HasPlaceholders,
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
err.help(&format!("{}: `{}`", msg, snippet));
|
2019-08-24 21:45:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-16 01:42:27 +00:00
|
|
|
fn suggest_add_reference_to_arg(
|
|
|
|
&self,
|
|
|
|
obligation: &PredicateObligation<'tcx>,
|
|
|
|
err: &mut DiagnosticBuilder<'tcx>,
|
|
|
|
trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
|
|
|
|
points_at_arg: bool,
|
2019-10-27 20:42:20 +00:00
|
|
|
has_custom_message: bool,
|
2019-10-16 01:42:27 +00:00
|
|
|
) -> bool {
|
|
|
|
if !points_at_arg {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
let span = obligation.cause.span;
|
|
|
|
let param_env = obligation.param_env;
|
|
|
|
let trait_ref = trait_ref.skip_binder();
|
|
|
|
|
|
|
|
if let ObligationCauseCode::ImplDerivedObligation(obligation) = &obligation.cause.code {
|
|
|
|
// Try to apply the original trait binding obligation by borrowing.
|
|
|
|
let self_ty = trait_ref.self_ty();
|
|
|
|
let found = self_ty.to_string();
|
|
|
|
let new_self_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, self_ty);
|
|
|
|
let substs = self.tcx.mk_substs_trait(new_self_ty, &[]);
|
|
|
|
let new_trait_ref = ty::TraitRef::new(obligation.parent_trait_ref.def_id(), substs);
|
|
|
|
let new_obligation = Obligation::new(
|
|
|
|
ObligationCause::dummy(),
|
|
|
|
param_env,
|
|
|
|
new_trait_ref.to_predicate(),
|
|
|
|
);
|
2019-11-06 18:39:57 +00:00
|
|
|
if self.predicate_must_hold_modulo_regions(&new_obligation) {
|
2019-10-16 01:42:27 +00:00
|
|
|
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
|
|
|
|
// We have a very specific type of error, where just borrowing this argument
|
|
|
|
// might solve the problem. In cases like this, the important part is the
|
|
|
|
// original type obligation, not the last one that failed, which is arbitrary.
|
|
|
|
// Because of this, we modify the error to refer to the original obligation and
|
|
|
|
// return early in the caller.
|
2019-10-27 20:42:20 +00:00
|
|
|
let msg = format!(
|
|
|
|
"the trait bound `{}: {}` is not satisfied",
|
|
|
|
found,
|
2019-11-21 18:01:14 +00:00
|
|
|
obligation.parent_trait_ref.skip_binder().print_only_trait_path(),
|
2019-10-27 20:42:20 +00:00
|
|
|
);
|
|
|
|
if has_custom_message {
|
|
|
|
err.note(&msg);
|
|
|
|
} else {
|
|
|
|
err.message = vec![(msg, Style::NoStyle)];
|
|
|
|
}
|
2019-10-16 01:42:27 +00:00
|
|
|
if snippet.starts_with('&') {
|
|
|
|
// This is already a literal borrow and the obligation is failing
|
|
|
|
// somewhere else in the obligation chain. Do not suggest non-sense.
|
|
|
|
return false;
|
|
|
|
}
|
2019-10-16 02:09:15 +00:00
|
|
|
err.span_label(span, &format!(
|
|
|
|
"expected an implementor of trait `{}`",
|
2019-11-21 18:01:14 +00:00
|
|
|
obligation.parent_trait_ref.skip_binder().print_only_trait_path(),
|
2019-10-16 02:09:15 +00:00
|
|
|
));
|
2019-10-16 01:42:27 +00:00
|
|
|
err.span_suggestion(
|
|
|
|
span,
|
|
|
|
"consider borrowing here",
|
|
|
|
format!("&{}", snippet),
|
2019-11-06 18:39:57 +00:00
|
|
|
Applicability::MaybeIncorrect,
|
2019-10-16 01:42:27 +00:00
|
|
|
);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
false
|
|
|
|
}
|
|
|
|
|
2018-03-13 04:06:04 +00:00
|
|
|
/// 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.
|
2019-03-04 21:39:52 +00:00
|
|
|
fn suggest_remove_reference(
|
|
|
|
&self,
|
|
|
|
obligation: &PredicateObligation<'tcx>,
|
|
|
|
err: &mut DiagnosticBuilder<'tcx>,
|
|
|
|
trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
|
|
|
|
) {
|
2018-04-25 02:45:49 +00:00
|
|
|
let trait_ref = trait_ref.skip_binder();
|
2018-02-09 18:04:12 +00:00
|
|
|
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();
|
2019-09-20 22:02:36 +00:00
|
|
|
if let Some('\'') = snippet.chars()
|
|
|
|
.filter(|c| !c.is_whitespace())
|
|
|
|
.skip(refs_number)
|
|
|
|
.next()
|
|
|
|
{ // Do not suggest removal of borrow from type arguments.
|
|
|
|
return;
|
|
|
|
}
|
2018-02-09 18:04:12 +00:00
|
|
|
|
2018-03-11 05:21:38 +00:00
|
|
|
let mut trait_type = trait_ref.self_ty();
|
2018-02-09 18:04:12 +00:00
|
|
|
|
2018-03-13 04:06:04 +00:00
|
|
|
for refs_remaining in 0..refs_number {
|
2019-09-16 18:08:35 +00:00
|
|
|
if let ty::Ref(_, t_type, _) = trait_type.kind {
|
2018-02-09 18:04:12 +00:00
|
|
|
trait_type = t_type;
|
|
|
|
|
2019-11-17 01:10:13 +00:00
|
|
|
let new_obligation = self.mk_obligation_for_def_id(
|
|
|
|
trait_ref.def_id,
|
|
|
|
trait_type,
|
2019-10-04 00:10:37 +00:00
|
|
|
ObligationCause::dummy(),
|
|
|
|
obligation.param_env,
|
|
|
|
);
|
2018-02-09 18:04:12 +00:00
|
|
|
|
2018-04-08 06:56:27 +00:00
|
|
|
if self.predicate_may_hold(&new_obligation) {
|
2018-08-18 10:14:09 +00:00
|
|
|
let sp = self.tcx.sess.source_map()
|
2018-03-17 18:41:46 +00:00
|
|
|
.span_take_while(span, |c| c.is_whitespace() || *c == '&');
|
2018-03-11 05:21:38 +00:00
|
|
|
|
2018-03-17 18:41:46 +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
|
|
|
|
2019-01-25 21:03:27 +00:00
|
|
|
err.span_suggestion_short(
|
2018-08-23 08:14:52 +00:00
|
|
|
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;
|
2018-02-09 18:04:12 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
2018-03-11 05:21:38 +00:00
|
|
|
}
|
2018-02-09 18:04:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-04 00:10:37 +00:00
|
|
|
/// Check if the trait bound is implemented for a different mutability and note it in the
|
|
|
|
/// final error.
|
|
|
|
fn suggest_change_mut(
|
|
|
|
&self,
|
|
|
|
obligation: &PredicateObligation<'tcx>,
|
|
|
|
err: &mut DiagnosticBuilder<'tcx>,
|
|
|
|
trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
|
|
|
|
points_at_arg: bool,
|
|
|
|
) {
|
|
|
|
let span = obligation.cause.span;
|
|
|
|
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
|
|
|
|
let refs_number = snippet.chars()
|
|
|
|
.filter(|c| !c.is_whitespace())
|
|
|
|
.take_while(|c| *c == '&')
|
|
|
|
.count();
|
|
|
|
if let Some('\'') = snippet.chars()
|
|
|
|
.filter(|c| !c.is_whitespace())
|
|
|
|
.skip(refs_number)
|
|
|
|
.next()
|
|
|
|
{ // Do not suggest removal of borrow from type arguments.
|
|
|
|
return;
|
|
|
|
}
|
2019-10-09 18:42:29 +00:00
|
|
|
let trait_ref = self.resolve_vars_if_possible(trait_ref);
|
|
|
|
if trait_ref.has_infer_types() {
|
|
|
|
// Do not ICE while trying to find if a reborrow would succeed on a trait with
|
|
|
|
// unresolved bindings.
|
|
|
|
return;
|
|
|
|
}
|
2019-10-04 00:10:37 +00:00
|
|
|
|
|
|
|
if let ty::Ref(region, t_type, mutability) = trait_ref.skip_binder().self_ty().kind {
|
|
|
|
let trait_type = match mutability {
|
2019-11-09 16:44:11 +00:00
|
|
|
hir::Mutability::Mutable => self.tcx.mk_imm_ref(region, t_type),
|
|
|
|
hir::Mutability::Immutable => self.tcx.mk_mut_ref(region, t_type),
|
2019-10-04 00:10:37 +00:00
|
|
|
};
|
|
|
|
|
2019-11-17 01:10:13 +00:00
|
|
|
let new_obligation = self.mk_obligation_for_def_id(
|
|
|
|
trait_ref.skip_binder().def_id,
|
|
|
|
trait_type,
|
2019-10-04 00:10:37 +00:00
|
|
|
ObligationCause::dummy(),
|
|
|
|
obligation.param_env,
|
|
|
|
);
|
|
|
|
|
2019-10-05 17:41:24 +00:00
|
|
|
if self.evaluate_obligation_no_overflow(
|
|
|
|
&new_obligation,
|
|
|
|
).must_apply_modulo_regions() {
|
2019-10-04 00:10:37 +00:00
|
|
|
let sp = self.tcx.sess.source_map()
|
|
|
|
.span_take_while(span, |c| c.is_whitespace() || *c == '&');
|
|
|
|
if points_at_arg &&
|
2019-11-09 16:44:11 +00:00
|
|
|
mutability == hir::Mutability::Immutable &&
|
2019-10-04 00:10:37 +00:00
|
|
|
refs_number > 0
|
|
|
|
{
|
|
|
|
err.span_suggestion(
|
|
|
|
sp,
|
|
|
|
"consider changing this borrow's mutability",
|
|
|
|
"&mut ".to_string(),
|
|
|
|
Applicability::MachineApplicable,
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
err.note(&format!(
|
2019-10-04 00:39:58 +00:00
|
|
|
"`{}` is implemented for `{:?}`, but not for `{:?}`",
|
2019-11-21 18:01:14 +00:00
|
|
|
trait_ref.print_only_trait_path(),
|
2019-10-04 00:10:37 +00:00
|
|
|
trait_type,
|
2019-10-04 00:39:58 +00:00
|
|
|
trait_ref.skip_binder().self_ty(),
|
2019-10-04 00:10:37 +00:00
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-04 21:39:52 +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();
|
2019-06-24 07:46:38 +00:00
|
|
|
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);
|
2019-03-04 21:39:52 +00:00
|
|
|
if let Some(hir::Node::Item(hir::Item {
|
2019-11-07 11:57:52 +00:00
|
|
|
kind: hir::ItemKind::Fn(sig, _, body_id),
|
2019-03-04 21:39:52 +00:00
|
|
|
..
|
|
|
|
})) = node {
|
|
|
|
let body = hir.body(*body_id);
|
2019-09-26 13:39:48 +00:00
|
|
|
if let hir::ExprKind::Block(blk, _) = &body.value.kind {
|
2019-11-07 11:57:52 +00:00
|
|
|
if sig.decl.output.span().overlaps(span) && blk.expr.is_none() &&
|
2019-03-04 21:39:52 +00:00
|
|
|
"()" == &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");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-12 21:00:15 +00:00
|
|
|
/// 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`.
|
2018-08-30 05:02:42 +00:00
|
|
|
pub fn get_fn_like_arguments(&self, node: Node<'_>) -> (Span, Vec<ArgKind>) {
|
2018-01-25 18:41:01 +00:00
|
|
|
match node {
|
2018-08-25 14:56:16 +00:00
|
|
|
Node::Expr(&hir::Expr {
|
2019-09-26 13:39:48 +00:00
|
|
|
kind: hir::ExprKind::Closure(_, ref _decl, id, span, _),
|
2018-01-25 18:41:01 +00:00
|
|
|
..
|
|
|
|
}) => {
|
2019-08-27 11:24:32 +00:00
|
|
|
(self.tcx.sess.source_map().def_span(span),
|
|
|
|
self.tcx.hir().body(id).params.iter()
|
2018-01-25 18:41:01 +00:00
|
|
|
.map(|arg| {
|
|
|
|
if let hir::Pat {
|
2019-09-26 15:18:31 +00:00
|
|
|
kind: hir::PatKind::Tuple(ref args, _),
|
2018-01-19 09:28:20 +00:00
|
|
|
span,
|
2018-01-25 18:41:01 +00:00
|
|
|
..
|
2019-06-12 08:43:15 +00:00
|
|
|
} = *arg.pat {
|
2018-01-25 18:41:01 +00:00
|
|
|
ArgKind::Tuple(
|
2018-02-12 21:00:15 +00:00
|
|
|
Some(span),
|
2018-01-25 18:41:01 +00:00
|
|
|
args.iter().map(|pat| {
|
2018-08-18 10:14:09 +00:00
|
|
|
let snippet = self.tcx.sess.source_map()
|
2018-01-25 18:41:01 +00:00
|
|
|
.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()
|
2018-01-25 18:41:01 +00:00
|
|
|
.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 {
|
2018-01-25 18:41:01 +00:00
|
|
|
span,
|
2019-11-07 11:57:52 +00:00
|
|
|
kind: hir::ItemKind::Fn(ref sig, ..),
|
2018-01-25 18:41:01 +00:00
|
|
|
..
|
|
|
|
}) |
|
2018-08-25 14:56:16 +00:00
|
|
|
Node::ImplItem(&hir::ImplItem {
|
2018-01-25 18:41:01 +00:00
|
|
|
span,
|
2019-11-07 11:57:52 +00:00
|
|
|
kind: hir::ImplItemKind::Method(ref sig, _),
|
2018-01-25 18:41:01 +00:00
|
|
|
..
|
2018-01-29 07:43:44 +00:00
|
|
|
}) |
|
2018-08-25 14:56:16 +00:00
|
|
|
Node::TraitItem(&hir::TraitItem {
|
2018-01-29 07:43:44 +00:00
|
|
|
span,
|
2019-11-07 11:57:52 +00:00
|
|
|
kind: hir::TraitItemKind::Method(ref sig, _),
|
2018-01-29 07:43:44 +00:00
|
|
|
..
|
2018-01-25 18:41:01 +00:00
|
|
|
}) => {
|
2019-11-07 11:57:52 +00:00
|
|
|
(self.tcx.sess.source_map().def_span(span), sig.decl.inputs.iter()
|
2019-09-26 16:25:31 +00:00
|
|
|
.map(|arg| match arg.clone().kind {
|
2018-07-11 14:41:03 +00:00
|
|
|
hir::TyKind::Tup(ref tys) => ArgKind::Tuple(
|
2018-02-12 21:00:15 +00:00
|
|
|
Some(arg.span),
|
2018-09-12 14:57:19 +00:00
|
|
|
vec![("_".to_owned(), "_".to_owned()); tys.len()]
|
2018-01-25 18:41:01 +00:00
|
|
|
),
|
2018-09-12 14:57:19 +00:00
|
|
|
_ => ArgKind::empty()
|
2018-01-25 18:41:01 +00:00
|
|
|
}).collect::<Vec<ArgKind>>())
|
|
|
|
}
|
2019-03-24 17:21:59 +00:00
|
|
|
Node::Ctor(ref variant_data) => {
|
2019-03-21 22:38:50 +00:00
|
|
|
let span = variant_data.ctor_hir_id()
|
2019-06-14 16:58:55 +00:00
|
|
|
.map(|hir_id| self.tcx.hir().span(hir_id))
|
2019-03-21 22:38:50 +00:00
|
|
|
.unwrap_or(DUMMY_SP);
|
|
|
|
let span = self.tcx.sess.source_map().def_span(span);
|
|
|
|
|
|
|
|
(span, vec![ArgKind::empty(); variant_data.fields().len()])
|
2018-04-26 21:19:21 +00:00
|
|
|
}
|
2018-01-25 18:41:01 +00:00
|
|
|
_ => panic!("non-FnLike node found: {:?}", node),
|
2018-01-19 09:28:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-12 21:00:15 +00:00
|
|
|
/// 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,
|
2018-02-07 07:34:45 +00:00
|
|
|
found_span: Option<Span>,
|
2018-01-19 09:28:20 +00:00
|
|
|
expected_args: Vec<ArgKind>,
|
|
|
|
found_args: Vec<ArgKind>,
|
|
|
|
is_closure: bool,
|
2017-10-07 06:12:56 +00:00
|
|
|
) -> DiagnosticBuilder<'tcx> {
|
2017-10-06 14:57:00 +00:00
|
|
|
let kind = if is_closure { "closure" } else { "function" };
|
|
|
|
|
2018-07-27 14:50:28 +00:00
|
|
|
let args_str = |arguments: &[ArgKind], other: &[ArgKind]| {
|
2018-01-19 09:28:20 +00:00
|
|
|
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 { "" },
|
2019-11-05 20:10:24 +00:00
|
|
|
pluralize!(arg_length))
|
2017-10-13 00:56:50 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-01-19 09:28:20 +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
|
|
|
|
2018-01-19 09:28:20 +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 {}",
|
2017-10-06 14:57:00 +00:00
|
|
|
kind,
|
2017-10-13 00:56:50 +00:00
|
|
|
expected_str,
|
|
|
|
found_str,
|
2017-10-10 02:03:23 +00:00
|
|
|
);
|
2017-10-06 14:57:00 +00:00
|
|
|
|
2018-09-12 14:57:19 +00:00
|
|
|
err.span_label(span, format!("expected {} that takes {}", kind, expected_str));
|
2018-02-07 07:34:45 +00:00
|
|
|
|
|
|
|
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
|
2018-11-17 09:57:17 +00:00
|
|
|
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
|
|
|
|
};
|
|
|
|
|
2018-07-23 14:16:53 +00:00
|
|
|
// 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 `|_, _|`.
|
2018-07-23 14:16:53 +00:00
|
|
|
if found_args.is_empty() && is_closure {
|
2018-10-30 13:37:26 +00:00
|
|
|
let underscores = vec!["_"; expected_args.len()].join(", ");
|
2019-01-25 21:03:27 +00:00
|
|
|
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
|
|
|
),
|
2018-07-23 14:16:53 +00:00
|
|
|
format!("|{}|", underscores),
|
2018-07-23 14:45:37 +00:00
|
|
|
Applicability::MachineApplicable,
|
2018-07-23 14:16:53 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2018-02-07 07:34:45 +00:00
|
|
|
if let &[ArgKind::Tuple(_, ref fields)] = &found_args[..] {
|
|
|
|
if fields.len() == expected_args.len() {
|
|
|
|
let sugg = fields.iter()
|
|
|
|
.map(|(name, _)| name.to_owned())
|
2018-09-12 14:57:19 +00:00
|
|
|
.collect::<Vec<String>>()
|
|
|
|
.join(", ");
|
2019-01-25 21:03:27 +00:00
|
|
|
err.span_suggestion(
|
|
|
|
found_span,
|
|
|
|
"change the closure to take multiple arguments instead of a single tuple",
|
|
|
|
format!("|{}|", sugg),
|
|
|
|
Applicability::MachineApplicable,
|
|
|
|
);
|
2018-02-07 07:34:45 +00:00
|
|
|
}
|
2018-01-19 09:28:20 +00:00
|
|
|
}
|
2018-02-07 07:34:45 +00:00
|
|
|
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 {
|
2018-08-23 08:14:52 +00:00
|
|
|
String::new()
|
2018-02-07 07:34:45 +00:00
|
|
|
},
|
|
|
|
);
|
2019-01-25 21:03:27 +00:00
|
|
|
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,
|
2019-01-25 21:03:27 +00:00
|
|
|
"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,
|
2019-01-25 21:03:27 +00:00
|
|
|
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-02-07 07:34:45 +00:00
|
|
|
}
|
2017-10-07 06:12:56 +00:00
|
|
|
}
|
2017-04-24 00:54:32 +00:00
|
|
|
}
|
2017-10-06 14:57:00 +00:00
|
|
|
|
2017-04-24 00:54:32 +00:00
|
|
|
err
|
|
|
|
}
|
2017-09-23 01:15:30 +00:00
|
|
|
|
2019-06-11 21:11:55 +00:00
|
|
|
fn report_closure_arg_mismatch(
|
|
|
|
&self,
|
|
|
|
span: Span,
|
|
|
|
found_span: Option<Span>,
|
|
|
|
expected_ref: ty::PolyTraitRef<'tcx>,
|
|
|
|
found: ty::PolyTraitRef<'tcx>,
|
|
|
|
) -> DiagnosticBuilder<'tcx> {
|
2019-06-13 22:32:15 +00:00
|
|
|
fn build_fn_sig_string<'tcx>(tcx: TyCtxt<'tcx>, trait_ref: &ty::TraitRef<'tcx>) -> String {
|
2017-09-23 01:15:30 +00:00
|
|
|
let inputs = trait_ref.substs.type_at(1);
|
2019-09-16 18:08:35 +00:00
|
|
|
let sig = if let ty::Tuple(inputs) = inputs.kind {
|
2017-09-23 01:15:30 +00:00
|
|
|
tcx.mk_fn_sig(
|
2019-04-25 23:27:33 +00:00
|
|
|
inputs.iter().map(|k| k.expect_ty()),
|
2019-03-01 04:02:32 +00:00
|
|
|
tcx.mk_ty_infer(ty::TyVar(ty::TyVid { index: 0 })),
|
2017-09-23 01:15:30 +00:00
|
|
|
false,
|
|
|
|
hir::Unsafety::Normal,
|
2018-04-25 16:30:39 +00:00
|
|
|
::rustc_target::spec::abi::Abi::Rust
|
2017-09-23 01:15:30 +00:00
|
|
|
)
|
|
|
|
} else {
|
|
|
|
tcx.mk_fn_sig(
|
|
|
|
::std::iter::once(inputs),
|
2019-03-01 04:02:32 +00:00
|
|
|
tcx.mk_ty_infer(ty::TyVar(ty::TyVid { index: 0 })),
|
2017-09-23 01:15:30 +00:00
|
|
|
false,
|
|
|
|
hir::Unsafety::Normal,
|
2018-04-25 16:30:39 +00:00
|
|
|
::rustc_target::spec::abi::Abi::Rust
|
2017-09-23 01:15:30 +00:00
|
|
|
)
|
|
|
|
};
|
2018-07-27 09:11:18 +00:00
|
|
|
ty::Binder::bind(sig).to_string()
|
2017-09-23 01:15:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
2016-03-16 22:15:31 +00:00
|
|
|
}
|
|
|
|
|
2019-06-13 21:48:52 +00:00
|
|
|
impl<'tcx> TyCtxt<'tcx> {
|
2016-05-11 05:48:12 +00:00
|
|
|
pub fn recursive_type_with_infinite_size_error(self,
|
|
|
|
type_def_id: DefId)
|
|
|
|
-> DiagnosticBuilder<'tcx>
|
|
|
|
{
|
|
|
|
assert!(type_def_id.is_local());
|
2018-12-04 12:45:36 +00:00
|
|
|
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);
|
2016-05-11 05:48:12 +00:00
|
|
|
let mut err = struct_span_err!(self.sess, span, E0072,
|
|
|
|
"recursive type `{}` has infinite size",
|
2018-12-19 10:31:35 +00:00
|
|
|
self.def_path_str(type_def_id));
|
2017-05-04 12:17:23 +00:00
|
|
|
err.span_label(span, "recursive type has infinite size");
|
2016-05-11 05:48:12 +00:00
|
|
|
err.help(&format!("insert indirection (e.g., a `Box`, `Rc`, or `&`) \
|
|
|
|
at some point to make `{}` representable",
|
2018-12-19 10:31:35 +00:00
|
|
|
self.def_path_str(type_def_id)));
|
2016-05-11 05:48:12 +00:00
|
|
|
err
|
|
|
|
}
|
2015-04-14 23:57:29 +00:00
|
|
|
|
2019-03-05 03:24:52 +00:00
|
|
|
pub fn report_object_safety_error(
|
|
|
|
self,
|
|
|
|
span: Span,
|
|
|
|
trait_def_id: DefId,
|
|
|
|
violations: Vec<ObjectSafetyViolation>,
|
2019-01-08 21:14:04 +00:00
|
|
|
) -> DiagnosticBuilder<'tcx> {
|
2018-12-19 10:31:35 +00:00
|
|
|
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);
|
2016-09-01 10:34:56 +00:00
|
|
|
let mut err = struct_span_err!(
|
|
|
|
self.sess, span, E0038,
|
|
|
|
"the trait `{}` cannot be made into an object",
|
|
|
|
trait_str);
|
2017-05-04 12:17:23 +00:00
|
|
|
err.span_label(span, format!("the trait `{}` cannot be made into an object", trait_str));
|
2015-04-14 23:57:29 +00:00
|
|
|
|
2018-10-16 08:44:26 +00:00
|
|
|
let mut reported_violations = FxHashSet::default();
|
2016-05-11 05:48:12 +00:00
|
|
|
for violation in violations {
|
2018-09-12 14:57:19 +00:00
|
|
|
if reported_violations.insert(violation.clone()) {
|
2019-09-03 03:22:22 +00:00
|
|
|
match violation.span() {
|
|
|
|
Some(span) => err.span_label(span, violation.error_msg()),
|
|
|
|
None => err.note(&violation.error_msg()),
|
|
|
|
};
|
2015-08-07 14:28:51 +00:00
|
|
|
}
|
2015-04-14 23:57:29 +00:00
|
|
|
}
|
2019-01-08 21:14:04 +00:00
|
|
|
|
|
|
|
if self.sess.trait_methods_not_found.borrow().contains(&span) {
|
|
|
|
// Avoid emitting error caused by non-existing method (#58734)
|
|
|
|
err.cancel();
|
|
|
|
}
|
|
|
|
|
|
|
|
err
|
2014-12-06 16:39:25 +00:00
|
|
|
}
|
2016-03-16 22:15:31 +00:00
|
|
|
}
|
2014-12-06 16:39:25 +00:00
|
|
|
|
2019-06-13 21:48:52 +00:00
|
|
|
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
2019-09-24 18:05:49 +00:00
|
|
|
fn maybe_report_ambiguity(
|
|
|
|
&self,
|
|
|
|
obligation: &PredicateObligation<'tcx>,
|
|
|
|
body_id: Option<hir::BodyId>,
|
|
|
|
) {
|
2016-05-11 05:48:12 +00:00
|
|
|
// 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.
|
|
|
|
|
2019-05-11 18:08:26 +00:00
|
|
|
let predicate = self.resolve_vars_if_possible(&obligation.predicate);
|
2017-04-11 21:37:40 +00:00
|
|
|
let span = obligation.cause.span;
|
2016-05-11 05:48:12 +00:00
|
|
|
|
2019-09-24 18:05:49 +00:00
|
|
|
debug!(
|
|
|
|
"maybe_report_ambiguity(predicate={:?}, obligation={:?} body_id={:?}, code={:?})",
|
|
|
|
predicate,
|
|
|
|
obligation,
|
|
|
|
body_id,
|
|
|
|
obligation.cause.code,
|
|
|
|
);
|
2016-05-11 05:48:12 +00:00
|
|
|
|
|
|
|
// 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();
|
2019-09-25 14:57:54 +00:00
|
|
|
debug!("self_ty {:?} {:?} trait_ref {:?}", self_ty, self_ty.kind, trait_ref);
|
2019-09-24 18:05:49 +00:00
|
|
|
|
2016-08-18 05:32:50 +00:00
|
|
|
if predicate.references_error() {
|
2017-02-19 18:12:18 +00:00
|
|
|
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
|
2019-09-24 18:05:49 +00:00
|
|
|
// inhabited. We used to check for `self.tcx.sess.has_errors()` to
|
|
|
|
// avoid inundating the user with unnecessary errors, but we now
|
|
|
|
// check upstream for type errors and dont add the obligations to
|
|
|
|
// begin with in those cases.
|
|
|
|
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 needed: cannot resolve `{}`",
|
|
|
|
predicate,
|
|
|
|
);
|
|
|
|
self.note_obligation_cause(&mut err, obligation);
|
|
|
|
err.emit();
|
2014-12-30 22:42:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-11 05:48:12 +00:00
|
|
|
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() {
|
2018-05-13 15:52:50 +00:00
|
|
|
self.need_type_info_err(body_id, span, ty).emit();
|
2016-05-11 05:48:12 +00:00
|
|
|
}
|
2015-08-07 14:28:51 +00:00
|
|
|
}
|
|
|
|
|
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();
|
generalize type variables too
When we are generalizing a super/sub-type, we have to replace type
variables with a fresh variable (and not just region variables). So if
we know that `Box<?T> <: ?U`, for example, we instantiate `?U` with
`Box<?V>` and then relate `Box<?T>` to `Box<?V>` (and hence require that
`?T <: ?V`).
This change has some complex interactions, however:
First, the occurs check must be updated to detect constraints like `?T
<: ?U` and `?U <: Box<?T>`. If we're not careful, we'll create a
never-ending sequence of new variables. To address this, we add a second
unification set into `type_variables` that tracks type variables related
through **either** equality **or** subtyping, and use that during the
occurs-check.
Second, the "fudge regions if ok" code was expecting no new type
variables to be created. It must be updated to create new type variables
outside of the probe. This is relatively straight-forward under the new
scheme, since type variables are now independent from one another, and
any relations are moderated by pending subtype obliations and so forth.
This part would be tricky to backport though.
cc #18653
cc #40951
2017-04-11 21:17:58 +00:00
|
|
|
// both must be type variables, or the other would've been instantiated
|
|
|
|
assert!(a.is_ty_var() && b.is_ty_var());
|
2018-05-13 15:52:50 +00:00
|
|
|
self.need_type_info_err(body_id,
|
|
|
|
obligation.cause.span,
|
|
|
|
a).emit();
|
2017-03-10 02:47:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-11 05:48:12 +00:00
|
|
|
_ => {
|
|
|
|
if !self.tcx.sess.has_errors() {
|
2019-09-24 18:05:49 +00:00
|
|
|
let mut err = struct_span_err!(
|
|
|
|
self.tcx.sess,
|
|
|
|
obligation.cause.span,
|
|
|
|
E0284,
|
|
|
|
"type annotations needed: cannot resolve `{}`",
|
|
|
|
predicate,
|
|
|
|
);
|
2016-05-11 05:48:12 +00:00
|
|
|
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
|
2016-05-11 05:48:12 +00:00
|
|
|
/// to the type parameters.
|
2019-06-11 21:11:55 +00:00
|
|
|
fn predicate_can_apply(
|
|
|
|
&self,
|
|
|
|
param_env: ty::ParamEnv<'tcx>,
|
|
|
|
pred: ty::PolyTraitRef<'tcx>,
|
|
|
|
) -> bool {
|
2019-06-14 16:39:39 +00:00
|
|
|
struct ParamToVarFolder<'a, 'tcx> {
|
2019-06-13 21:48:52 +00:00
|
|
|
infcx: &'a InferCtxt<'a, 'tcx>,
|
2019-06-13 22:32:15 +00:00
|
|
|
var_map: FxHashMap<Ty<'tcx>, Ty<'tcx>>,
|
2016-05-11 05:48:12 +00:00
|
|
|
}
|
2016-03-29 17:12:31 +00:00
|
|
|
|
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 }
|
2016-03-29 17:12:31 +00:00
|
|
|
|
2016-05-11 05:48:12 +00:00
|
|
|
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
2019-09-16 18:08:35 +00:00
|
|
|
if let ty::Param(ty::ParamTy {name, .. }) = ty.kind {
|
2016-05-11 05:48:12 +00:00
|
|
|
let infcx = self.infcx;
|
2018-03-06 16:07:27 +00:00
|
|
|
self.var_map.entry(ty).or_insert_with(||
|
|
|
|
infcx.next_ty_var(
|
2019-03-21 00:00:24 +00:00
|
|
|
TypeVariableOrigin {
|
|
|
|
kind: TypeVariableOriginKind::TypeParameterDefinition(name),
|
|
|
|
span: DUMMY_SP,
|
|
|
|
}
|
|
|
|
)
|
|
|
|
)
|
2016-05-11 05:48:12 +00:00
|
|
|
} else {
|
|
|
|
ty.super_fold_with(self)
|
|
|
|
}
|
2016-03-29 17:12:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-11 05:48:12 +00:00
|
|
|
self.probe(|_| {
|
|
|
|
let mut selcx = SelectionContext::new(self);
|
2016-03-29 17:12:31 +00:00
|
|
|
|
2016-05-11 05:48:12 +00:00
|
|
|
let cleaned_pred = pred.fold_with(&mut ParamToVarFolder {
|
|
|
|
infcx: self,
|
2018-10-16 14:57:53 +00:00
|
|
|
var_map: Default::default()
|
2016-05-11 05:48:12 +00:00
|
|
|
});
|
2016-03-29 17:12:31 +00:00
|
|
|
|
2016-05-11 05:48:12 +00:00
|
|
|
let cleaned_pred = super::project::normalize(
|
|
|
|
&mut selcx,
|
2017-05-23 08:19:47 +00:00
|
|
|
param_env,
|
2016-05-11 05:48:12 +00:00
|
|
|
ObligationCause::dummy(),
|
|
|
|
&cleaned_pred
|
|
|
|
).value;
|
2016-03-29 17:12:31 +00:00
|
|
|
|
2016-05-11 05:48:12 +00:00
|
|
|
let obligation = Obligation::new(
|
|
|
|
ObligationCause::dummy(),
|
2017-05-23 08:19:47 +00:00
|
|
|
param_env,
|
2016-05-11 05:48:12 +00:00
|
|
|
cleaned_pred.to_predicate()
|
|
|
|
);
|
2016-03-29 17:12:31 +00:00
|
|
|
|
2018-04-08 06:56:27 +00:00
|
|
|
self.predicate_may_hold(&obligation)
|
2016-05-11 05:48:12 +00:00
|
|
|
})
|
|
|
|
}
|
2016-03-29 17:12:31 +00:00
|
|
|
|
2019-09-25 12:58:41 +00:00
|
|
|
fn note_obligation_cause(
|
|
|
|
&self,
|
|
|
|
err: &mut DiagnosticBuilder<'_>,
|
|
|
|
obligation: &PredicateObligation<'tcx>,
|
|
|
|
) {
|
|
|
|
// First, attempt to add note to this error with an async-await-specific
|
|
|
|
// message, and fall back to regular note otherwise.
|
|
|
|
if !self.note_obligation_cause_for_async_await(err, obligation) {
|
|
|
|
self.note_obligation_cause_code(err, &obligation.predicate, &obligation.cause.code,
|
|
|
|
&mut vec![]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Adds an async-await specific note to the diagnostic:
|
|
|
|
///
|
|
|
|
/// ```ignore (diagnostic)
|
|
|
|
/// note: future does not implement `std::marker::Send` because this value is used across an
|
|
|
|
/// await
|
|
|
|
/// --> $DIR/issue-64130-non-send-future-diags.rs:15:5
|
|
|
|
/// |
|
|
|
|
/// LL | let g = x.lock().unwrap();
|
|
|
|
/// | - has type `std::sync::MutexGuard<'_, u32>`
|
|
|
|
/// LL | baz().await;
|
|
|
|
/// | ^^^^^^^^^^^ await occurs here, with `g` maybe used later
|
|
|
|
/// LL | }
|
|
|
|
/// | - `g` is later dropped here
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Returns `true` if an async-await specific note was added to the diagnostic.
|
|
|
|
fn note_obligation_cause_for_async_await(
|
|
|
|
&self,
|
|
|
|
err: &mut DiagnosticBuilder<'_>,
|
|
|
|
obligation: &PredicateObligation<'tcx>,
|
|
|
|
) -> bool {
|
|
|
|
debug!("note_obligation_cause_for_async_await: obligation.predicate={:?} \
|
|
|
|
obligation.cause.span={:?}", obligation.predicate, obligation.cause.span);
|
|
|
|
let source_map = self.tcx.sess.source_map();
|
|
|
|
|
|
|
|
// Look into the obligation predicate to determine the type in the generator which meant
|
|
|
|
// that the predicate was not satisifed.
|
|
|
|
let (trait_ref, target_ty) = match obligation.predicate {
|
|
|
|
ty::Predicate::Trait(trait_predicate) =>
|
|
|
|
(trait_predicate.skip_binder().trait_ref, trait_predicate.skip_binder().self_ty()),
|
|
|
|
_ => return false,
|
|
|
|
};
|
|
|
|
debug!("note_obligation_cause_for_async_await: target_ty={:?}", target_ty);
|
|
|
|
|
|
|
|
// Attempt to detect an async-await error by looking at the obligation causes, looking
|
|
|
|
// for only generators, generator witnesses, opaque types or `std::future::GenFuture` to
|
|
|
|
// be present.
|
|
|
|
//
|
|
|
|
// When a future does not implement a trait because of a captured type in one of the
|
|
|
|
// generators somewhere in the call stack, then the result is a chain of obligations.
|
|
|
|
// Given a `async fn` A that calls a `async fn` B which captures a non-send type and that
|
|
|
|
// future is passed as an argument to a function C which requires a `Send` type, then the
|
|
|
|
// chain looks something like this:
|
|
|
|
//
|
|
|
|
// - `BuiltinDerivedObligation` with a generator witness (B)
|
|
|
|
// - `BuiltinDerivedObligation` with a generator (B)
|
|
|
|
// - `BuiltinDerivedObligation` with `std::future::GenFuture` (B)
|
|
|
|
// - `BuiltinDerivedObligation` with `impl std::future::Future` (B)
|
|
|
|
// - `BuiltinDerivedObligation` with `impl std::future::Future` (B)
|
|
|
|
// - `BuiltinDerivedObligation` with a generator witness (A)
|
|
|
|
// - `BuiltinDerivedObligation` with a generator (A)
|
|
|
|
// - `BuiltinDerivedObligation` with `std::future::GenFuture` (A)
|
|
|
|
// - `BuiltinDerivedObligation` with `impl std::future::Future` (A)
|
|
|
|
// - `BuiltinDerivedObligation` with `impl std::future::Future` (A)
|
|
|
|
// - `BindingObligation` with `impl_send (Send requirement)
|
|
|
|
//
|
|
|
|
// The first obligations in the chain can be used to get the details of the type that is
|
|
|
|
// captured but the entire chain must be inspected to detect this case.
|
|
|
|
let mut generator = None;
|
|
|
|
let mut next_code = Some(&obligation.cause.code);
|
|
|
|
while let Some(code) = next_code {
|
|
|
|
debug!("note_obligation_cause_for_async_await: code={:?}", code);
|
|
|
|
match code {
|
|
|
|
ObligationCauseCode::BuiltinDerivedObligation(derived_obligation) |
|
|
|
|
ObligationCauseCode::ImplDerivedObligation(derived_obligation) => {
|
|
|
|
debug!("note_obligation_cause_for_async_await: self_ty.kind={:?}",
|
|
|
|
derived_obligation.parent_trait_ref.self_ty().kind);
|
|
|
|
match derived_obligation.parent_trait_ref.self_ty().kind {
|
|
|
|
ty::Adt(ty::AdtDef { did, .. }, ..) if
|
|
|
|
self.tcx.is_diagnostic_item(sym::gen_future, *did) => {},
|
|
|
|
ty::Generator(did, ..) => generator = generator.or(Some(did)),
|
|
|
|
ty::GeneratorWitness(_) | ty::Opaque(..) => {},
|
|
|
|
_ => return false,
|
|
|
|
}
|
|
|
|
|
|
|
|
next_code = Some(derived_obligation.parent_code.as_ref());
|
|
|
|
},
|
|
|
|
ObligationCauseCode::ItemObligation(_) | ObligationCauseCode::BindingObligation(..)
|
|
|
|
if generator.is_some() => break,
|
|
|
|
_ => return false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let generator_did = generator.expect("can only reach this if there was a generator");
|
|
|
|
|
|
|
|
// Only continue to add a note if the generator is from an `async` function.
|
|
|
|
let parent_node = self.tcx.parent(generator_did)
|
|
|
|
.and_then(|parent_did| self.tcx.hir().get_if_local(parent_did));
|
|
|
|
debug!("note_obligation_cause_for_async_await: parent_node={:?}", parent_node);
|
|
|
|
if let Some(hir::Node::Item(hir::Item {
|
2019-11-07 11:57:52 +00:00
|
|
|
kind: hir::ItemKind::Fn(sig, _, _),
|
2019-09-25 12:58:41 +00:00
|
|
|
..
|
|
|
|
})) = parent_node {
|
2019-11-07 11:57:52 +00:00
|
|
|
debug!("note_obligation_cause_for_async_await: header={:?}", sig.header);
|
|
|
|
if sig.header.asyncness != hir::IsAsync::Async {
|
2019-09-25 12:58:41 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let span = self.tcx.def_span(generator_did);
|
|
|
|
let tables = self.tcx.typeck_tables_of(generator_did);
|
|
|
|
debug!("note_obligation_cause_for_async_await: generator_did={:?} span={:?} ",
|
|
|
|
generator_did, span);
|
|
|
|
|
|
|
|
// Look for a type inside the generator interior that matches the target type to get
|
|
|
|
// a span.
|
|
|
|
let target_span = tables.generator_interior_types.iter()
|
|
|
|
.find(|ty::GeneratorInteriorTypeCause { ty, .. }| ty::TyS::same_type(*ty, target_ty))
|
|
|
|
.map(|ty::GeneratorInteriorTypeCause { span, scope_span, .. }|
|
|
|
|
(span, source_map.span_to_snippet(*span), scope_span));
|
|
|
|
if let Some((target_span, Ok(snippet), scope_span)) = target_span {
|
|
|
|
// Look at the last interior type to get a span for the `.await`.
|
|
|
|
let await_span = tables.generator_interior_types.iter().map(|i| i.span).last().unwrap();
|
|
|
|
let mut span = MultiSpan::from_span(await_span);
|
|
|
|
span.push_span_label(
|
|
|
|
await_span, format!("await occurs here, with `{}` maybe used later", snippet));
|
|
|
|
|
|
|
|
span.push_span_label(*target_span, format!("has type `{}`", target_ty));
|
|
|
|
|
|
|
|
// If available, use the scope span to annotate the drop location.
|
|
|
|
if let Some(scope_span) = scope_span {
|
|
|
|
span.push_span_label(
|
|
|
|
source_map.end_point(*scope_span),
|
|
|
|
format!("`{}` is later dropped here", snippet),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
err.span_note(span, &format!(
|
|
|
|
"future does not implement `{}` as this value is used across an await",
|
2019-11-21 18:01:14 +00:00
|
|
|
trait_ref.print_only_trait_path(),
|
2019-09-25 12:58:41 +00:00
|
|
|
));
|
|
|
|
|
|
|
|
// Add a note for the item obligation that remains - normally a note pointing to the
|
|
|
|
// bound that introduced the obligation (e.g. `T: Send`).
|
|
|
|
debug!("note_obligation_cause_for_async_await: next_code={:?}", next_code);
|
|
|
|
self.note_obligation_cause_code(
|
|
|
|
err,
|
|
|
|
&obligation.predicate,
|
|
|
|
next_code.unwrap(),
|
|
|
|
&mut Vec::new(),
|
|
|
|
);
|
|
|
|
|
|
|
|
true
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
2016-05-11 05:48:12 +00:00
|
|
|
}
|
2014-12-06 16:39:25 +00:00
|
|
|
|
2016-05-11 05:48:12 +00:00
|
|
|
fn note_obligation_cause_code<T>(&self,
|
2018-08-30 05:02:42 +00:00
|
|
|
err: &mut DiagnosticBuilder<'_>,
|
2016-05-11 05:48:12 +00:00
|
|
|
predicate: &T,
|
2018-01-27 11:02:45 +00:00
|
|
|
cause_code: &ObligationCauseCode<'tcx>,
|
|
|
|
obligated_types: &mut Vec<&ty::TyS<'tcx>>)
|
2016-05-11 05:48:12 +00:00
|
|
|
where T: fmt::Display
|
|
|
|
{
|
|
|
|
let tcx = self.tcx;
|
|
|
|
match *cause_code {
|
2016-11-07 18:25:06 +00:00
|
|
|
ObligationCauseCode::ExprAssignable |
|
|
|
|
ObligationCauseCode::MatchExpressionArm { .. } |
|
2019-01-06 01:08:15 +00:00
|
|
|
ObligationCauseCode::MatchExpressionArmPattern { .. } |
|
2019-01-06 21:37:03 +00:00
|
|
|
ObligationCauseCode::IfExpression { .. } |
|
2016-11-07 18:25:06 +00:00
|
|
|
ObligationCauseCode::IfExpressionWithNoElse |
|
|
|
|
ObligationCauseCode::MainFunctionType |
|
|
|
|
ObligationCauseCode::StartFunctionType |
|
|
|
|
ObligationCauseCode::IntrinsicType |
|
|
|
|
ObligationCauseCode::MethodReceiver |
|
2017-03-17 13:37:18 +00:00
|
|
|
ObligationCauseCode::ReturnNoExpression |
|
2019-01-06 01:08:15 +00:00
|
|
|
ObligationCauseCode::MiscObligation => {}
|
2016-05-11 05:48:12 +00:00
|
|
|
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");
|
2016-05-11 05:48:12 +00:00
|
|
|
}
|
|
|
|
ObligationCauseCode::ProjectionWf(data) => {
|
2019-08-24 21:44:43 +00:00
|
|
|
err.note(&format!(
|
|
|
|
"required so that the projection `{}` is well-formed",
|
|
|
|
data,
|
|
|
|
));
|
2016-05-11 05:48:12 +00:00
|
|
|
}
|
|
|
|
ObligationCauseCode::ReferenceOutlivesReferent(ref_ty) => {
|
2019-08-24 21:44:43 +00:00
|
|
|
err.note(&format!(
|
|
|
|
"required so that reference `{}` does not outlive its referent",
|
|
|
|
ref_ty,
|
|
|
|
));
|
2016-05-11 05:48:12 +00:00
|
|
|
}
|
2016-10-14 14:09:59 +00:00
|
|
|
ObligationCauseCode::ObjectTypeBound(object_ty, region) => {
|
2019-08-24 21:44:43 +00:00
|
|
|
err.note(&format!(
|
|
|
|
"required so that the lifetime bound of `{}` for `{}` is satisfied",
|
|
|
|
region,
|
|
|
|
object_ty,
|
|
|
|
));
|
2016-10-14 14:09:59 +00:00
|
|
|
}
|
2016-05-11 05:48:12 +00:00
|
|
|
ObligationCauseCode::ItemObligation(item_def_id) => {
|
2018-12-19 10:31:35 +00:00
|
|
|
let item_name = tcx.def_path_str(item_def_id);
|
2018-01-15 22:26:36 +00:00
|
|
|
let msg = format!("required by `{}`", item_name);
|
2018-09-12 14:57:19 +00:00
|
|
|
|
2018-12-04 12:45:36 +00:00
|
|
|
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);
|
2019-08-24 21:44:43 +00:00
|
|
|
err.span_label(sp, &msg);
|
2018-01-15 22:26:36 +00:00
|
|
|
} else {
|
|
|
|
err.note(&msg);
|
|
|
|
}
|
2016-05-11 05:48:12 +00:00
|
|
|
}
|
2019-09-04 17:17:59 +00:00
|
|
|
ObligationCauseCode::BindingObligation(item_def_id, span) => {
|
|
|
|
let item_name = tcx.def_path_str(item_def_id);
|
|
|
|
let msg = format!("required by this bound in `{}`", item_name);
|
|
|
|
if let Some(ident) = tcx.opt_item_name(item_def_id) {
|
|
|
|
err.span_label(ident.span, "");
|
|
|
|
}
|
|
|
|
if span != DUMMY_SP {
|
|
|
|
err.span_label(span, &msg);
|
|
|
|
} else {
|
|
|
|
err.note(&msg);
|
|
|
|
}
|
|
|
|
}
|
2016-05-11 05:48:12 +00:00
|
|
|
ObligationCauseCode::ObjectCastObligation(object_ty) => {
|
|
|
|
err.note(&format!("required for the cast to the object type `{}`",
|
|
|
|
self.ty_to_string(object_ty)));
|
|
|
|
}
|
2019-01-08 21:14:04 +00:00
|
|
|
ObligationCauseCode::Coercion { source: _, target } => {
|
|
|
|
err.note(&format!("required by cast to type `{}`",
|
|
|
|
self.ty_to_string(target)));
|
|
|
|
}
|
2019-11-15 06:50:52 +00:00
|
|
|
ObligationCauseCode::RepeatVec(suggest_const_in_array_repeat_expressions) => {
|
2016-05-11 05:48:12 +00:00
|
|
|
err.note("the `Copy` trait is required because the \
|
|
|
|
repeated element will be copied");
|
2019-11-15 06:50:52 +00:00
|
|
|
if suggest_const_in_array_repeat_expressions {
|
2019-10-26 22:59:24 +00:00
|
|
|
err.note("this array initializer can be evaluated at compile-time, for more \
|
|
|
|
information, see issue \
|
|
|
|
https://github.com/rust-lang/rust/issues/49147");
|
|
|
|
if tcx.sess.opts.unstable_features.is_nightly_build() {
|
2019-11-15 06:50:52 +00:00
|
|
|
err.help("add `#![feature(const_in_array_repeat_expressions)]` to the \
|
2019-10-26 22:59:24 +00:00
|
|
|
crate attributes to enable");
|
|
|
|
}
|
|
|
|
}
|
2016-05-11 05:48:12 +00:00
|
|
|
}
|
|
|
|
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");
|
|
|
|
}
|
2016-05-11 05:48:12 +00:00
|
|
|
}
|
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");
|
|
|
|
}
|
2016-05-11 05:48:12 +00:00
|
|
|
}
|
2017-06-24 07:57:39 +00:00
|
|
|
ObligationCauseCode::SizedReturnType => {
|
2016-05-11 05:48:12 +00:00
|
|
|
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");
|
|
|
|
}
|
2016-05-11 05:48:12 +00:00
|
|
|
ObligationCauseCode::AssignmentLhsSized => {
|
|
|
|
err.note("the left-hand-side of an assignment must have a statically known size");
|
|
|
|
}
|
2017-06-08 05:46:46 +00:00
|
|
|
ObligationCauseCode::TupleInitializerSized => {
|
|
|
|
err.note("tuples must have a statically known size to be initialized");
|
|
|
|
}
|
2016-05-11 05:48:12 +00:00
|
|
|
ObligationCauseCode::StructInitializerSized => {
|
|
|
|
err.note("structs must have a statically known size to be initialized");
|
|
|
|
}
|
2018-08-14 10:50:01 +00:00
|
|
|
ObligationCauseCode::FieldSized { adt_kind: ref item, last } => {
|
2017-08-16 16:45:54 +00:00
|
|
|
match *item {
|
|
|
|
AdtKind::Struct => {
|
2018-08-14 10:50:01 +00:00
|
|
|
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");
|
|
|
|
}
|
2017-08-16 16:45:54 +00:00
|
|
|
}
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
}
|
2016-05-11 05:48:12 +00:00
|
|
|
}
|
2016-06-24 00:20:37 +00:00
|
|
|
ObligationCauseCode::ConstSized => {
|
|
|
|
err.note("constant expressions must have a statically known size");
|
|
|
|
}
|
2019-10-17 08:54:37 +00:00
|
|
|
ObligationCauseCode::ConstPatternStructural => {
|
|
|
|
err.note("constants used for pattern-matching must derive `PartialEq` and `Eq`");
|
|
|
|
}
|
2016-05-11 05:48:12 +00:00
|
|
|
ObligationCauseCode::SharedStatic => {
|
|
|
|
err.note("shared static variables must have a type that implements `Sync`");
|
|
|
|
}
|
|
|
|
ObligationCauseCode::BuiltinDerivedObligation(ref data) => {
|
2019-05-11 18:08:26 +00:00
|
|
|
let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref);
|
2018-04-25 02:45:49 +00:00
|
|
|
let ty = parent_trait_ref.skip_binder().self_ty();
|
2018-01-27 11:02:45 +00:00
|
|
|
err.note(&format!("required because it appears within the type `{}`", ty));
|
|
|
|
obligated_types.push(ty);
|
|
|
|
|
2016-05-11 05:48:12 +00:00
|
|
|
let parent_predicate = parent_trait_ref.to_predicate();
|
2018-01-27 11:02:45 +00:00
|
|
|
if !self.is_recursive_obligation(obligated_types, &data.parent_code) {
|
|
|
|
self.note_obligation_cause_code(err,
|
|
|
|
&parent_predicate,
|
|
|
|
&data.parent_code,
|
|
|
|
obligated_types);
|
|
|
|
}
|
2016-05-11 05:48:12 +00:00
|
|
|
}
|
|
|
|
ObligationCauseCode::ImplDerivedObligation(ref data) => {
|
2019-05-11 18:08:26 +00:00
|
|
|
let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref);
|
2016-05-11 05:48:12 +00:00
|
|
|
err.note(
|
|
|
|
&format!("required because of the requirements on the impl of `{}` for `{}`",
|
2019-11-21 18:01:14 +00:00
|
|
|
parent_trait_ref.print_only_trait_path(),
|
2018-04-25 02:45:49 +00:00
|
|
|
parent_trait_ref.skip_binder().self_ty()));
|
2016-05-11 05:48:12 +00:00
|
|
|
let parent_predicate = parent_trait_ref.to_predicate();
|
|
|
|
self.note_obligation_cause_code(err,
|
2018-09-12 14:57:19 +00:00
|
|
|
&parent_predicate,
|
|
|
|
&data.parent_code,
|
|
|
|
obligated_types);
|
2016-05-11 05:48:12 +00:00
|
|
|
}
|
2016-10-05 14:17:14 +00:00
|
|
|
ObligationCauseCode::CompareImplMethodObligation { .. } => {
|
2016-05-11 05:48:12 +00:00
|
|
|
err.note(
|
|
|
|
&format!("the requirement `{}` appears on the impl method \
|
|
|
|
but not on the corresponding trait method",
|
|
|
|
predicate));
|
|
|
|
}
|
2019-09-24 18:05:49 +00:00
|
|
|
ObligationCauseCode::ReturnType |
|
|
|
|
ObligationCauseCode::ReturnValue(_) |
|
2017-06-24 07:57:39 +00:00
|
|
|
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() {
|
2019-07-23 19:26:01 +00:00
|
|
|
err.help("add `#![feature(trivial_bounds)]` to the \
|
2018-05-06 21:50:35 +00:00
|
|
|
crate attributes to enable",
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2019-10-31 04:24:08 +00:00
|
|
|
ObligationCauseCode::AssocTypeBound(ref data) => {
|
|
|
|
err.span_label(data.original, "associated type defined here");
|
|
|
|
if let Some(sp) = data.impl_span {
|
2019-10-10 23:20:42 +00:00
|
|
|
err.span_label(sp, "in this `impl` item");
|
|
|
|
}
|
2019-10-31 04:24:08 +00:00
|
|
|
for sp in &data.bounds {
|
|
|
|
err.span_label(*sp, "restricted in this bound");
|
|
|
|
}
|
2019-10-10 23:20:42 +00:00
|
|
|
}
|
2015-01-14 21:43:17 +00:00
|
|
|
}
|
2014-12-06 16:39:25 +00:00
|
|
|
}
|
2014-12-17 19:16:28 +00:00
|
|
|
|
2018-08-30 05:02:42 +00:00
|
|
|
fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>) {
|
2016-05-11 05:48:12 +00:00
|
|
|
let current_limit = self.tcx.sess.recursion_limit.get();
|
|
|
|
let suggested_limit = current_limit * 2;
|
2017-08-16 16:45:54 +00:00
|
|
|
err.help(&format!("consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
|
2016-05-11 05:48:12 +00:00
|
|
|
suggested_limit));
|
|
|
|
}
|
2018-01-27 11:02:45 +00:00
|
|
|
|
|
|
|
fn is_recursive_obligation(&self,
|
2018-09-12 14:57:19 +00:00
|
|
|
obligated_types: &mut Vec<&ty::TyS<'tcx>>,
|
|
|
|
cause_code: &ObligationCauseCode<'tcx>) -> bool {
|
2018-01-27 11:02:45 +00:00
|
|
|
if let ObligationCauseCode::BuiltinDerivedObligation(ref data) = cause_code {
|
2019-05-11 18:08:26 +00:00
|
|
|
let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref);
|
2018-09-12 14:57:19 +00:00
|
|
|
|
|
|
|
if obligated_types.iter().any(|ot| ot == &parent_trait_ref.skip_binder().self_ty()) {
|
|
|
|
return true;
|
2018-01-27 11:02:45 +00:00
|
|
|
}
|
|
|
|
}
|
2018-09-12 14:57:19 +00:00
|
|
|
false
|
2018-01-27 11:02:45 +00:00
|
|
|
}
|
2016-03-16 22:15:31 +00:00
|
|
|
}
|
2018-01-19 09:28:20 +00:00
|
|
|
|
2018-02-12 21:00:15 +00:00
|
|
|
/// Summarizes information
|
2018-09-12 14:57:19 +00:00
|
|
|
#[derive(Clone)]
|
2018-02-12 21:00:15 +00:00
|
|
|
pub enum ArgKind {
|
|
|
|
/// An argument of non-tuple type. Parameters are (name, ty)
|
2018-01-19 09:28:20 +00:00
|
|
|
Arg(String, String),
|
2018-02-12 21:00:15 +00:00
|
|
|
|
|
|
|
/// 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)>),
|
2018-01-19 09:28:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ArgKind {
|
|
|
|
fn empty() -> ArgKind {
|
|
|
|
ArgKind::Arg("_".to_owned(), "_".to_owned())
|
|
|
|
}
|
2018-02-12 21:00:15 +00:00
|
|
|
|
|
|
|
/// Creates an `ArgKind` from the expected type of an
|
2018-09-12 14:57:19 +00:00
|
|
|
/// argument. It has no name (`_`) and an optional source span.
|
|
|
|
pub fn from_expected_ty(t: Ty<'_>, span: Option<Span>) -> ArgKind {
|
2019-09-16 18:08:35 +00:00
|
|
|
match t.kind {
|
2018-08-22 00:35:02 +00:00
|
|
|
ty::Tuple(ref tys) => ArgKind::Tuple(
|
2018-09-12 14:57:19 +00:00
|
|
|
span,
|
2018-02-12 21:00:15 +00:00
|
|
|
tys.iter()
|
2018-12-07 17:14:30 +00:00
|
|
|
.map(|ty| ("_".to_owned(), ty.to_string()))
|
2018-02-12 21:00:15 +00:00
|
|
|
.collect::<Vec<_>>()
|
|
|
|
),
|
2018-12-07 17:14:30 +00:00
|
|
|
_ => ArgKind::Arg("_".to_owned(), t.to_string()),
|
2018-02-12 21:00:15 +00:00
|
|
|
}
|
|
|
|
}
|
2018-01-19 09:28:20 +00:00
|
|
|
}
|
2019-11-24 05:44:28 +00:00
|
|
|
|
|
|
|
/// Suggest restricting a type param with a new bound.
|
|
|
|
pub fn suggest_constraining_type_param(
|
|
|
|
generics: &hir::Generics,
|
|
|
|
err: &mut DiagnosticBuilder<'_>,
|
|
|
|
param_name: &str,
|
|
|
|
constraint: &str,
|
|
|
|
source_map: &SourceMap,
|
|
|
|
span: Span,
|
|
|
|
) -> bool {
|
|
|
|
let restrict_msg = "consider further restricting this bound";
|
|
|
|
if let Some(param) = generics.params.iter().filter(|p| {
|
|
|
|
p.name.ident().as_str() == param_name
|
|
|
|
}).next() {
|
|
|
|
if param_name.starts_with("impl ") {
|
|
|
|
// `impl Trait` in argument:
|
|
|
|
// `fn foo(x: impl Trait) {}` → `fn foo(t: impl Trait + Trait2) {}`
|
|
|
|
err.span_suggestion(
|
|
|
|
param.span,
|
|
|
|
restrict_msg,
|
|
|
|
// `impl CurrentTrait + MissingTrait`
|
|
|
|
format!("{} + {}", param_name, constraint),
|
|
|
|
Applicability::MachineApplicable,
|
|
|
|
);
|
|
|
|
} else if generics.where_clause.predicates.is_empty() &&
|
|
|
|
param.bounds.is_empty()
|
|
|
|
{
|
|
|
|
// If there are no bounds whatsoever, suggest adding a constraint
|
|
|
|
// to the type parameter:
|
|
|
|
// `fn foo<T>(t: T) {}` → `fn foo<T: Trait>(t: T) {}`
|
|
|
|
err.span_suggestion(
|
|
|
|
param.span,
|
|
|
|
"consider restricting this bound",
|
|
|
|
format!("{}: {}", param_name, constraint),
|
|
|
|
Applicability::MachineApplicable,
|
|
|
|
);
|
|
|
|
} else if !generics.where_clause.predicates.is_empty() {
|
|
|
|
// There is a `where` clause, so suggest expanding it:
|
|
|
|
// `fn foo<T>(t: T) where T: Debug {}` →
|
|
|
|
// `fn foo<T>(t: T) where T: Debug, T: Trait {}`
|
|
|
|
err.span_suggestion(
|
|
|
|
generics.where_clause.span().unwrap().shrink_to_hi(),
|
|
|
|
&format!("consider further restricting type parameter `{}`", param_name),
|
|
|
|
format!(", {}: {}", param_name, constraint),
|
|
|
|
Applicability::MachineApplicable,
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
// If there is no `where` clause lean towards constraining to the
|
|
|
|
// type parameter:
|
|
|
|
// `fn foo<X: Bar, T>(t: T, x: X) {}` → `fn foo<T: Trait>(t: T) {}`
|
|
|
|
// `fn foo<T: Bar>(t: T) {}` → `fn foo<T: Bar + Trait>(t: T) {}`
|
|
|
|
let sp = param.span.with_hi(span.hi());
|
|
|
|
let span = source_map.span_through_char(sp, ':');
|
|
|
|
if sp != param.span && sp != span {
|
|
|
|
// Only suggest if we have high certainty that the span
|
|
|
|
// covers the colon in `foo<T: Trait>`.
|
|
|
|
err.span_suggestion(
|
|
|
|
span,
|
|
|
|
restrict_msg,
|
|
|
|
format!("{}: {} + ", param_name, constraint),
|
|
|
|
Applicability::MachineApplicable,
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
err.span_label(
|
|
|
|
param.span,
|
|
|
|
&format!("consider adding a `where {}: {}` bound", param_name, constraint),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
false
|
|
|
|
}
|