fix RebaseReason::Ambiguity
we should not get the certainty from the current result of the provisional cache entry
This commit is contained in:
parent
1e772f9681
commit
36283bcb7e
5 changed files with 99 additions and 15 deletions
|
|
@ -99,19 +99,23 @@ where
|
|||
response_no_constraints(cx, input, Certainty::overflow(false))
|
||||
}
|
||||
|
||||
fn is_ambiguous_result(result: QueryResult<I>) -> bool {
|
||||
result.is_ok_and(|response| {
|
||||
has_no_inference_or_external_constraints(response)
|
||||
fn is_ambiguous_result(result: QueryResult<I>) -> Option<Certainty> {
|
||||
result.ok().and_then(|response| {
|
||||
if has_no_inference_or_external_constraints(response)
|
||||
&& matches!(response.value.certainty, Certainty::Maybe { .. })
|
||||
{
|
||||
Some(response.value.certainty)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn propagate_ambiguity(
|
||||
cx: I,
|
||||
for_input: CanonicalInput<I>,
|
||||
from_result: QueryResult<I>,
|
||||
certainty: Certainty,
|
||||
) -> QueryResult<I> {
|
||||
let certainty = from_result.unwrap().value.certainty;
|
||||
response_no_constraints(cx, for_input, certainty)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use crate::inherent::*;
|
|||
use crate::ir_print::IrPrint;
|
||||
use crate::lang_items::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem};
|
||||
use crate::relate::Relate;
|
||||
use crate::solve::{CanonicalInput, ExternalConstraintsData, QueryResult, inspect};
|
||||
use crate::solve::{CanonicalInput, Certainty, ExternalConstraintsData, QueryResult, inspect};
|
||||
use crate::visit::{Flags, TypeVisitable};
|
||||
use crate::{self as ty, CanonicalParamEnvCacheEntry, search_graph};
|
||||
|
||||
|
|
@ -548,6 +548,7 @@ impl<T, R, E> CollectAndApply<T, R> for Result<T, E> {
|
|||
impl<I: Interner> search_graph::Cx for I {
|
||||
type Input = CanonicalInput<I>;
|
||||
type Result = QueryResult<I>;
|
||||
type AmbiguityInfo = Certainty;
|
||||
|
||||
type DepNodeIndex = I::DepNodeIndex;
|
||||
type Tracked<T: Debug + Clone> = I::Tracked<T>;
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ pub use global_cache::GlobalCache;
|
|||
pub trait Cx: Copy {
|
||||
type Input: Debug + Eq + Hash + Copy;
|
||||
type Result: Debug + Eq + Hash + Copy;
|
||||
type AmbiguityInfo: Debug + Eq + Hash + Copy;
|
||||
|
||||
type DepNodeIndex;
|
||||
type Tracked<T: Debug + Clone>: Debug;
|
||||
|
|
@ -96,11 +97,13 @@ pub trait Delegate: Sized {
|
|||
input: <Self::Cx as Cx>::Input,
|
||||
) -> <Self::Cx as Cx>::Result;
|
||||
|
||||
fn is_ambiguous_result(result: <Self::Cx as Cx>::Result) -> bool;
|
||||
fn is_ambiguous_result(
|
||||
result: <Self::Cx as Cx>::Result,
|
||||
) -> Option<<Self::Cx as Cx>::AmbiguityInfo>;
|
||||
fn propagate_ambiguity(
|
||||
cx: Self::Cx,
|
||||
for_input: <Self::Cx as Cx>::Input,
|
||||
from_result: <Self::Cx as Cx>::Result,
|
||||
ambiguity_info: <Self::Cx as Cx>::AmbiguityInfo,
|
||||
) -> <Self::Cx as Cx>::Result;
|
||||
|
||||
fn compute_goal(
|
||||
|
|
@ -913,9 +916,9 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
|
|||
/// heads from the stack. This may not necessarily mean that we've actually
|
||||
/// reached a fixpoint for that cycle head, which impacts the way we rebase
|
||||
/// provisional cache entries.
|
||||
enum RebaseReason {
|
||||
enum RebaseReason<X: Cx> {
|
||||
NoCycleUsages,
|
||||
Ambiguity,
|
||||
Ambiguity(X::AmbiguityInfo),
|
||||
Overflow,
|
||||
/// We've actually reached a fixpoint.
|
||||
///
|
||||
|
|
@ -951,7 +954,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D, X> {
|
|||
&mut self,
|
||||
cx: X,
|
||||
stack_entry: &StackEntry<X>,
|
||||
rebase_reason: RebaseReason,
|
||||
rebase_reason: RebaseReason<X>,
|
||||
) {
|
||||
let popped_head_index = self.stack.next_index();
|
||||
#[allow(rustc::potential_query_instability)]
|
||||
|
|
@ -1029,8 +1032,8 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D, X> {
|
|||
// is not actually equal to the final provisional result. We
|
||||
// need to discard the provisional cache entry in this case.
|
||||
RebaseReason::NoCycleUsages => return false,
|
||||
RebaseReason::Ambiguity => {
|
||||
*result = D::propagate_ambiguity(cx, input, *result);
|
||||
RebaseReason::Ambiguity(info) => {
|
||||
*result = D::propagate_ambiguity(cx, input, info);
|
||||
}
|
||||
RebaseReason::Overflow => *result = D::fixpoint_overflow_result(cx, input),
|
||||
RebaseReason::ReachedFixpoint(None) => {}
|
||||
|
|
@ -1268,6 +1271,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D, X> {
|
|||
}
|
||||
|
||||
/// Whether we've reached a fixpoint when evaluating a cycle head.
|
||||
#[instrument(level = "trace", skip(self, stack_entry), ret)]
|
||||
fn reached_fixpoint(
|
||||
&mut self,
|
||||
stack_entry: &StackEntry<X>,
|
||||
|
|
@ -1355,8 +1359,12 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D, X> {
|
|||
// As we only get to this branch if we haven't yet reached a fixpoint,
|
||||
// we also taint all provisional cache entries which depend on the
|
||||
// current goal.
|
||||
if D::is_ambiguous_result(result) {
|
||||
self.rebase_provisional_cache_entries(cx, &stack_entry, RebaseReason::Ambiguity);
|
||||
if let Some(info) = D::is_ambiguous_result(result) {
|
||||
self.rebase_provisional_cache_entries(
|
||||
cx,
|
||||
&stack_entry,
|
||||
RebaseReason::Ambiguity(info),
|
||||
);
|
||||
return EvaluationResult::finalize(stack_entry, encountered_overflow, result);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
//@ compile-flags: -Znext-solver
|
||||
#![feature(rustc_attrs)]
|
||||
#![rustc_no_implicit_bounds]
|
||||
|
||||
// A regression test making sure that when forcing dependent
|
||||
// provisional cache entries to ambiguous, we use the `MaybeCause`
|
||||
// of the cycle head. We ended up trying to use the current result
|
||||
// of the provisional cache entry, which is incorrect and caused an
|
||||
// ICE when trying to unwrap it.
|
||||
|
||||
struct Root<T>(T);
|
||||
struct Head<T>(T);
|
||||
struct Error<T>(T);
|
||||
struct NotImplemented<T>(T);
|
||||
|
||||
#[rustc_coinductive]
|
||||
trait Trait {}
|
||||
impl<T> Trait for Root<T>
|
||||
where
|
||||
Head<T>: Trait,
|
||||
{}
|
||||
|
||||
impl<T> Trait for Head<T>
|
||||
where
|
||||
Root<T>: Trait,
|
||||
T: Trait, // ambiguous
|
||||
{}
|
||||
|
||||
impl<T> Trait for Head<T>
|
||||
where
|
||||
Error<T>: Trait,
|
||||
NotImplemented<T>: Trait,
|
||||
{}
|
||||
|
||||
impl<T> Trait for Error<T>
|
||||
where
|
||||
Head<T>: Trait,
|
||||
NotImplemented<T>: Trait,
|
||||
{}
|
||||
|
||||
fn impls_trait<T: Trait>() {}
|
||||
fn main() {
|
||||
impls_trait::<Root<_>>() //~ ERROR type annotations needed
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
error[E0283]: type annotations needed
|
||||
--> $DIR/forced_ambiguity-use-head-maybe-cause.rs:43:19
|
||||
|
|
||||
LL | impls_trait::<Root<_>>()
|
||||
| ^^^^^^^ cannot infer type for struct `Head<_>`
|
||||
|
|
||||
= note: cannot satisfy `Head<_>: Trait`
|
||||
= help: the trait `Trait` is implemented for `Head<T>`
|
||||
note: required for `Root<_>` to implement `Trait`
|
||||
--> $DIR/forced_ambiguity-use-head-maybe-cause.rs:18:9
|
||||
|
|
||||
LL | impl<T> Trait for Root<T>
|
||||
| ^^^^^ ^^^^^^^
|
||||
LL | where
|
||||
LL | Head<T>: Trait,
|
||||
| ----- unsatisfied trait bound introduced here
|
||||
= note: 8 redundant requirements hidden
|
||||
= note: required for `Root<_>` to implement `Trait`
|
||||
note: required by a bound in `impls_trait`
|
||||
--> $DIR/forced_ambiguity-use-head-maybe-cause.rs:41:19
|
||||
|
|
||||
LL | fn impls_trait<T: Trait>() {}
|
||||
| ^^^^^ required by this bound in `impls_trait`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0283`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue