Skip to content

Commit

Permalink
Normalize if knowable
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Jul 24, 2023
1 parent 999877c commit d667549
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 14 deletions.
56 changes: 42 additions & 14 deletions compiler/rustc_trait_selection/src/solve/assembly/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -889,20 +889,48 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
SolverMode::Normal => return,
SolverMode::Coherence => {
let trait_ref = goal.predicate.trait_ref(self.tcx());
match coherence::trait_ref_is_knowable(self.tcx(), trait_ref) {
Ok(()) => {}
Err(_) => match self
.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
{
Ok(result) => candidates.push(Candidate {
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Ambiguity),
result,
}),
// FIXME: This will be reachable at some point if we're in
// `assemble_candidates_after_normalizing_self_ty` and we get a
// universe error. We'll deal with it at this point.
Err(NoSolution) => bug!("coherence candidate resulted in NoSolution"),
},
// will assemble in `assemble_candidates_after_normalizing_self_ty`
if matches!(trait_ref.self_ty().kind(), ty::Alias(..)) {
return;
}
let result = self.probe_candidate("unknowable candidate").enter(|ecx| {
let mut args = trait_ref.args.to_vec();
for arg in args.iter_mut().skip(1) {
let Some(ty) = arg.as_type() else {
continue;
};
let Some(normalized_ty) = ecx.normalize_non_self_ty(ty, goal.param_env)?
else {
return Ok(ecx
.evaluate_added_goals_and_make_canonical_response(
Certainty::AMBIGUOUS,
)
.unwrap());
};
*arg = normalized_ty.into();
}
match coherence::trait_ref_is_knowable(ecx.tcx(), trait_ref) {
Ok(()) => Err(NoSolution),
Err(_) => {
match ecx.evaluate_added_goals_and_make_canonical_response(
Certainty::AMBIGUOUS,
) {
Ok(result) => Ok(result),
// FIXME: This will be reachable at some point if we're in
// `assemble_candidates_after_normalizing_self_ty` and we get a
// universe error. We'll deal with it at this point.
Err(NoSolution) => {
bug!("coherence candidate resulted in NoSolution")
}
}
}
}
});
if let Ok(result) = result {
candidates.push(Candidate {
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Ambiguity),
result,
});
}
}
}
Expand Down
44 changes: 44 additions & 0 deletions compiler/rustc_trait_selection/src/solve/trait_goals.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Dealing with trait goals, i.e. `T: Trait<'a, U>`.

use super::assembly::{self, structural_traits};
use super::search_graph::OverflowHandler;
use super::{EvalCtxt, SolverMode};
use rustc_hir::def_id::DefId;
use rustc_hir::{LangItem, Movability};
Expand Down Expand Up @@ -750,4 +751,47 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
let candidates = self.assemble_and_evaluate_candidates(goal);
self.merge_candidates(candidates)
}

/// Normalize a non-self type when it is structually matched on when solving
/// a built-in goal. This is handled already through `assemble_candidates_after_normalizing_self_ty`
/// for the self type, but for other goals, additional normalization of other
/// arguments may be needed to completely implement the semantics of the trait.
///
/// This is required when structurally matching on any trait argument that is
/// not the self type.
pub(super) fn normalize_non_self_ty(
&mut self,
mut ty: Ty<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> Result<Option<Ty<'tcx>>, NoSolution> {
if !matches!(ty.kind(), ty::Alias(..)) {
return Ok(Some(ty));
}

self.repeat_while_none(
|_| Ok(None),
|ecx| {
let ty::Alias(_, projection_ty) = *ty.kind() else {
return Some(Ok(Some(ty)));
};

let normalized_ty = ecx.next_ty_infer();
let normalizes_to_goal = Goal::new(
ecx.tcx(),
param_env,
ty::Binder::dummy(ty::ProjectionPredicate {
projection_ty,
term: normalized_ty.into(),
}),
);
ecx.add_goal(normalizes_to_goal);
if let Err(err) = ecx.try_evaluate_added_goals() {
return Some(Err(err));
}

ty = ecx.resolve_vars_if_possible(normalized_ty);
None
},
)
}
}

0 comments on commit d667549

Please sign in to comment.