Skip to content

Report overflows gracefully with new solver #110103

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 13, 2023
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
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

#[instrument(skip(self), level = "debug")]
pub(in super::super) fn report_ambiguity_errors(&self) {
let mut errors = self.fulfillment_cx.borrow_mut().collect_remaining_errors();
let mut errors = self.fulfillment_cx.borrow_mut().collect_remaining_errors(self);

if !errors.is_empty() {
self.adjust_fulfillment_errors_for_expr_obligation(&mut errors);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Finally, for ambiguity-related errors, we actually want to look
// for a parameter that is the source of the inference type left
// over in this predicate.
if let traits::FulfillmentErrorCode::CodeAmbiguity = error.code {
if let traits::FulfillmentErrorCode::CodeAmbiguity { .. } = error.code {
fallback_param_to_point_at = None;
self_param_to_point_at = None;
param_to_point_at =
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_infer/src/traits/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ pub trait TraitEngine<'tcx>: 'tcx {

fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>;

fn collect_remaining_errors(&mut self) -> Vec<FulfillmentError<'tcx>>;
fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>;

fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>>;

Expand Down Expand Up @@ -78,6 +78,6 @@ impl<'tcx, T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T {
return errors;
}

self.collect_remaining_errors()
self.collect_remaining_errors(infcx)
}
}
6 changes: 5 additions & 1 deletion compiler/rustc_infer/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,11 @@ pub enum FulfillmentErrorCode<'tcx> {
CodeProjectionError(MismatchedProjectionTypes<'tcx>),
CodeSubtypeError(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate
CodeConstEquateError(ExpectedFound<Const<'tcx>>, TypeError<'tcx>),
CodeAmbiguity,
CodeAmbiguity {
/// Overflow reported from the new solver `-Ztrait-solver=next`, which will
/// be reported as an regular error as opposed to a fatal error.
overflow: bool,
},
}

impl<'tcx, O> Obligation<'tcx, O> {
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_infer/src/traits/structural_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> {
super::CodeConstEquateError(ref a, ref b) => {
write!(f, "CodeConstEquateError({:?}, {:?})", a, b)
}
super::CodeAmbiguity => write!(f, "Ambiguity"),
super::CodeAmbiguity { overflow: false } => write!(f, "Ambiguity"),
super::CodeAmbiguity { overflow: true } => write!(f, "Overflow"),
super::CodeCycle(ref cycle) => write!(f, "Cycle({:?})", cycle),
}
}
Expand Down
29 changes: 24 additions & 5 deletions compiler/rustc_trait_selection/src/solve/fulfill.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::mem;

use rustc_infer::infer::InferCtxt;
use rustc_infer::traits::solve::MaybeCause;
use rustc_infer::traits::Obligation;
use rustc_infer::traits::{
query::NoSolution, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes,
Expand Down Expand Up @@ -41,13 +42,31 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
self.obligations.push(obligation);
}

fn collect_remaining_errors(&mut self) -> Vec<FulfillmentError<'tcx>> {
fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
self.obligations
.drain(..)
.map(|obligation| FulfillmentError {
obligation: obligation.clone(),
code: FulfillmentErrorCode::CodeAmbiguity,
root_obligation: obligation,
.map(|obligation| {
let code =
infcx.probe(|_| match infcx.evaluate_root_goal(obligation.clone().into()) {
Ok((_, Certainty::Maybe(MaybeCause::Ambiguity), _)) => {
FulfillmentErrorCode::CodeAmbiguity { overflow: false }
}
Ok((_, Certainty::Maybe(MaybeCause::Overflow), _)) => {
FulfillmentErrorCode::CodeAmbiguity { overflow: true }
}
Ok((_, Certainty::Yes, _)) => {
bug!("did not expect successful goal when collecting ambiguity errors")
}
Err(_) => {
bug!("did not expect selection error when collecting ambiguity errors")
}
});

FulfillmentError {
obligation: obligation.clone(),
code,
root_obligation: obligation,
}
})
.collect()
}
Expand Down
7 changes: 5 additions & 2 deletions compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,16 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
self.obligations.insert(obligation);
}

fn collect_remaining_errors(&mut self) -> Vec<FulfillmentError<'tcx>> {
fn collect_remaining_errors(
&mut self,
_infcx: &InferCtxt<'tcx>,
) -> Vec<FulfillmentError<'tcx>> {
// any remaining obligations are errors
self.obligations
.iter()
.map(|obligation| FulfillmentError {
obligation: obligation.clone(),
code: FulfillmentErrorCode::CodeAmbiguity,
code: FulfillmentErrorCode::CodeAmbiguity { overflow: false },
// FIXME - does Chalk have a notation of 'root obligation'?
// This is just for diagnostics, so it's okay if this is wrong
root_obligation: obligation.clone(),
Expand Down
15 changes: 14 additions & 1 deletion compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ pub trait TypeErrCtxtExt<'tcx> {
+ Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>,
<T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug;

fn report_overflow_no_abort(&self, obligation: PredicateObligation<'tcx>) -> ErrorGuaranteed;

fn report_fulfillment_errors(&self, errors: &[FulfillmentError<'tcx>]) -> ErrorGuaranteed;

fn report_overflow_obligation<T>(
Expand Down Expand Up @@ -602,6 +604,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
);
}

fn report_overflow_no_abort(&self, obligation: PredicateObligation<'tcx>) -> ErrorGuaranteed {
let obligation = self.resolve_vars_if_possible(obligation);
let mut err = self.build_overflow_error(&obligation.predicate, obligation.cause.span, true);
self.note_obligation_cause(&mut err, &obligation);
self.point_at_returns_when_relevant(&mut err, &obligation);
err.emit()
}

fn report_selection_error(
&self,
mut obligation: PredicateObligation<'tcx>,
Expand Down Expand Up @@ -1658,9 +1668,12 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
FulfillmentErrorCode::CodeProjectionError(ref e) => {
self.report_projection_error(&error.obligation, e);
}
FulfillmentErrorCode::CodeAmbiguity => {
FulfillmentErrorCode::CodeAmbiguity { overflow: false } => {
self.maybe_report_ambiguity(&error.obligation);
}
FulfillmentErrorCode::CodeAmbiguity { overflow: true } => {
self.report_overflow_no_abort(error.obligation.clone());
}
FulfillmentErrorCode::CodeSubtypeError(ref expected_found, ref err) => {
self.report_mismatched_types(
&error.obligation.cause,
Expand Down
11 changes: 9 additions & 2 deletions compiler/rustc_trait_selection/src/traits/fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,15 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
.register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] });
}

fn collect_remaining_errors(&mut self) -> Vec<FulfillmentError<'tcx>> {
self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect()
fn collect_remaining_errors(
&mut self,
_infcx: &InferCtxt<'tcx>,
) -> Vec<FulfillmentError<'tcx>> {
self.predicates
.to_errors(CodeAmbiguity { overflow: false })
.into_iter()
.map(to_fulfillment_error)
.collect()
}

fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
Expand Down
7 changes: 4 additions & 3 deletions tests/ui/higher-rank-trait-bounds/issue-95230.new.stderr
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
error[E0282]: type annotations needed
error[E0275]: overflow evaluating the requirement `for<'a> &'a mut Bar well-formed`
--> $DIR/issue-95230.rs:9:13
|
LL | for<'a> &'a mut Self:;
| ^^^^^^^^^^^^ cannot infer type for mutable reference `&'a mut Bar`
| ^^^^^^^^^^^^
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_95230`)
note: required by a bound in `Bar`
--> $DIR/issue-95230.rs:9:13
|
Expand All @@ -15,4 +16,4 @@ LL | for<'a> &'a mut Self:;

error: aborting due to previous error

For more information about this error, try `rustc --explain E0282`.
For more information about this error, try `rustc --explain E0275`.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ fn needs_bar<S: Bar>() {}

fn test<T: Foo1<Assoc1 = <T as Foo2>::Assoc2> + Foo2<Assoc2 = <T as Foo1>::Assoc1>>() {
needs_bar::<T::Assoc1>();
//~^ ERROR type annotations needed
//~^ ERROR overflow evaluating the requirement `<T as Foo1>::Assoc1: Bar`
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
error[E0283]: type annotations needed: cannot satisfy `<T as Foo1>::Assoc1: Bar`
error[E0275]: overflow evaluating the requirement `<T as Foo1>::Assoc1: Bar`
--> $DIR/recursive-self-normalization-2.rs:15:5
|
LL | needs_bar::<T::Assoc1>();
| ^^^^^^^^^^^^^^^^^^^^^^
|
= note: cannot satisfy `<T as Foo1>::Assoc1: Bar`
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization_2`)
note: required by a bound in `needs_bar`
--> $DIR/recursive-self-normalization-2.rs:12:17
|
Expand All @@ -13,4 +13,4 @@ LL | fn needs_bar<S: Bar>() {}

error: aborting due to previous error

For more information about this error, try `rustc --explain E0283`.
For more information about this error, try `rustc --explain E0275`.
2 changes: 1 addition & 1 deletion tests/ui/traits/new-solver/recursive-self-normalization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ fn needs_bar<S: Bar>() {}

fn test<T: Foo<Assoc = <T as Foo>::Assoc>>() {
needs_bar::<T::Assoc>();
//~^ ERROR type annotations needed
//~^ ERROR overflow evaluating the requirement `<T as Foo>::Assoc: Bar`
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
error[E0283]: type annotations needed: cannot satisfy `<T as Foo>::Assoc: Bar`
error[E0275]: overflow evaluating the requirement `<T as Foo>::Assoc: Bar`
--> $DIR/recursive-self-normalization.rs:11:5
|
LL | needs_bar::<T::Assoc>();
| ^^^^^^^^^^^^^^^^^^^^^
|
= note: cannot satisfy `<T as Foo>::Assoc: Bar`
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization`)
note: required by a bound in `needs_bar`
--> $DIR/recursive-self-normalization.rs:8:17
|
Expand All @@ -13,4 +13,4 @@ LL | fn needs_bar<S: Bar>() {}

error: aborting due to previous error

For more information about this error, try `rustc --explain E0283`.
For more information about this error, try `rustc --explain E0275`.