mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
do not attempt to prove unknowable goals
This commit is contained in:
parent
6199b69c53
commit
6188aae369
@ -304,6 +304,11 @@ where
|
|||||||
|
|
||||||
let mut candidates = vec![];
|
let mut candidates = vec![];
|
||||||
|
|
||||||
|
if self.solver_mode() == SolverMode::Coherence {
|
||||||
|
if let Ok(candidate) = self.consider_coherence_unknowable_candidate(goal) {
|
||||||
|
return vec![candidate];
|
||||||
|
}
|
||||||
|
}
|
||||||
self.assemble_impl_candidates(goal, &mut candidates);
|
self.assemble_impl_candidates(goal, &mut candidates);
|
||||||
|
|
||||||
self.assemble_builtin_impl_candidates(goal, &mut candidates);
|
self.assemble_builtin_impl_candidates(goal, &mut candidates);
|
||||||
@ -314,11 +319,8 @@ where
|
|||||||
|
|
||||||
self.assemble_param_env_candidates(goal, &mut candidates);
|
self.assemble_param_env_candidates(goal, &mut candidates);
|
||||||
|
|
||||||
match self.solver_mode() {
|
if self.solver_mode() == SolverMode::Normal {
|
||||||
SolverMode::Normal => self.discard_impls_shadowed_by_env(goal, &mut candidates),
|
self.discard_impls_shadowed_by_env(goal, &mut candidates);
|
||||||
SolverMode::Coherence => {
|
|
||||||
self.assemble_coherence_unknowable_candidates(goal, &mut candidates)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
candidates
|
candidates
|
||||||
@ -682,38 +684,34 @@ where
|
|||||||
/// also consider impls which may get added in a downstream or sibling crate
|
/// also consider impls which may get added in a downstream or sibling crate
|
||||||
/// or which an upstream impl may add in a minor release.
|
/// or which an upstream impl may add in a minor release.
|
||||||
///
|
///
|
||||||
/// To do so we add an ambiguous candidate in case such an unknown impl could
|
/// To do so we return a single ambiguous candidate in case such an unknown
|
||||||
/// apply to the current goal.
|
/// impl could apply to the current goal.
|
||||||
#[instrument(level = "trace", skip_all)]
|
#[instrument(level = "trace", skip_all)]
|
||||||
fn assemble_coherence_unknowable_candidates<G: GoalKind<D>>(
|
fn consider_coherence_unknowable_candidate<G: GoalKind<D>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
goal: Goal<I, G>,
|
goal: Goal<I, G>,
|
||||||
candidates: &mut Vec<Candidate<I>>,
|
) -> Result<Candidate<I>, NoSolution> {
|
||||||
) {
|
self.probe_trait_candidate(CandidateSource::CoherenceUnknowable).enter(|ecx| {
|
||||||
let cx = self.cx();
|
let cx = ecx.cx();
|
||||||
|
let trait_ref = goal.predicate.trait_ref(cx);
|
||||||
candidates.extend(self.probe_trait_candidate(CandidateSource::CoherenceUnknowable).enter(
|
if ecx.trait_ref_is_knowable(goal.param_env, trait_ref)? {
|
||||||
|ecx| {
|
Err(NoSolution)
|
||||||
let trait_ref = goal.predicate.trait_ref(cx);
|
} else {
|
||||||
if ecx.trait_ref_is_knowable(goal.param_env, trait_ref)? {
|
// While the trait bound itself may be unknowable, we may be able to
|
||||||
Err(NoSolution)
|
// prove that a super trait is not implemented. For this, we recursively
|
||||||
} else {
|
// prove the super trait bounds of the current goal.
|
||||||
// While the trait bound itself may be unknowable, we may be able to
|
//
|
||||||
// prove that a super trait is not implemented. For this, we recursively
|
// We skip the goal itself as that one would cycle.
|
||||||
// prove the super trait bounds of the current goal.
|
let predicate: I::Predicate = trait_ref.upcast(cx);
|
||||||
//
|
ecx.add_goals(
|
||||||
// We skip the goal itself as that one would cycle.
|
GoalSource::Misc,
|
||||||
let predicate: I::Predicate = trait_ref.upcast(cx);
|
elaborate::elaborate(cx, [predicate])
|
||||||
ecx.add_goals(
|
.skip(1)
|
||||||
GoalSource::Misc,
|
.map(|predicate| goal.with(cx, predicate)),
|
||||||
elaborate::elaborate(cx, [predicate])
|
);
|
||||||
.skip(1)
|
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
|
||||||
.map(|predicate| goal.with(cx, predicate)),
|
}
|
||||||
);
|
})
|
||||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If there's a where-bound for the current goal, do not use any impl candidates
|
/// If there's a where-bound for the current goal, do not use any impl candidates
|
||||||
|
@ -29,6 +29,7 @@ use crate::infer::outlives::env::OutlivesEnvironment;
|
|||||||
use crate::infer::InferOk;
|
use crate::infer::InferOk;
|
||||||
use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor};
|
use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor};
|
||||||
use crate::solve::{deeply_normalize_for_diagnostics, inspect};
|
use crate::solve::{deeply_normalize_for_diagnostics, inspect};
|
||||||
|
use crate::traits::query::evaluate_obligation::InferCtxtExt;
|
||||||
use crate::traits::select::IntercrateAmbiguityCause;
|
use crate::traits::select::IntercrateAmbiguityCause;
|
||||||
use crate::traits::{
|
use crate::traits::{
|
||||||
util, FulfillmentErrorCode, NormalizeExt, Obligation, ObligationCause, PredicateObligation,
|
util, FulfillmentErrorCode, NormalizeExt, Obligation, ObligationCause, PredicateObligation,
|
||||||
@ -624,14 +625,13 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> {
|
|||||||
// at ambiguous goals, as for others the coherence unknowable candidate
|
// at ambiguous goals, as for others the coherence unknowable candidate
|
||||||
// was irrelevant.
|
// was irrelevant.
|
||||||
match goal.result() {
|
match goal.result() {
|
||||||
Ok(Certainty::Maybe(_)) => {}
|
|
||||||
Ok(Certainty::Yes) | Err(NoSolution) => return,
|
Ok(Certainty::Yes) | Err(NoSolution) => return,
|
||||||
|
Ok(Certainty::Maybe(_)) => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
let Goal { param_env, predicate } = goal.goal();
|
|
||||||
|
|
||||||
// For bound predicates we simply call `infcx.enter_forall`
|
// For bound predicates we simply call `infcx.enter_forall`
|
||||||
// and then prove the resulting predicate as a nested goal.
|
// and then prove the resulting predicate as a nested goal.
|
||||||
|
let Goal { param_env, predicate } = goal.goal();
|
||||||
let trait_ref = match predicate.kind().no_bound_vars() {
|
let trait_ref = match predicate.kind().no_bound_vars() {
|
||||||
Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr))) => tr.trait_ref,
|
Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr))) => tr.trait_ref,
|
||||||
Some(ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)))
|
Some(ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)))
|
||||||
@ -645,7 +645,11 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> {
|
|||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add ambiguity causes for reservation impls.
|
if trait_ref.references_error() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut candidates = goal.candidates();
|
||||||
for cand in goal.candidates() {
|
for cand in goal.candidates() {
|
||||||
if let inspect::ProbeKind::TraitCandidate {
|
if let inspect::ProbeKind::TraitCandidate {
|
||||||
source: CandidateSource::Impl(def_id),
|
source: CandidateSource::Impl(def_id),
|
||||||
@ -664,78 +668,68 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add ambiguity causes for unknowable goals.
|
// We also look for unknowable candidates. In case a goal is unknowable, there's
|
||||||
let mut ambiguity_cause = None;
|
// always exactly 1 candidate.
|
||||||
for cand in goal.candidates() {
|
let Some(cand) = candidates.pop() else {
|
||||||
if let inspect::ProbeKind::TraitCandidate {
|
return;
|
||||||
source: CandidateSource::CoherenceUnknowable,
|
};
|
||||||
result: Ok(_),
|
|
||||||
} = cand.kind()
|
|
||||||
{
|
|
||||||
let lazily_normalize_ty = |mut ty: Ty<'tcx>| {
|
|
||||||
if matches!(ty.kind(), ty::Alias(..)) {
|
|
||||||
let ocx = ObligationCtxt::new(infcx);
|
|
||||||
ty = ocx
|
|
||||||
.structurally_normalize(&ObligationCause::dummy(), param_env, ty)
|
|
||||||
.map_err(|_| ())?;
|
|
||||||
if !ocx.select_where_possible().is_empty() {
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(ty)
|
|
||||||
};
|
|
||||||
|
|
||||||
infcx.probe(|_| {
|
let inspect::ProbeKind::TraitCandidate {
|
||||||
match trait_ref_is_knowable(infcx, trait_ref, lazily_normalize_ty) {
|
source: CandidateSource::CoherenceUnknowable,
|
||||||
Err(()) => {}
|
result: Ok(_),
|
||||||
Ok(Ok(())) => warn!("expected an unknowable trait ref: {trait_ref:?}"),
|
} = cand.kind()
|
||||||
Ok(Err(conflict)) => {
|
else {
|
||||||
if !trait_ref.references_error() {
|
return;
|
||||||
// Normalize the trait ref for diagnostics, ignoring any errors if this fails.
|
};
|
||||||
let trait_ref =
|
|
||||||
deeply_normalize_for_diagnostics(infcx, param_env, trait_ref);
|
|
||||||
|
|
||||||
let self_ty = trait_ref.self_ty();
|
let lazily_normalize_ty = |mut ty: Ty<'tcx>| {
|
||||||
let self_ty = self_ty.has_concrete_skeleton().then(|| self_ty);
|
if matches!(ty.kind(), ty::Alias(..)) {
|
||||||
ambiguity_cause = Some(match conflict {
|
let ocx = ObligationCtxt::new(infcx);
|
||||||
Conflict::Upstream => {
|
ty = ocx
|
||||||
IntercrateAmbiguityCause::UpstreamCrateUpdate {
|
.structurally_normalize(&ObligationCause::dummy(), param_env, ty)
|
||||||
trait_ref,
|
.map_err(|_| ())?;
|
||||||
self_ty,
|
if !ocx.select_where_possible().is_empty() {
|
||||||
}
|
return Err(());
|
||||||
}
|
|
||||||
Conflict::Downstream => {
|
|
||||||
IntercrateAmbiguityCause::DownstreamCrate {
|
|
||||||
trait_ref,
|
|
||||||
self_ty,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
match cand.result() {
|
|
||||||
// We only add an ambiguity cause if the goal would otherwise
|
|
||||||
// result in an error.
|
|
||||||
//
|
|
||||||
// FIXME: While this matches the behavior of the
|
|
||||||
// old solver, it is not the only way in which the unknowable
|
|
||||||
// candidates *weaken* coherence, they can also force otherwise
|
|
||||||
// successful normalization to be ambiguous.
|
|
||||||
Ok(Certainty::Maybe(_) | Certainty::Yes) => {
|
|
||||||
ambiguity_cause = None;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Err(NoSolution) => continue,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
Ok(ty)
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(ambiguity_cause) = ambiguity_cause {
|
infcx.probe(|_| {
|
||||||
self.causes.insert(ambiguity_cause);
|
let conflict = match trait_ref_is_knowable(infcx, trait_ref, lazily_normalize_ty) {
|
||||||
}
|
Err(()) => return,
|
||||||
|
Ok(Ok(())) => {
|
||||||
|
warn!("expected an unknowable trait ref: {trait_ref:?}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Ok(Err(conflict)) => conflict,
|
||||||
|
};
|
||||||
|
|
||||||
|
// It is only relevant that a goal is unknowable if it would have otherwise
|
||||||
|
// failed.
|
||||||
|
let non_intercrate_infcx = infcx.fork_with_intercrate(false);
|
||||||
|
if non_intercrate_infcx.predicate_may_hold(&Obligation::new(
|
||||||
|
infcx.tcx,
|
||||||
|
ObligationCause::dummy(),
|
||||||
|
param_env,
|
||||||
|
predicate,
|
||||||
|
)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize the trait ref for diagnostics, ignoring any errors if this fails.
|
||||||
|
let trait_ref = deeply_normalize_for_diagnostics(infcx, param_env, trait_ref);
|
||||||
|
let self_ty = trait_ref.self_ty();
|
||||||
|
let self_ty = self_ty.has_concrete_skeleton().then(|| self_ty);
|
||||||
|
self.causes.insert(match conflict {
|
||||||
|
Conflict::Upstream => {
|
||||||
|
IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_ref, self_ty }
|
||||||
|
}
|
||||||
|
Conflict::Downstream => {
|
||||||
|
IntercrateAmbiguityCause::DownstreamCrate { trait_ref, self_ty }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ pub enum Reveal {
|
|||||||
All,
|
All,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum SolverMode {
|
pub enum SolverMode {
|
||||||
/// Ordinary trait solving, using everywhere except for coherence.
|
/// Ordinary trait solving, using everywhere except for coherence.
|
||||||
Normal,
|
Normal,
|
||||||
|
@ -7,7 +7,7 @@ LL |
|
|||||||
LL | impl<S: Iterator> MyTrait<S> for (Box<<(MyType,) as Mirror>::Assoc>, S::Item) {}
|
LL | impl<S: Iterator> MyTrait<S> for (Box<<(MyType,) as Mirror>::Assoc>, S::Item) {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(Box<(MyType,)>, <_ as Iterator>::Item)`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(Box<(MyType,)>, <_ as Iterator>::Item)`
|
||||||
|
|
|
|
||||||
= note: upstream crates may add a new impl of trait `std::clone::Clone` for type `(MyType,)` in future versions
|
= note: upstream crates may add a new impl of trait `std::clone::Clone` for type `std::boxed::Box<(MyType,)>` in future versions
|
||||||
= note: upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions
|
= note: upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
@ -18,6 +18,6 @@ impl<S: Iterator> MyTrait<S> for (Box<<(MyType,) as Mirror>::Assoc>, S::Item) {}
|
|||||||
//~^ ERROR conflicting implementations of trait `MyTrait<_>` for type `(Box<(MyType,)>,
|
//~^ ERROR conflicting implementations of trait `MyTrait<_>` for type `(Box<(MyType,)>,
|
||||||
//~| NOTE conflicting implementation for `(Box<(MyType,)>,
|
//~| NOTE conflicting implementation for `(Box<(MyType,)>,
|
||||||
//~| NOTE upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions
|
//~| NOTE upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions
|
||||||
//[next]~| NOTE upstream crates may add a new impl of trait `std::clone::Clone` for type `(MyType,)` in future versions
|
//[next]~| NOTE upstream crates may add a new impl of trait `std::clone::Clone` for type `std::boxed::Box<(MyType,)>` in future versions
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
Loading…
Reference in New Issue
Block a user