Auto merge of #98816 - estebank:implicit-sized, r=oli-obk
Track implicit `Sized` obligations in type params When we evaluate `ty::GenericPredicates` we introduce the implicit `Sized` predicate of type params, but we do so with only the `Predicate` its `Span` as context, we don't have an `Obligation` or `ObligationCauseCode` we could influence. To try and carry this information through, we add a new field to `ty::GenericPredicates` that tracks both which predicates come from a type param and whether that param has any bounds already (to use in suggestions). We also suggest adding a `?Sized` bound if appropriate on E0599. Address part of #98539.
This commit is contained in:
commit
47575bb066
66 changed files with 283 additions and 125 deletions
|
@ -270,7 +270,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn normalize(mut self) -> Vec<traits::PredicateObligation<'tcx>> {
|
||||
let cause = self.cause(traits::MiscObligation);
|
||||
let cause = self.cause(traits::WellFormed(None));
|
||||
let infcx = &mut self.infcx;
|
||||
let param_env = self.param_env;
|
||||
let mut obligations = Vec::with_capacity(self.out.len());
|
||||
|
@ -384,7 +384,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
|||
self.out.extend(obligations);
|
||||
|
||||
let tcx = self.tcx();
|
||||
let cause = self.cause(traits::MiscObligation);
|
||||
let cause = self.cause(traits::WellFormed(None));
|
||||
let param_env = self.param_env;
|
||||
let depth = self.recursion_depth;
|
||||
|
||||
|
@ -444,7 +444,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
|||
let predicate =
|
||||
ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv.shrink()))
|
||||
.to_predicate(self.tcx());
|
||||
let cause = self.cause(traits::MiscObligation);
|
||||
let cause = self.cause(traits::WellFormed(None));
|
||||
self.out.push(traits::Obligation::with_depth(
|
||||
cause,
|
||||
self.recursion_depth,
|
||||
|
@ -456,7 +456,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
|||
let resolved = self.infcx.shallow_resolve(infer);
|
||||
// the `InferConst` changed, meaning that we made progress.
|
||||
if resolved != infer {
|
||||
let cause = self.cause(traits::MiscObligation);
|
||||
let cause = self.cause(traits::WellFormed(None));
|
||||
|
||||
let resolved_constant = self.infcx.tcx.mk_const(ty::ConstS {
|
||||
kind: ty::ConstKind::Infer(resolved),
|
||||
|
@ -647,7 +647,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
|||
let defer_to_coercion = self.tcx().features().object_safe_for_dispatch;
|
||||
|
||||
if !defer_to_coercion {
|
||||
let cause = self.cause(traits::MiscObligation);
|
||||
let cause = self.cause(traits::WellFormed(None));
|
||||
let component_traits = data.auto_traits().chain(data.principal_def_id());
|
||||
let tcx = self.tcx();
|
||||
self.out.extend(component_traits.map(|did| {
|
||||
|
@ -678,7 +678,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
|||
let ty = self.infcx.shallow_resolve(ty);
|
||||
if let ty::Infer(ty::TyVar(_)) = ty.kind() {
|
||||
// Not yet resolved, but we've made progress.
|
||||
let cause = self.cause(traits::MiscObligation);
|
||||
let cause = self.cause(traits::WellFormed(None));
|
||||
self.out.push(traits::Obligation::with_depth(
|
||||
cause,
|
||||
self.recursion_depth,
|
||||
|
|
|
@ -117,7 +117,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
};
|
||||
|
||||
// we must check that return type of called functions is WF:
|
||||
self.register_wf_obligation(output.into(), call_expr.span, traits::MiscObligation);
|
||||
self.register_wf_obligation(output.into(), call_expr.span, traits::WellFormed(None));
|
||||
|
||||
output
|
||||
}
|
||||
|
|
|
@ -496,7 +496,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
pub fn to_ty(&self, ast_t: &hir::Ty<'_>) -> Ty<'tcx> {
|
||||
let t = <dyn AstConv<'_>>::ast_ty_to_ty(self, ast_t);
|
||||
self.register_wf_obligation(t.into(), ast_t.span, traits::MiscObligation);
|
||||
self.register_wf_obligation(t.into(), ast_t.span, traits::WellFormed(None));
|
||||
t
|
||||
}
|
||||
|
||||
|
@ -526,7 +526,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.register_wf_obligation(
|
||||
c.into(),
|
||||
self.tcx.hir().span(ast_c.hir_id),
|
||||
ObligationCauseCode::MiscObligation,
|
||||
ObligationCauseCode::WellFormed(None),
|
||||
);
|
||||
c
|
||||
}
|
||||
|
@ -544,7 +544,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.register_wf_obligation(
|
||||
c.into(),
|
||||
self.tcx.hir().span(ast_c.hir_id),
|
||||
ObligationCauseCode::MiscObligation,
|
||||
ObligationCauseCode::WellFormed(None),
|
||||
);
|
||||
c
|
||||
}
|
||||
|
@ -607,7 +607,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
for arg in substs.iter().filter(|arg| {
|
||||
matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..))
|
||||
}) {
|
||||
self.register_wf_obligation(arg, expr.span, traits::MiscObligation);
|
||||
self.register_wf_obligation(arg, expr.span, traits::WellFormed(None));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -501,7 +501,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
|
|||
// the function type must also be well-formed (this is not
|
||||
// implied by the substs being well-formed because of inherent
|
||||
// impls and late-bound regions - see issue #28609).
|
||||
self.register_wf_obligation(fty.into(), self.span, traits::MiscObligation);
|
||||
self.register_wf_obligation(fty.into(), self.span, traits::WellFormed(None));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -348,9 +348,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let type_param = generics.type_param(param_type, self.tcx);
|
||||
Some(self.tcx.def_span(type_param.def_id))
|
||||
}
|
||||
ty::Adt(def, _) if def.did().is_local() => {
|
||||
tcx.def_ident_span(def.did()).map(|span| span)
|
||||
}
|
||||
ty::Adt(def, _) if def.did().is_local() => Some(tcx.def_span(def.did())),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
|
@ -621,12 +619,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// Find all the requirements that come from a local `impl` block.
|
||||
let mut skip_list: FxHashSet<_> = Default::default();
|
||||
let mut spanned_predicates: FxHashMap<MultiSpan, _> = Default::default();
|
||||
for (data, p, parent_p, impl_def_id, cause_span) in unsatisfied_predicates
|
||||
for (data, p, parent_p, impl_def_id, cause) in unsatisfied_predicates
|
||||
.iter()
|
||||
.filter_map(|(p, parent, c)| c.as_ref().map(|c| (p, parent, c)))
|
||||
.filter_map(|(p, parent, c)| match c.code() {
|
||||
ObligationCauseCode::ImplDerivedObligation(ref data) => {
|
||||
Some((&data.derived, p, parent, data.impl_def_id, data.span))
|
||||
Some((&data.derived, p, parent, data.impl_def_id, data))
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
|
@ -695,9 +693,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let _ = format_pred(*pred);
|
||||
}
|
||||
skip_list.insert(p);
|
||||
let mut spans = if cause_span != *item_span {
|
||||
let mut spans: MultiSpan = cause_span.into();
|
||||
spans.push_span_label(cause_span, unsatisfied_msg);
|
||||
let mut spans = if cause.span != *item_span {
|
||||
let mut spans: MultiSpan = cause.span.into();
|
||||
spans.push_span_label(cause.span, unsatisfied_msg);
|
||||
spans
|
||||
} else {
|
||||
ident.span.into()
|
||||
|
@ -709,7 +707,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
// Unmet obligation coming from an `impl`.
|
||||
Some(Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
|
||||
kind:
|
||||
hir::ItemKind::Impl(hir::Impl {
|
||||
of_trait, self_ty, generics, ..
|
||||
}),
|
||||
span: item_span,
|
||||
..
|
||||
})) if !matches!(
|
||||
|
@ -725,14 +726,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
Some(ExpnKind::Macro(MacroKind::Derive, _))
|
||||
) =>
|
||||
{
|
||||
let sized_pred =
|
||||
unsatisfied_predicates.iter().any(|(pred, _, _)| {
|
||||
match pred.kind().skip_binder() {
|
||||
ty::PredicateKind::Trait(pred) => {
|
||||
Some(pred.def_id())
|
||||
== self.tcx.lang_items().sized_trait()
|
||||
&& pred.polarity == ty::ImplPolarity::Positive
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
});
|
||||
for param in generics.params {
|
||||
if param.span == cause.span && sized_pred {
|
||||
let (sp, sugg) = match param.colon_span {
|
||||
Some(sp) => (sp.shrink_to_hi(), " ?Sized +"),
|
||||
None => (param.span.shrink_to_hi(), ": ?Sized"),
|
||||
};
|
||||
err.span_suggestion_verbose(
|
||||
sp,
|
||||
"consider relaxing the type parameter's implicit \
|
||||
`Sized` bound",
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
if let Some(pred) = parent_p {
|
||||
// Done to add the "doesn't satisfy" `span_label`.
|
||||
let _ = format_pred(*pred);
|
||||
}
|
||||
skip_list.insert(p);
|
||||
let mut spans = if cause_span != *item_span {
|
||||
let mut spans: MultiSpan = cause_span.into();
|
||||
spans.push_span_label(cause_span, unsatisfied_msg);
|
||||
let mut spans = if cause.span != *item_span {
|
||||
let mut spans: MultiSpan = cause.span.into();
|
||||
spans.push_span_label(cause.span, unsatisfied_msg);
|
||||
spans
|
||||
} else {
|
||||
let mut spans = Vec::with_capacity(2);
|
||||
|
|
|
@ -1180,7 +1180,7 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: LocalDefId, ty_span: Span, allow_fo
|
|||
fcx.register_bound(
|
||||
item_ty,
|
||||
tcx.require_lang_item(LangItem::Sized, None),
|
||||
traits::ObligationCause::new(ty_span, fcx.body_id, traits::MiscObligation),
|
||||
traits::ObligationCause::new(ty_span, fcx.body_id, traits::WellFormed(None)),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ fn diagnostic_hir_wf_check<'tcx>(
|
|||
let cause = traits::ObligationCause::new(
|
||||
ty.span,
|
||||
self.hir_id,
|
||||
traits::ObligationCauseCode::MiscObligation,
|
||||
traits::ObligationCauseCode::WellFormed(None),
|
||||
);
|
||||
fulfill.register_predicate_obligation(
|
||||
&infcx,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue