TraitNotObjectSafe,
};
-use crate::infer::error_reporting::TypeAnnotationNeeded as ErrorCode;
+use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use crate::infer::{self, InferCtxt};
use crate::mir::interpret::ErrorHandled;
use crate::ty::TypeckTables;
use crate::ty::{self, AdtKind, DefIdTree, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable};
-use errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, Style};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, Style};
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_hir::Node;
flags.push((sym::from_method, Some(method.to_string())));
}
}
- if let Some(t) = self.get_parent_trait_ref(&obligation.cause.code) {
+ if let Some((t, _)) = self.get_parent_trait_ref(&obligation.cause.code) {
flags.push((sym::parent_trait, Some(t)));
}
}
/// Gets the parent trait chain start
- fn get_parent_trait_ref(&self, code: &ObligationCauseCode<'tcx>) -> Option<String> {
+ fn get_parent_trait_ref(
+ &self,
+ code: &ObligationCauseCode<'tcx>,
+ ) -> Option<(String, Option<Span>)> {
match code {
&ObligationCauseCode::BuiltinDerivedObligation(ref data) => {
let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref);
match self.get_parent_trait_ref(&data.parent_code) {
Some(t) => Some(t),
- None => Some(parent_trait_ref.skip_binder().self_ty().to_string()),
+ None => {
+ let ty = parent_trait_ref.skip_binder().self_ty();
+ let span =
+ TyCategory::from_ty(ty).map(|(_, def_id)| self.tcx.def_span(def_id));
+ Some((ty.to_string(), span))
+ }
}
}
_ => None,
return;
}
let trait_ref = trait_predicate.to_poly_trait_ref();
- let (post_message, pre_message) = self
+ let (post_message, pre_message, type_def) = self
.get_parent_trait_ref(&obligation.cause.code)
- .map(|t| (format!(" in `{}`", t), format!("within `{}`, ", t)))
+ .map(|(t, s)| {
+ (
+ format!(" in `{}`", t),
+ format!("within `{}`, ", t),
+ s.map(|s| (format!("within this `{}`", t), s)),
+ )
+ })
.unwrap_or_default();
let OnUnimplementedNote { message, label, note, enclosing_scope } =
} else {
err.span_label(span, explanation);
}
+ if let Some((msg, span)) = type_def {
+ err.span_label(span, &msg);
+ }
if let Some(ref s) = note {
// If it has a custom `#[rustc_on_unimplemented]` note, let's display it
err.note(s.as_str());
let target_span = tables
.generator_interior_types
.iter()
- .find(|ty::GeneratorInteriorTypeCause { ty, .. }| {
+ .zip(tables.generator_interior_exprs.iter())
+ .find(|(ty::GeneratorInteriorTypeCause { ty, .. }, _)| {
// Careful: the regions for types that appear in the
// generator interior are not generally known, so we
// want to erase them when comparing (and anyway,
);
eq
})
- .map(|ty::GeneratorInteriorTypeCause { span, scope_span, .. }| {
- (span, source_map.span_to_snippet(*span), scope_span)
+ .map(|(ty::GeneratorInteriorTypeCause { span, scope_span, .. }, expr)| {
+ (span, source_map.span_to_snippet(*span), scope_span, expr)
});
+
debug!(
"maybe_note_obligation_cause_for_async_await: target_ty={:?} \
generator_interior_types={:?} target_span={:?}",
target_ty, tables.generator_interior_types, target_span
);
- if let Some((target_span, Ok(snippet), scope_span)) = target_span {
+ if let Some((target_span, Ok(snippet), scope_span, expr)) = target_span {
self.note_obligation_cause_for_async_await(
err,
*target_span,
scope_span,
+ *expr,
snippet,
generator_did,
last_generator,
err: &mut DiagnosticBuilder<'_>,
target_span: Span,
scope_span: &Option<Span>,
+ expr: Option<hir::HirId>,
snippet: String,
first_generator: DefId,
last_generator: Option<DefId>,
// not implemented.
let is_send = self.tcx.is_diagnostic_item(sym::send_trait, trait_ref.def_id);
let is_sync = self.tcx.is_diagnostic_item(sym::sync_trait, trait_ref.def_id);
+ let hir = self.tcx.hir();
let trait_explanation = if is_send || is_sync {
let (trait_name, trait_verb) =
if is_send { ("`Send`", "sent") } else { ("`Sync`", "shared") };
let message = if let Some(name) = last_generator
.and_then(|generator_did| self.tcx.parent(generator_did))
- .and_then(|parent_did| self.tcx.hir().as_local_hir_id(parent_did))
- .and_then(|parent_hir_id| self.tcx.hir().opt_name(parent_hir_id))
+ .and_then(|parent_did| hir.as_local_hir_id(parent_did))
+ .and_then(|parent_hir_id| hir.opt_name(parent_hir_id))
{
format!("future returned by `{}` is not {}", name, trait_name)
} else {
};
span.push_span_label(original_span, message);
- err.set_span(span);
+ err.set_span(span.clone());
format!("is not {}", trait_name)
} else {
format!("{} occurs here, with `{}` maybe used later", await_or_yield, snippet),
);
+ if let Some(expr_id) = expr {
+ let expr = hir.expect_expr(expr_id);
+ let is_ref = tables.expr_adjustments(expr).iter().any(|adj| adj.is_region_borrow());
+ let parent = hir.get_parent_node(expr_id);
+ if let Some(hir::Node::Expr(e)) = hir.find(parent) {
+ let method_span = hir.span(parent);
+ if tables.is_method_call(e) && is_ref {
+ err.span_help(
+ method_span,
+ "consider moving this method call into a `let` \
+ binding to create a shorter lived borrow"
+ );
+ }
+ }
+ }
+
span.push_span_label(target_span, format!("has type `{}`", target_ty));
// If available, use the scope span to annotate the drop location.