Skip to content

Commit

Permalink
Preserve substitutions when trying to prove trait obligation
Browse files Browse the repository at this point in the history
`mk_obligation_for_def_id` is only correct if the trait and self type do
not have any substitutions. Use a different method,
`mk_trait_obligation_with_new_self_ty` that is more clear about what is
happening.
  • Loading branch information
ecstatic-morse committed May 22, 2020
1 parent 215f2d3 commit 730c6f3
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 33 deletions.
27 changes: 16 additions & 11 deletions src/librustc_trait_selection/traits/error_reporting/mod.rs
Expand Up @@ -1000,12 +1000,11 @@ trait InferCtxtPrivExt<'tcx> {
trait_ref: &ty::PolyTraitRef<'tcx>,
);

fn mk_obligation_for_def_id(
fn mk_trait_obligation_with_new_self_ty(
&self,
def_id: DefId,
output_ty: Ty<'tcx>,
cause: ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
trait_ref: &ty::PolyTraitRef<'tcx>,
new_self_ty: Ty<'tcx>,
) -> PredicateObligation<'tcx>;

fn maybe_report_ambiguity(
Expand Down Expand Up @@ -1380,16 +1379,22 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
}
}

fn mk_obligation_for_def_id(
fn mk_trait_obligation_with_new_self_ty(
&self,
def_id: DefId,
output_ty: Ty<'tcx>,
cause: ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
trait_ref: &ty::PolyTraitRef<'tcx>,
new_self_ty: Ty<'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.without_const().to_predicate(self.tcx))
let trait_ref = trait_ref.map_bound_ref(|tr| ty::TraitRef {
substs: self.tcx.mk_substs_trait(new_self_ty, &tr.substs[1..]),
..*tr
});

Obligation::new(
ObligationCause::dummy(),
param_env,
trait_ref.without_const().to_predicate(self.tcx),
)
}

fn maybe_report_ambiguity(
Expand Down
41 changes: 19 additions & 22 deletions src/librustc_trait_selection/traits/error_reporting/suggestions.rs
Expand Up @@ -532,14 +532,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
};
let msg = format!("use parentheses to call the {}", callable);

let obligation = self.mk_obligation_for_def_id(
trait_ref.def_id(),
output_ty.skip_binder(),
obligation.cause.clone(),
let new_obligation = self.mk_trait_obligation_with_new_self_ty(
obligation.param_env,
trait_ref,
output_ty.skip_binder(),
);

match self.evaluate_obligation(&obligation) {
match self.evaluate_obligation(&new_obligation) {
Ok(
EvaluationResult::EvaluatedToOk
| EvaluationResult::EvaluatedToOkModuloRegions
Expand Down Expand Up @@ -694,7 +693,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
err: &mut DiagnosticBuilder<'_>,
trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
) {
let trait_ref = trait_ref.skip_binder();
let span = obligation.cause.span;

if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
Expand All @@ -705,17 +703,16 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
return;
}

let mut trait_type = trait_ref.self_ty();
let mut suggested_ty = trait_ref.self_ty();

for refs_remaining in 0..refs_number {
if let ty::Ref(_, t_type, _) = trait_type.kind {
trait_type = t_type;
if let ty::Ref(_, inner_ty, _) = suggested_ty.kind {
suggested_ty = inner_ty;

let new_obligation = self.mk_obligation_for_def_id(
trait_ref.def_id,
trait_type,
ObligationCause::dummy(),
let new_obligation = self.mk_trait_obligation_with_new_self_ty(
obligation.param_env,
trait_ref,
suggested_ty,
);

if self.predicate_may_hold(&new_obligation) {
Expand Down Expand Up @@ -782,20 +779,20 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
return;
}

let trait_type = match mutability {
let suggested_ty = match mutability {
hir::Mutability::Mut => self.tcx.mk_imm_ref(region, t_type),
hir::Mutability::Not => self.tcx.mk_mut_ref(region, t_type),
};

let new_obligation = self.mk_obligation_for_def_id(
trait_ref.skip_binder().def_id,
trait_type,
ObligationCause::dummy(),
let new_obligation = self.mk_trait_obligation_with_new_self_ty(
obligation.param_env,
&trait_ref,
suggested_ty,
);

if self.evaluate_obligation_no_overflow(&new_obligation).must_apply_modulo_regions()
{
let suggested_ty_would_satisfy_obligation = self
.evaluate_obligation_no_overflow(&new_obligation)
.must_apply_modulo_regions();
if suggested_ty_would_satisfy_obligation {
let sp = self
.tcx
.sess
Expand All @@ -812,7 +809,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
err.note(&format!(
"`{}` is implemented for `{:?}`, but not for `{:?}`",
trait_ref.print_only_trait_path(),
trait_type,
suggested_ty,
trait_ref.skip_binder().self_ty(),
));
}
Expand Down

0 comments on commit 730c6f3

Please sign in to comment.