Rollup merge of #97123 - ricked-twice:issue-96223-clean-fix, r=jackh726
Clean fix for #96223 Okay, so here we are (hopefully) 👍 Closes #96223 Thanks a lot to `@jackh726` for your help and explanation 🙏 - Modified `InferCtxt::mk_trait_obligation_with_new_self_ty` to take as argument a `Binder<(TraitPredicate, Ty)>` instead of a `Binder<TraitPredicate>` and a separate `Ty` with no bound vars. - Modified all call places to avoid calling `Binder::no_bounds_var` or `Binder::skip_binder` when it is not safe. r? `@jackh726`
This commit is contained in:
commit
a2c2720e09
4 changed files with 139 additions and 142 deletions
|
@ -1384,8 +1384,7 @@ trait InferCtxtPrivExt<'hir, 'tcx> {
|
||||||
fn mk_trait_obligation_with_new_self_ty(
|
fn mk_trait_obligation_with_new_self_ty(
|
||||||
&self,
|
&self,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
trait_ref: ty::PolyTraitPredicate<'tcx>,
|
trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>,
|
||||||
new_self_ty: Ty<'tcx>,
|
|
||||||
) -> PredicateObligation<'tcx>;
|
) -> PredicateObligation<'tcx>;
|
||||||
|
|
||||||
fn maybe_report_ambiguity(
|
fn maybe_report_ambiguity(
|
||||||
|
@ -1923,14 +1922,11 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
fn mk_trait_obligation_with_new_self_ty(
|
fn mk_trait_obligation_with_new_self_ty(
|
||||||
&self,
|
&self,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
trait_ref: ty::PolyTraitPredicate<'tcx>,
|
trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>,
|
||||||
new_self_ty: Ty<'tcx>,
|
|
||||||
) -> PredicateObligation<'tcx> {
|
) -> PredicateObligation<'tcx> {
|
||||||
assert!(!new_self_ty.has_escaping_bound_vars());
|
let trait_pred = trait_ref_and_ty.map_bound_ref(|(tr, new_self_ty)| ty::TraitPredicate {
|
||||||
|
|
||||||
let trait_pred = trait_ref.map_bound_ref(|tr| ty::TraitPredicate {
|
|
||||||
trait_ref: ty::TraitRef {
|
trait_ref: ty::TraitRef {
|
||||||
substs: self.tcx.mk_substs_trait(new_self_ty, &tr.trait_ref.substs[1..]),
|
substs: self.tcx.mk_substs_trait(*new_self_ty, &tr.trait_ref.substs[1..]),
|
||||||
..tr.trait_ref
|
..tr.trait_ref
|
||||||
},
|
},
|
||||||
..*tr
|
..*tr
|
||||||
|
|
|
@ -628,17 +628,21 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
if let Some(parent_trait_pred) = parent_trait_pred {
|
if let Some(parent_trait_pred) = parent_trait_pred {
|
||||||
real_trait_pred = parent_trait_pred;
|
real_trait_pred = parent_trait_pred;
|
||||||
}
|
}
|
||||||
let Some(real_ty) = real_trait_pred.self_ty().no_bound_vars() else {
|
|
||||||
continue;
|
// Skipping binder here, remapping below
|
||||||
};
|
let real_ty = real_trait_pred.self_ty().skip_binder();
|
||||||
|
|
||||||
if let ty::Ref(region, base_ty, mutbl) = *real_ty.kind() {
|
if let ty::Ref(region, base_ty, mutbl) = *real_ty.kind() {
|
||||||
let mut autoderef = Autoderef::new(self, param_env, body_id, span, base_ty, span);
|
let mut autoderef = Autoderef::new(self, param_env, body_id, span, base_ty, span);
|
||||||
if let Some(steps) = autoderef.find_map(|(ty, steps)| {
|
if let Some(steps) = autoderef.find_map(|(ty, steps)| {
|
||||||
// Re-add the `&`
|
// Re-add the `&`
|
||||||
let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl });
|
let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl });
|
||||||
let obligation =
|
|
||||||
self.mk_trait_obligation_with_new_self_ty(param_env, real_trait_pred, ty);
|
// Remapping bound vars here
|
||||||
|
let real_trait_pred_and_ty =
|
||||||
|
real_trait_pred.map_bound(|inner_trait_pred| (inner_trait_pred, ty));
|
||||||
|
let obligation = self
|
||||||
|
.mk_trait_obligation_with_new_self_ty(param_env, real_trait_pred_and_ty);
|
||||||
Some(steps).filter(|_| self.predicate_may_hold(&obligation))
|
Some(steps).filter(|_| self.predicate_may_hold(&obligation))
|
||||||
}) {
|
}) {
|
||||||
if steps > 0 {
|
if steps > 0 {
|
||||||
|
@ -659,10 +663,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
} else if real_trait_pred != trait_pred {
|
} else if real_trait_pred != trait_pred {
|
||||||
// This branch addresses #87437.
|
// This branch addresses #87437.
|
||||||
|
|
||||||
|
// Remapping bound vars here
|
||||||
|
let real_trait_pred_and_base_ty =
|
||||||
|
real_trait_pred.map_bound(|inner_trait_pred| (inner_trait_pred, base_ty));
|
||||||
let obligation = self.mk_trait_obligation_with_new_self_ty(
|
let obligation = self.mk_trait_obligation_with_new_self_ty(
|
||||||
param_env,
|
param_env,
|
||||||
real_trait_pred,
|
real_trait_pred_and_base_ty,
|
||||||
base_ty,
|
|
||||||
);
|
);
|
||||||
if self.predicate_may_hold(&obligation) {
|
if self.predicate_may_hold(&obligation) {
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
|
@ -720,9 +727,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
err: &mut Diagnostic,
|
err: &mut Diagnostic,
|
||||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let Some(self_ty) = trait_pred.self_ty().no_bound_vars() else {
|
// Skipping binder here, remapping below
|
||||||
return false;
|
let self_ty = trait_pred.self_ty().skip_binder();
|
||||||
};
|
|
||||||
|
|
||||||
let (def_id, output_ty, callable) = match *self_ty.kind() {
|
let (def_id, output_ty, callable) = match *self_ty.kind() {
|
||||||
ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig().output(), "closure"),
|
ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig().output(), "closure"),
|
||||||
|
@ -731,14 +737,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
};
|
};
|
||||||
let msg = format!("use parentheses to call the {}", callable);
|
let msg = format!("use parentheses to call the {}", callable);
|
||||||
|
|
||||||
// `mk_trait_obligation_with_new_self_ty` only works for types with no escaping bound
|
// "We should really create a single list of bound vars from the combined vars
|
||||||
// variables, so bail out if we have any.
|
// from the predicate and function, but instead we just liberate the function bound vars"
|
||||||
let Some(output_ty) = output_ty.no_bound_vars() else {
|
let output_ty = self.tcx.liberate_late_bound_regions(def_id, output_ty);
|
||||||
return false;
|
|
||||||
};
|
// Remapping bound vars here
|
||||||
|
let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, output_ty));
|
||||||
|
|
||||||
let new_obligation =
|
let new_obligation =
|
||||||
self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred, output_ty);
|
self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred_and_self);
|
||||||
|
|
||||||
match self.evaluate_obligation(&new_obligation) {
|
match self.evaluate_obligation(&new_obligation) {
|
||||||
Ok(
|
Ok(
|
||||||
|
@ -842,96 +849,97 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
let param_env = obligation.param_env;
|
let param_env = obligation.param_env;
|
||||||
|
|
||||||
// Try to apply the original trait binding obligation by borrowing.
|
// Try to apply the original trait binding obligation by borrowing.
|
||||||
let mut try_borrowing = |old_pred: ty::PolyTraitPredicate<'tcx>,
|
let mut try_borrowing =
|
||||||
blacklist: &[DefId]|
|
|old_pred: ty::PolyTraitPredicate<'tcx>, blacklist: &[DefId]| -> bool {
|
||||||
-> bool {
|
if blacklist.contains(&old_pred.def_id()) {
|
||||||
if blacklist.contains(&old_pred.def_id()) {
|
return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is a quick fix to resolve an ICE (#96223).
|
|
||||||
// This change should probably be deeper.
|
|
||||||
// As suggested by @jackh726, `mk_trait_obligation_with_new_self_ty` could take a `Binder<(TraitRef, Ty)>
|
|
||||||
// instead of `Binder<Ty>` leading to some changes to its call places.
|
|
||||||
let Some(orig_ty) = old_pred.self_ty().no_bound_vars() else {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
let mk_result = |new_ty| {
|
|
||||||
let obligation =
|
|
||||||
self.mk_trait_obligation_with_new_self_ty(param_env, old_pred, new_ty);
|
|
||||||
self.predicate_must_hold_modulo_regions(&obligation)
|
|
||||||
};
|
|
||||||
let imm_result = mk_result(self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, orig_ty));
|
|
||||||
let mut_result = mk_result(self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, orig_ty));
|
|
||||||
|
|
||||||
if imm_result || mut_result {
|
|
||||||
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.
|
|
||||||
|
|
||||||
let msg = format!(
|
|
||||||
"the trait bound `{}: {}` is not satisfied",
|
|
||||||
orig_ty,
|
|
||||||
old_pred.print_modifiers_and_trait_path(),
|
|
||||||
);
|
|
||||||
if has_custom_message {
|
|
||||||
err.note(&msg);
|
|
||||||
} else {
|
|
||||||
err.message =
|
|
||||||
vec![(rustc_errors::DiagnosticMessage::Str(msg), Style::NoStyle)];
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
err.span_label(
|
|
||||||
span,
|
|
||||||
&format!(
|
|
||||||
"expected an implementor of trait `{}`",
|
|
||||||
old_pred.print_modifiers_and_trait_path(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
// This if is to prevent a special edge-case
|
|
||||||
if matches!(
|
|
||||||
span.ctxt().outer_expn_data().kind,
|
|
||||||
ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop)
|
|
||||||
) {
|
|
||||||
// We don't want a borrowing suggestion on the fields in structs,
|
|
||||||
// ```
|
|
||||||
// struct Foo {
|
|
||||||
// the_foos: Vec<Foo>
|
|
||||||
// }
|
|
||||||
// ```
|
|
||||||
|
|
||||||
if imm_result && mut_result {
|
|
||||||
err.span_suggestions(
|
|
||||||
span.shrink_to_lo(),
|
|
||||||
"consider borrowing here",
|
|
||||||
["&".to_string(), "&mut ".to_string()].into_iter(),
|
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
err.span_suggestion_verbose(
|
|
||||||
span.shrink_to_lo(),
|
|
||||||
&format!(
|
|
||||||
"consider{} borrowing here",
|
|
||||||
if mut_result { " mutably" } else { "" }
|
|
||||||
),
|
|
||||||
format!("&{}", if mut_result { "mut " } else { "" }),
|
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
// We map bounds to `&T` and `&mut T`
|
||||||
return false;
|
let trait_pred_and_imm_ref = old_pred.map_bound(|trait_pred| {
|
||||||
};
|
(
|
||||||
|
trait_pred,
|
||||||
|
self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
let trait_pred_and_mut_ref = old_pred.map_bound(|trait_pred| {
|
||||||
|
(
|
||||||
|
trait_pred,
|
||||||
|
self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let mk_result = |trait_pred_and_new_ty| {
|
||||||
|
let obligation =
|
||||||
|
self.mk_trait_obligation_with_new_self_ty(param_env, trait_pred_and_new_ty);
|
||||||
|
self.predicate_must_hold_modulo_regions(&obligation)
|
||||||
|
};
|
||||||
|
let imm_result = mk_result(trait_pred_and_imm_ref);
|
||||||
|
let mut_result = mk_result(trait_pred_and_mut_ref);
|
||||||
|
|
||||||
|
if imm_result || mut_result {
|
||||||
|
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.
|
||||||
|
|
||||||
|
let msg = format!("the trait bound `{}` is not satisfied", old_pred);
|
||||||
|
if has_custom_message {
|
||||||
|
err.note(&msg);
|
||||||
|
} else {
|
||||||
|
err.message =
|
||||||
|
vec![(rustc_errors::DiagnosticMessage::Str(msg), Style::NoStyle)];
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
err.span_label(
|
||||||
|
span,
|
||||||
|
&format!(
|
||||||
|
"expected an implementor of trait `{}`",
|
||||||
|
old_pred.print_modifiers_and_trait_path(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// This if is to prevent a special edge-case
|
||||||
|
if matches!(
|
||||||
|
span.ctxt().outer_expn_data().kind,
|
||||||
|
ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop)
|
||||||
|
) {
|
||||||
|
// We don't want a borrowing suggestion on the fields in structs,
|
||||||
|
// ```
|
||||||
|
// struct Foo {
|
||||||
|
// the_foos: Vec<Foo>
|
||||||
|
// }
|
||||||
|
// ```
|
||||||
|
|
||||||
|
if imm_result && mut_result {
|
||||||
|
err.span_suggestions(
|
||||||
|
span.shrink_to_lo(),
|
||||||
|
"consider borrowing here",
|
||||||
|
["&".to_string(), "&mut ".to_string()].into_iter(),
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
err.span_suggestion_verbose(
|
||||||
|
span.shrink_to_lo(),
|
||||||
|
&format!(
|
||||||
|
"consider{} borrowing here",
|
||||||
|
if mut_result { " mutably" } else { "" }
|
||||||
|
),
|
||||||
|
format!("&{}", if mut_result { "mut " } else { "" }),
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
if let ObligationCauseCode::ImplDerivedObligation(cause) = &*code {
|
if let ObligationCauseCode::ImplDerivedObligation(cause) = &*code {
|
||||||
try_borrowing(cause.derived.parent_trait_pred, &[])
|
try_borrowing(cause.derived.parent_trait_pred, &[])
|
||||||
|
@ -992,9 +1000,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some(mut suggested_ty) = trait_pred.self_ty().no_bound_vars() else {
|
// Skipping binder here, remapping below
|
||||||
return false;
|
let mut suggested_ty = trait_pred.self_ty().skip_binder();
|
||||||
};
|
|
||||||
|
|
||||||
for refs_remaining in 0..refs_number {
|
for refs_remaining in 0..refs_number {
|
||||||
let ty::Ref(_, inner_ty, _) = suggested_ty.kind() else {
|
let ty::Ref(_, inner_ty, _) = suggested_ty.kind() else {
|
||||||
|
@ -1002,10 +1009,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
};
|
};
|
||||||
suggested_ty = *inner_ty;
|
suggested_ty = *inner_ty;
|
||||||
|
|
||||||
|
// Remapping bound vars here
|
||||||
|
let trait_pred_and_suggested_ty =
|
||||||
|
trait_pred.map_bound(|trait_pred| (trait_pred, suggested_ty));
|
||||||
|
|
||||||
let new_obligation = self.mk_trait_obligation_with_new_self_ty(
|
let new_obligation = self.mk_trait_obligation_with_new_self_ty(
|
||||||
obligation.param_env,
|
obligation.param_env,
|
||||||
trait_pred,
|
trait_pred_and_suggested_ty,
|
||||||
suggested_ty,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if self.predicate_may_hold(&new_obligation) {
|
if self.predicate_may_hold(&new_obligation) {
|
||||||
|
@ -1125,26 +1135,21 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Skipping binder here, remapping below
|
||||||
if let ty::Ref(region, t_type, mutability) = *trait_pred.skip_binder().self_ty().kind()
|
if let ty::Ref(region, t_type, mutability) = *trait_pred.skip_binder().self_ty().kind()
|
||||||
{
|
{
|
||||||
if region.is_late_bound() || t_type.has_escaping_bound_vars() {
|
|
||||||
// Avoid debug assertion in `mk_obligation_for_def_id`.
|
|
||||||
//
|
|
||||||
// If the self type has escaping bound vars then it's not
|
|
||||||
// going to be the type of an expression, so the suggestion
|
|
||||||
// probably won't apply anyway.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let suggested_ty = match mutability {
|
let suggested_ty = match mutability {
|
||||||
hir::Mutability::Mut => self.tcx.mk_imm_ref(region, t_type),
|
hir::Mutability::Mut => self.tcx.mk_imm_ref(region, t_type),
|
||||||
hir::Mutability::Not => self.tcx.mk_mut_ref(region, t_type),
|
hir::Mutability::Not => self.tcx.mk_mut_ref(region, t_type),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Remapping bound vars here
|
||||||
|
let trait_pred_and_suggested_ty =
|
||||||
|
trait_pred.map_bound(|trait_pred| (trait_pred, suggested_ty));
|
||||||
|
|
||||||
let new_obligation = self.mk_trait_obligation_with_new_self_ty(
|
let new_obligation = self.mk_trait_obligation_with_new_self_ty(
|
||||||
obligation.param_env,
|
obligation.param_env,
|
||||||
trait_pred,
|
trait_pred_and_suggested_ty,
|
||||||
suggested_ty,
|
|
||||||
);
|
);
|
||||||
let suggested_ty_would_satisfy_obligation = self
|
let suggested_ty_would_satisfy_obligation = self
|
||||||
.evaluate_obligation_no_overflow(&new_obligation)
|
.evaluate_obligation_no_overflow(&new_obligation)
|
||||||
|
@ -1195,7 +1200,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
// Only suggest this if the expression behind the semicolon implements the predicate
|
// Only suggest this if the expression behind the semicolon implements the predicate
|
||||||
&& let Some(typeck_results) = self.in_progress_typeck_results
|
&& let Some(typeck_results) = self.in_progress_typeck_results
|
||||||
&& let Some(ty) = typeck_results.borrow().expr_ty_opt(expr)
|
&& let Some(ty) = typeck_results.borrow().expr_ty_opt(expr)
|
||||||
&& self.predicate_may_hold(&self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred, ty))
|
&& self.predicate_may_hold(&self.mk_trait_obligation_with_new_self_ty(
|
||||||
|
obligation.param_env, trait_pred.map_bound(|trait_pred| (trait_pred, ty))
|
||||||
|
))
|
||||||
{
|
{
|
||||||
err.span_label(
|
err.span_label(
|
||||||
expr.span,
|
expr.span,
|
||||||
|
@ -2727,8 +2734,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
let try_obligation = self.mk_trait_obligation_with_new_self_ty(
|
let try_obligation = self.mk_trait_obligation_with_new_self_ty(
|
||||||
obligation.param_env,
|
obligation.param_env,
|
||||||
trait_pred,
|
trait_pred.map_bound(|trait_pred| (trait_pred, normalized_ty.ty().unwrap())),
|
||||||
normalized_ty.ty().unwrap(),
|
|
||||||
);
|
);
|
||||||
debug!("suggest_await_before_try: try_trait_obligation {:?}", try_obligation);
|
debug!("suggest_await_before_try: try_trait_obligation {:?}", try_obligation);
|
||||||
if self.predicate_may_hold(&try_obligation)
|
if self.predicate_may_hold(&try_obligation)
|
||||||
|
|
|
@ -12,20 +12,14 @@ LL | assert_eq!(foo, y);
|
||||||
error[E0277]: `for<'r> fn(&'r i32) -> &'r i32 {foo}` doesn't implement `Debug`
|
error[E0277]: `for<'r> fn(&'r i32) -> &'r i32 {foo}` doesn't implement `Debug`
|
||||||
--> $DIR/issue-77910-1.rs:8:5
|
--> $DIR/issue-77910-1.rs:8:5
|
||||||
|
|
|
|
||||||
|
LL | fn foo(s: &i32) -> &i32 {
|
||||||
|
| --- consider calling this function
|
||||||
|
...
|
||||||
LL | assert_eq!(foo, y);
|
LL | assert_eq!(foo, y);
|
||||||
| ^^^^^^^^^^^^^^^^^^ `for<'r> fn(&'r i32) -> &'r i32 {foo}` cannot be formatted using `{:?}` because it doesn't implement `Debug`
|
| ^^^^^^^^^^^^^^^^^^ `for<'r> fn(&'r i32) -> &'r i32 {foo}` cannot be formatted using `{:?}` because it doesn't implement `Debug`
|
||||||
|
|
|
|
||||||
= help: the trait `Debug` is not implemented for `for<'r> fn(&'r i32) -> &'r i32 {foo}`
|
= help: the trait `Debug` is not implemented for `for<'r> fn(&'r i32) -> &'r i32 {foo}`
|
||||||
= help: the following other types implement trait `Debug`:
|
= help: use parentheses to call the function: `foo(s)`
|
||||||
extern "C" fn() -> Ret
|
|
||||||
extern "C" fn(A) -> Ret
|
|
||||||
extern "C" fn(A, ...) -> Ret
|
|
||||||
extern "C" fn(A, B) -> Ret
|
|
||||||
extern "C" fn(A, B, ...) -> Ret
|
|
||||||
extern "C" fn(A, B, C) -> Ret
|
|
||||||
extern "C" fn(A, B, C, ...) -> Ret
|
|
||||||
extern "C" fn(A, B, C, D) -> Ret
|
|
||||||
and 68 others
|
|
||||||
= note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
|
@ -5,6 +5,7 @@ LL | foo::<S>(s);
|
||||||
| ^^^^^^^^ the trait `for<'b> Trait` is not implemented for `&'b S`
|
| ^^^^^^^^ the trait `for<'b> Trait` is not implemented for `&'b S`
|
||||||
|
|
|
|
||||||
= help: the trait `Trait` is implemented for `&'a mut S`
|
= help: the trait `Trait` is implemented for `&'a mut S`
|
||||||
|
= note: `for<'b> Trait` is implemented for `&'b mut S`, but not for `&'b S`
|
||||||
note: required by a bound in `foo`
|
note: required by a bound in `foo`
|
||||||
--> $DIR/imm-ref-trait-object-literal-bound-regions.rs:11:20
|
--> $DIR/imm-ref-trait-object-literal-bound-regions.rs:11:20
|
||||||
|
|
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue