Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 6 additions & 19 deletions compiler/rustc_trait_selection/src/solve/fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use self::derive_errors::*;
use super::Certainty;
use super::delegate::SolverDelegate;
use crate::error_reporting::InferCtxtErrorExt;
use crate::traits::{FulfillmentError, FulfillmentErrorCode, ScrubbedTraitError};
use crate::traits::{FulfillmentError, ScrubbedTraitError};

mod derive_errors;

Expand Down Expand Up @@ -157,8 +157,7 @@ where
// the other case.
TraitErrors::NoErrors
} else {
let errors = collect_remaining_errors_impl(self, infcx);
TraitErrors::from_iter(errors.into_iter())
TraitErrors::HasErrors(collect_remaining_errors_impl(self, infcx))
}
}

Expand Down Expand Up @@ -367,26 +366,14 @@ where
cx.obligations
.pending
.drain(..)
.filter_map(|(obligation, _)| {
try_ambiguity_error_for_stalled(infcx, obligation).map(NextSolverError::Ambiguity)
})
.map(|(obligation, _)| NextSolverError::Ambiguity(obligation))
.map(|e| E::from_solver_error(infcx, e))
.collect()
}

// We evaluate stalled obligations while collecting remaining errors because a
// previously ambiguous goal may have become successful. In that case we emit a
// delayed bug instead of producing a fulfillment error. Store the diagnostic
// information here so error conversion does not reevaluate the goal.
pub struct NextSolverAmbiguityError<'tcx> {
root_obligation: PredicateObligation<'tcx>,
code: FulfillmentErrorCode<'tcx>,
refine_obligation: bool,
}

pub enum NextSolverError<'tcx> {
TrueError(PredicateObligation<'tcx>),
Ambiguity(NextSolverAmbiguityError<'tcx>),
Ambiguity(PredicateObligation<'tcx>),
}

impl<'tcx> FromSolverError<'tcx, NextSolverError<'tcx>> for FulfillmentError<'tcx> {
Expand All @@ -395,8 +382,8 @@ impl<'tcx> FromSolverError<'tcx, NextSolverError<'tcx>> for FulfillmentError<'tc
NextSolverError::TrueError(obligation) => {
fulfillment_error_for_no_solution(infcx, obligation)
}
NextSolverError::Ambiguity(ambiguity) => {
fulfillment_error_for_stalled(infcx, ambiguity)
NextSolverError::Ambiguity(obligation) => {
fulfillment_error_for_stalled(infcx, obligation)
}
}
}
Expand Down
52 changes: 19 additions & 33 deletions compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ use rustc_next_trait_solver::solve::{GoalEvaluation, MaybeInfo, SolverDelegateEv
use rustc_span::{bug, span_bug};
use tracing::{instrument, trace};

use super::NextSolverAmbiguityError;
use crate::solve::delegate::SolverDelegate;
use crate::solve::inspect::{self, InferCtxtProofTreeExt, ProofTreeVisitor};
use crate::solve::{Certainty, deeply_normalize_for_diagnostics};
Expand Down Expand Up @@ -84,25 +83,10 @@ pub(super) fn fulfillment_error_for_no_solution<'tcx>(
}

pub(super) fn fulfillment_error_for_stalled<'tcx>(
infcx: &InferCtxt<'tcx>,
ambiguity: NextSolverAmbiguityError<'tcx>,
) -> FulfillmentError<'tcx> {
let NextSolverAmbiguityError { root_obligation, code, refine_obligation } = ambiguity;

let obligation = if refine_obligation {
find_best_leaf_obligation(infcx, &root_obligation, true)
} else {
root_obligation.clone()
};

FulfillmentError { obligation, code, root_obligation }
}

pub(super) fn try_ambiguity_error_for_stalled<'tcx>(
infcx: &InferCtxt<'tcx>,
root_obligation: PredicateObligation<'tcx>,
) -> Option<NextSolverAmbiguityError<'tcx>> {
let evaluation = infcx.probe(|_| {
) -> FulfillmentError<'tcx> {
let (code, refine_obligation) = infcx.probe(|_| {
match <&SolverDelegate<'tcx>>::from(infcx).evaluate_root_goal(
root_obligation.as_goal(),
root_obligation.cause.span,
Expand All @@ -116,7 +100,7 @@ pub(super) fn try_ambiguity_error_for_stalled<'tcx>(
stalled_on_coroutines: _,
}),
..
}) => Some((FulfillmentErrorCode::Ambiguity { overflow: None }, true)),
}) => (FulfillmentErrorCode::Ambiguity { overflow: None }, true),
Ok(GoalEvaluation {
certainty:
Certainty::Maybe(MaybeInfo {
Expand All @@ -126,7 +110,7 @@ pub(super) fn try_ambiguity_error_for_stalled<'tcx>(
stalled_on_coroutines: _,
}),
..
}) => Some((
}) => (
FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) },
// Don't look into overflows because we treat overflows weirdly anyways.
// We discard the inference constraints from overflowing goals, so
Expand All @@ -135,17 +119,13 @@ pub(super) fn try_ambiguity_error_for_stalled<'tcx>(
//
// FIXME: We should probably just look into overflows here.
false,
)),
),
Ok(GoalEvaluation { certainty: Certainty::Yes, .. }) => {
infcx.dcx().span_delayed_bug(
root_obligation.cause.span,
format!(
"did not expect successful goal when collecting ambiguity errors for `{:?}`",
infcx.deeply_resolve_ignoring_regions(root_obligation.predicate),
),
);
None
},
// FIXME: We should ICE here. See the following links for details
// - <https://rust-lang.zulipchat.com/#narrow/channel/144729-t-types/topic/resolving.20equal.20regions/near/623484902>
// - <https://github.com/rust-lang/rust/issues/161669>
(FulfillmentErrorCode::Ambiguity { overflow: None }, false)
}
Err(_) => {
span_bug!(
root_obligation.cause.span,
Expand All @@ -156,9 +136,15 @@ pub(super) fn try_ambiguity_error_for_stalled<'tcx>(
}
});

let (code, refine_obligation) = evaluation?;

Some(NextSolverAmbiguityError { root_obligation, code, refine_obligation })
FulfillmentError {
obligation: if refine_obligation {
find_best_leaf_obligation(infcx, &root_obligation, true)
} else {
root_obligation.clone()
},
code,
root_obligation,
}
}

#[instrument(level = "debug", skip(infcx), ret)]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//@ compile-flags: -Znext-solver

// Regression test for <https://github.com/rust-lang/rust/issues/162557>

pub trait Service<Request> {
type Future;
}

pub trait ZebraService<Request>: Service<Request> {}

impl<MaybeVerify, Request> ZebraService<Request> for MaybeVerify where
MaybeVerify: Service<Request, Future: 'static>
{
}

pub struct Verifier;

impl Service<()> for Verifier {
type Future = &'static ();
}

//@ set blanket = "$.index[?(@.inner.impl.blanket_impl.generic=='MaybeVerify')].id"
//@ has "$.index[?(@.name=='Verifier')].inner.struct.impls[*]" $blanket
Loading