Skip to content

Commit

Permalink
Clear response values for overflow in new solver
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Apr 26, 2023
1 parent 1c42cb4 commit 5fa8209
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 9 deletions.
19 changes: 13 additions & 6 deletions compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ use rustc_infer::infer::at::ToTrace;
use rustc_infer::infer::canonical::CanonicalVarValues;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{
DefineOpaqueTypes, InferCtxt, InferOk, LateBoundRegionConversionTime, TyCtxtInferExt,
DefineOpaqueTypes, InferCtxt, InferOk, LateBoundRegionConversionTime, RegionVariableOrigin,
TyCtxtInferExt,
};
use rustc_infer::traits::query::NoSolution;
use rustc_infer::traits::ObligationCause;
Expand Down Expand Up @@ -223,18 +224,20 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
{
debug!("rerunning goal to check result is stable");
let (_orig_values, canonical_goal) = self.canonicalize_goal(goal);
let canonical_response =
let new_canonical_response =
EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?;
if !canonical_response.value.var_values.is_identity() {
if !new_canonical_response.value.var_values.is_identity() {
bug!(
"unstable result: re-canonicalized goal={canonical_goal:#?} \
response={canonical_response:#?}"
first_response={canonical_response:#?} \
second_response={new_canonical_response:#?}"
);
}
if certainty != canonical_response.value.certainty {
if certainty != new_canonical_response.value.certainty {
bug!(
"unstable certainty: {certainty:#?} re-canonicalized goal={canonical_goal:#?} \
response={canonical_response:#?}"
first_response={canonical_response:#?} \
second_response={new_canonical_response:#?}"
);
}
}
Expand Down Expand Up @@ -434,6 +437,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
})
}

pub(super) fn next_region_infer(&self) -> ty::Region<'tcx> {
self.infcx.next_region_var(RegionVariableOrigin::MiscVariable(DUMMY_SP))
}

pub(super) fn next_const_infer(&self, ty: Ty<'tcx>) -> ty::Const<'tcx> {
self.infcx.next_const_var(
ty,
Expand Down
35 changes: 32 additions & 3 deletions compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use rustc_infer::infer::canonical::query_response::make_query_region_constraints
use rustc_infer::infer::canonical::CanonicalVarValues;
use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints};
use rustc_middle::traits::query::NoSolution;
use rustc_middle::traits::solve::{ExternalConstraints, ExternalConstraintsData};
use rustc_middle::traits::solve::{ExternalConstraints, ExternalConstraintsData, MaybeCause};
use rustc_middle::ty::{self, BoundVar, GenericArgKind};
use rustc_span::DUMMY_SP;
use std::iter;
Expand Down Expand Up @@ -60,9 +60,38 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {

let certainty = certainty.unify_with(goals_certainty);

let external_constraints = self.compute_external_query_constraints()?;
let response = match certainty {
Certainty::Yes | Certainty::Maybe(MaybeCause::Ambiguity) => {
let external_constraints = self.compute_external_query_constraints()?;
Response { var_values: self.var_values, external_constraints, certainty }
}
Certainty::Maybe(MaybeCause::Overflow) => {
// If we have overflow, it's probable that we're substituting a type
// into itself infinitely and any partial substitutions in the query
// response are probably not useful anyways, so just return an empty
// query response.
Response {
var_values: CanonicalVarValues {
var_values: self.tcx().mk_substs_from_iter(
self.var_values.var_values.iter().map(|arg| -> ty::GenericArg<'tcx> {
match arg.unpack() {
GenericArgKind::Lifetime(_) => self.next_region_infer().into(),
GenericArgKind::Type(_) => self.next_ty_infer().into(),
GenericArgKind::Const(ct) => {
self.next_const_infer(ct.ty()).into()
}
}
}),
),
},
external_constraints: self
.tcx()
.mk_external_constraints(ExternalConstraintsData::default()),
certainty,
}
}
};

let response = Response { var_values: self.var_values, external_constraints, certainty };
let canonical = Canonicalizer::canonicalize(
self.infcx,
CanonicalizeMode::Response { max_input_universe: self.max_input_universe },
Expand Down
20 changes: 20 additions & 0 deletions tests/ui/traits/new-solver/exponential-trait-goals.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// compile-flags: -Ztrait-solver=next

trait Trait {}

struct W<T>(T);

impl<T, U> Trait for W<(W<T>, W<U>)>
where
W<T>: Trait,
W<U>: Trait,
{
}

fn impls<T: Trait>() {}

fn main() {
impls::<W<_>>();
//~^ ERROR type annotations needed
//~| ERROR overflow evaluating the requirement `W<_>: Trait`
}
23 changes: 23 additions & 0 deletions tests/ui/traits/new-solver/exponential-trait-goals.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
error[E0282]: type annotations needed
--> $DIR/exponential-trait-goals.rs:17:5
|
LL | impls::<W<_>>();
| ^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impls`

error[E0275]: overflow evaluating the requirement `W<_>: Trait`
--> $DIR/exponential-trait-goals.rs:17:5
|
LL | impls::<W<_>>();
| ^^^^^^^^^^^^^
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`exponential_trait_goals`)
note: required by a bound in `impls`
--> $DIR/exponential-trait-goals.rs:14:13
|
LL | fn impls<T: Trait>() {}
| ^^^^^ required by this bound in `impls`

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0275, E0282.
For more information about an error, try `rustc --explain E0275`.

0 comments on commit 5fa8209

Please sign in to comment.