Auto merge of #91769 - estebank:type-trait-bound-span-2, r=oli-obk
Tweak assoc type obligation spans * Point at RHS of associated type in obligation span * Point at `impl` assoc type on projection error * Reduce verbosity of recursive obligations * Point at source of binding lifetime obligation * Tweak "required bound" note * Tweak "expected... found opaque (return) type" labels * Point at set type in impl assoc type WF errors r? `@oli-obk` This is a(n uncontroversial) subset of #85799.
This commit is contained in:
commit
229d0a9412
92 changed files with 503 additions and 257 deletions
|
@ -1430,6 +1430,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Extend a type error with extra labels pointing at "non-trivial" types, like closures and
|
||||
/// the return type of `async fn`s.
|
||||
///
|
||||
/// `secondary_span` gives the caller the opportunity to expand `diag` with a `span_label`.
|
||||
///
|
||||
/// `swap_secondary_and_primary` is used to make projection errors in particular nicer by using
|
||||
/// the message in `secondary_span` as the primary label, and apply the message that would
|
||||
/// otherwise be used for the primary label on the `secondary_span` `Span`. This applies on
|
||||
/// E0271, like `src/test/ui/issues/issue-39970.stderr`.
|
||||
pub fn note_type_err(
|
||||
&self,
|
||||
diag: &mut DiagnosticBuilder<'tcx>,
|
||||
|
@ -1437,6 +1446,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
secondary_span: Option<(Span, String)>,
|
||||
mut values: Option<ValuePairs<'tcx>>,
|
||||
terr: &TypeError<'tcx>,
|
||||
swap_secondary_and_primary: bool,
|
||||
) {
|
||||
let span = cause.span(self.tcx);
|
||||
debug!("note_type_err cause={:?} values={:?}, terr={:?}", cause, values, terr);
|
||||
|
@ -1613,9 +1623,32 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
match terr {
|
||||
TypeError::ObjectUnsafeCoercion(_) => {}
|
||||
_ => {
|
||||
diag.span_label(span, terr.to_string());
|
||||
let mut label_or_note = |span: Span, msg: &str| {
|
||||
if &[span] == diag.span.primary_spans() {
|
||||
diag.span_label(span, msg);
|
||||
} else {
|
||||
diag.span_note(span, msg);
|
||||
}
|
||||
};
|
||||
if let Some((sp, msg)) = secondary_span {
|
||||
diag.span_label(sp, msg);
|
||||
if swap_secondary_and_primary {
|
||||
let terr = if let Some(infer::ValuePairs::Types(infer::ExpectedFound {
|
||||
expected,
|
||||
..
|
||||
})) = values
|
||||
{
|
||||
format!("expected this to be `{}`", expected)
|
||||
} else {
|
||||
terr.to_string()
|
||||
};
|
||||
label_or_note(sp, &terr);
|
||||
label_or_note(span, &msg);
|
||||
} else {
|
||||
label_or_note(span, &terr.to_string());
|
||||
label_or_note(sp, &msg);
|
||||
}
|
||||
} else {
|
||||
label_or_note(span, &terr.to_string());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -2049,7 +2082,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
struct_span_err!(self.tcx.sess, span, E0644, "{}", failure_str)
|
||||
}
|
||||
};
|
||||
self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr);
|
||||
self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr, false);
|
||||
diag
|
||||
}
|
||||
|
||||
|
|
|
@ -118,8 +118,7 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
|
|||
ArgumentMutability(_) | Mutability => write!(f, "types differ in mutability"),
|
||||
TupleSize(values) => write!(
|
||||
f,
|
||||
"expected a tuple with {} element{}, \
|
||||
found one with {} element{}",
|
||||
"expected a tuple with {} element{}, found one with {} element{}",
|
||||
values.expected,
|
||||
pluralize!(values.expected),
|
||||
values.found,
|
||||
|
@ -127,8 +126,7 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
|
|||
),
|
||||
FixedArraySize(values) => write!(
|
||||
f,
|
||||
"expected an array with a fixed size of {} element{}, \
|
||||
found one with {} element{}",
|
||||
"expected an array with a fixed size of {} element{}, found one with {} element{}",
|
||||
values.expected,
|
||||
pluralize!(values.expected),
|
||||
values.found,
|
||||
|
|
|
@ -1338,7 +1338,46 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
|
|||
"type mismatch resolving `{}`",
|
||||
predicate
|
||||
);
|
||||
self.note_type_err(&mut diag, &obligation.cause, None, values, err);
|
||||
let secondary_span = match predicate.kind().skip_binder() {
|
||||
ty::PredicateKind::Projection(proj) => self
|
||||
.tcx
|
||||
.opt_associated_item(proj.projection_ty.item_def_id)
|
||||
.and_then(|trait_assoc_item| {
|
||||
self.tcx
|
||||
.trait_of_item(proj.projection_ty.item_def_id)
|
||||
.map(|id| (trait_assoc_item, id))
|
||||
})
|
||||
.and_then(|(trait_assoc_item, id)| {
|
||||
self.tcx.find_map_relevant_impl(
|
||||
id,
|
||||
proj.projection_ty.self_ty(),
|
||||
|did| {
|
||||
self.tcx
|
||||
.associated_items(did)
|
||||
.in_definition_order()
|
||||
.filter(|assoc| assoc.ident == trait_assoc_item.ident)
|
||||
.next()
|
||||
},
|
||||
)
|
||||
})
|
||||
.and_then(|item| match self.tcx.hir().get_if_local(item.def_id) {
|
||||
Some(
|
||||
hir::Node::TraitItem(hir::TraitItem {
|
||||
kind: hir::TraitItemKind::Type(_, Some(ty)),
|
||||
..
|
||||
})
|
||||
| hir::Node::ImplItem(hir::ImplItem {
|
||||
kind: hir::ImplItemKind::TyAlias(ty),
|
||||
..
|
||||
}),
|
||||
) => {
|
||||
Some((ty.span, format!("type mismatch resolving `{}`", predicate)))
|
||||
}
|
||||
_ => None,
|
||||
}),
|
||||
_ => None,
|
||||
};
|
||||
self.note_type_err(&mut diag, &obligation.cause, secondary_span, values, err, true);
|
||||
self.note_obligation_cause(&mut diag, obligation);
|
||||
diag.emit();
|
||||
}
|
||||
|
@ -2095,10 +2134,21 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
|
|||
) -> bool {
|
||||
if let ObligationCauseCode::BuiltinDerivedObligation(ref data) = cause_code {
|
||||
let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref);
|
||||
|
||||
if obligated_types.iter().any(|ot| ot == &parent_trait_ref.skip_binder().self_ty()) {
|
||||
let self_ty = parent_trait_ref.skip_binder().self_ty();
|
||||
if obligated_types.iter().any(|ot| ot == &self_ty) {
|
||||
return true;
|
||||
}
|
||||
if let ty::Adt(def, substs) = self_ty.kind() {
|
||||
if let [arg] = &substs[..] {
|
||||
if let ty::subst::GenericArgKind::Type(ty) = arg.unpack() {
|
||||
if let ty::Adt(inner_def, _) = ty.kind() {
|
||||
if inner_def == def {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
|
|
@ -2186,6 +2186,16 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
|||
seen_requirements,
|
||||
)
|
||||
});
|
||||
} else {
|
||||
ensure_sufficient_stack(|| {
|
||||
self.note_obligation_cause_code(
|
||||
err,
|
||||
&parent_predicate,
|
||||
&cause_code.peel_derives(),
|
||||
obligated_types,
|
||||
seen_requirements,
|
||||
)
|
||||
});
|
||||
}
|
||||
}
|
||||
ObligationCauseCode::ImplDerivedObligation(ref data) => {
|
||||
|
|
|
@ -638,7 +638,11 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
|||
self.expr_ty = fcx.structurally_resolved_type(self.expr.span, self.expr_ty);
|
||||
self.cast_ty = fcx.structurally_resolved_type(self.cast_span, self.cast_ty);
|
||||
|
||||
if !fcx.type_is_known_to_be_sized_modulo_regions(self.cast_ty, self.span) {
|
||||
debug!("check_cast({}, {:?} as {:?})", self.expr.hir_id, self.expr_ty, self.cast_ty);
|
||||
|
||||
if !fcx.type_is_known_to_be_sized_modulo_regions(self.cast_ty, self.span)
|
||||
&& !self.cast_ty.has_infer_types()
|
||||
{
|
||||
self.report_cast_to_unsized_type(fcx);
|
||||
} else if self.expr_ty.references_error() || self.cast_ty.references_error() {
|
||||
// No sense in giving duplicate error messages
|
||||
|
|
|
@ -730,7 +730,7 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) {
|
|||
let abi = sig.header.abi;
|
||||
fn_maybe_err(tcx, item.ident.span, abi);
|
||||
}
|
||||
hir::TraitItemKind::Type(.., Some(_default)) => {
|
||||
hir::TraitItemKind::Type(.., Some(default)) => {
|
||||
let assoc_item = tcx.associated_item(item.def_id);
|
||||
let trait_substs =
|
||||
InternalSubsts::identity_for_item(tcx, it.def_id.to_def_id());
|
||||
|
@ -738,7 +738,7 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) {
|
|||
tcx,
|
||||
assoc_item,
|
||||
assoc_item,
|
||||
item.span,
|
||||
default.span,
|
||||
ty::TraitRef { def_id: it.def_id.to_def_id(), substs: trait_substs },
|
||||
);
|
||||
}
|
||||
|
@ -987,12 +987,12 @@ pub(super) fn check_impl_items_against_trait<'tcx>(
|
|||
opt_trait_span,
|
||||
);
|
||||
}
|
||||
hir::ImplItemKind::TyAlias(_) => {
|
||||
hir::ImplItemKind::TyAlias(impl_ty) => {
|
||||
let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
|
||||
compare_ty_impl(
|
||||
tcx,
|
||||
&ty_impl_item,
|
||||
impl_item.span,
|
||||
impl_ty.span,
|
||||
&ty_trait_item,
|
||||
impl_trait_ref,
|
||||
opt_trait_span,
|
||||
|
|
|
@ -379,6 +379,7 @@ fn compare_predicate_entailment<'tcx>(
|
|||
found: impl_fty,
|
||||
})),
|
||||
&terr,
|
||||
false,
|
||||
);
|
||||
diag.emit();
|
||||
return Err(ErrorReported);
|
||||
|
@ -734,8 +735,7 @@ fn compare_number_of_method_arguments<'tcx>(
|
|||
tcx.sess,
|
||||
impl_span,
|
||||
E0050,
|
||||
"method `{}` has {} but the declaration in \
|
||||
trait `{}` has {}",
|
||||
"method `{}` has {} but the declaration in trait `{}` has {}",
|
||||
trait_m.ident,
|
||||
potentially_plural_count(impl_number_args, "parameter"),
|
||||
tcx.def_path_str(trait_m.def_id),
|
||||
|
@ -1069,6 +1069,7 @@ crate fn compare_const_impl<'tcx>(
|
|||
found: impl_ty,
|
||||
})),
|
||||
&terr,
|
||||
false,
|
||||
);
|
||||
diag.emit();
|
||||
}
|
||||
|
@ -1099,7 +1100,8 @@ crate fn compare_ty_impl<'tcx>(
|
|||
let _: Result<(), ErrorReported> = (|| {
|
||||
compare_number_of_generics(tcx, impl_ty, impl_ty_span, trait_ty, trait_item_span)?;
|
||||
|
||||
compare_type_predicate_entailment(tcx, impl_ty, impl_ty_span, trait_ty, impl_trait_ref)?;
|
||||
let sp = tcx.def_span(impl_ty.def_id);
|
||||
compare_type_predicate_entailment(tcx, impl_ty, sp, trait_ty, impl_trait_ref)?;
|
||||
|
||||
check_type_bounds(tcx, trait_ty, impl_ty, impl_ty_span, impl_trait_ref)
|
||||
})();
|
||||
|
|
|
@ -683,7 +683,8 @@ pub fn check_impl_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
|||
|
||||
let (method_sig, span) = match impl_item.kind {
|
||||
hir::ImplItemKind::Fn(ref sig, _) => (Some(sig), impl_item.span),
|
||||
hir::ImplItemKind::TyAlias(ty) => (None, ty.span),
|
||||
// Constrain binding and overflow error spans to `<Ty>` in `type foo = <Ty>`.
|
||||
hir::ImplItemKind::TyAlias(ty) if ty.span != DUMMY_SP => (None, ty.span),
|
||||
_ => (None, impl_item.span),
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue