diff options
Diffstat (limited to 'compiler/rustc_trait_selection/src/solve/mod.rs')
-rw-r--r-- | compiler/rustc_trait_selection/src/solve/mod.rs | 99 |
1 files changed, 58 insertions, 41 deletions
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 19bcbd461..56a254d9c 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -24,6 +24,7 @@ mod assembly; mod canonicalize; mod eval_ctxt; mod fulfill; +mod opaques; mod project_goals; mod search_graph; mod trait_goals; @@ -212,7 +213,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { ); } - match (lhs.to_projection_term(tcx), rhs.to_projection_term(tcx)) { + match (lhs.to_alias_ty(tcx), rhs.to_alias_ty(tcx)) { (None, None) => bug!("`AliasRelate` goal without an alias on either lhs or rhs"), // RHS is not a projection, only way this is true is if LHS normalizes-to RHS @@ -230,44 +231,60 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { let mut candidates = Vec::new(); // LHS normalizes-to RHS - candidates.extend( - evaluate_normalizes_to(self, alias_lhs, rhs, direction, Invert::No).ok(), - ); + candidates.extend(evaluate_normalizes_to( + self, + alias_lhs, + rhs, + direction, + Invert::No, + )); // RHS normalizes-to RHS - candidates.extend( - evaluate_normalizes_to(self, alias_rhs, lhs, direction, Invert::Yes).ok(), - ); + candidates.extend(evaluate_normalizes_to( + self, + alias_rhs, + lhs, + direction, + Invert::Yes, + )); // Relate via substs - candidates.extend( - self.probe(|ecx| { - let span = tracing::span!( - tracing::Level::DEBUG, - "compute_alias_relate_goal(relate_via_substs)", - ?alias_lhs, - ?alias_rhs, - ?direction - ); - let _enter = span.enter(); - - match direction { - ty::AliasRelationDirection::Equate => { - ecx.eq(goal.param_env, alias_lhs, alias_rhs)?; - } - ty::AliasRelationDirection::Subtype => { - ecx.sub(goal.param_env, alias_lhs, alias_rhs)?; - } + let subst_relate_response = self.probe(|ecx| { + let span = tracing::span!( + tracing::Level::DEBUG, + "compute_alias_relate_goal(relate_via_substs)", + ?alias_lhs, + ?alias_rhs, + ?direction + ); + let _enter = span.enter(); + + match direction { + ty::AliasRelationDirection::Equate => { + ecx.eq(goal.param_env, alias_lhs, alias_rhs)?; + } + ty::AliasRelationDirection::Subtype => { + ecx.sub(goal.param_env, alias_lhs, alias_rhs)?; } + } - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }) - .ok(), - ); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }); + candidates.extend(subst_relate_response); debug!(?candidates); if let Some(merged) = self.try_merge_responses(&candidates) { Ok(merged) } else { - self.flounder(&candidates) + // When relating two aliases and we have ambiguity, we prefer + // relating the generic arguments of the aliases over normalizing + // them. This is necessary for inference during typeck. + // + // As this is incomplete, we must not do so during coherence. + match (self.solver_mode(), subst_relate_response) { + (SolverMode::Normal, Ok(response)) => Ok(response), + (SolverMode::Normal, Err(NoSolution)) | (SolverMode::Coherence, _) => { + self.flounder(&candidates) + } + } } } } @@ -340,17 +357,17 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { if responses.is_empty() { return Err(NoSolution); } - let certainty = responses.iter().fold(Certainty::AMBIGUOUS, |certainty, response| { - certainty.unify_with(response.value.certainty) - }); - - let response = self.evaluate_added_goals_and_make_canonical_response(certainty); - if let Ok(response) = response { - assert!(response.has_no_inference_or_external_constraints()); - Ok(response) - } else { - bug!("failed to make floundered response: {responses:?}"); - } + + let Certainty::Maybe(maybe_cause) = responses.iter().fold( + Certainty::AMBIGUOUS, + |certainty, response| { + certainty.unify_with(response.value.certainty) + }, + ) else { + bug!("expected flounder response to be ambiguous") + }; + + Ok(self.make_ambiguous_response_no_constraints(maybe_cause)) } } |