Skip to content

Commit

Permalink
Rollup merge of rust-lang#110103 - compiler-errors:new-solver-overflo…
Browse files Browse the repository at this point in the history
…ws, r=lcnr

Report overflows gracefully with new solver

avoid reporting overflows as ambiguity errors, so that the error message is clearer.

r? `@lcnr`
  • Loading branch information
Dylan-DPC authored Apr 11, 2023
2 parents 30c6961 + 05a6daa commit 84e1659
Show file tree
Hide file tree
Showing 14 changed files with 75 additions and 27 deletions.
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`.

0 comments on commit 84e1659

Please sign in to comment.