Skip to content

Commit cb1d80d

Browse files
authored
Rollup merge of rust-lang#130273 - lcnr:overflow-no-constraints, r=compiler-errors
more eagerly discard constraints on overflow We always discard the results of overflowing goals inside of the trait solver. We previously did so when instantiating the response in `evaluate_goal`. Canonicalizing results only to later discard them is also inefficient 🤷 It's simpler and nicer to debug to eagerly discard constraints inside of the query itself. r? ``@compiler-errors``
2 parents 7cae463 + 675c99f commit cb1d80d

File tree

5 files changed

+27
-35
lines changed

5 files changed

+27
-35
lines changed

Diff for: compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs

+15
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,21 @@ where
122122
(certainty, NestedNormalizationGoals::empty())
123123
};
124124

125+
if let Certainty::Maybe(cause @ MaybeCause::Overflow { .. }) = certainty {
126+
// If we have overflow, it's probable that we're substituting a type
127+
// into itself infinitely and any partial substitutions in the query
128+
// response are probably not useful anyways, so just return an empty
129+
// query response.
130+
//
131+
// This may prevent us from potentially useful inference, e.g.
132+
// 2 candidates, one ambiguous and one overflow, which both
133+
// have the same inference constraints.
134+
//
135+
// Changing this to retain some constraints in the future
136+
// won't be a breaking change, so this is good enough for now.
137+
return Ok(self.make_ambiguous_response_no_constraints(cause));
138+
}
139+
125140
let external_constraints =
126141
self.compute_external_query_constraints(certainty, normalization_nested_goals);
127142
let (var_values, mut external_constraints) = (self.var_values, external_constraints)

Diff for: compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs

+7-26
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use crate::delegate::SolverDelegate;
1717
use crate::solve::inspect::{self, ProofTreeBuilder};
1818
use crate::solve::search_graph::SearchGraph;
1919
use crate::solve::{
20-
CanonicalInput, CanonicalResponse, Certainty, Goal, GoalEvaluationKind, GoalSource, MaybeCause,
20+
CanonicalInput, CanonicalResponse, Certainty, Goal, GoalEvaluationKind, GoalSource,
2121
NestedNormalizationGoals, NoSolution, PredefinedOpaquesData, QueryResult, SolverMode,
2222
FIXPOINT_STEP_LIMIT,
2323
};
@@ -370,20 +370,19 @@ where
370370
canonical_goal,
371371
&mut goal_evaluation,
372372
);
373-
let canonical_response = match canonical_response {
373+
let response = match canonical_response {
374374
Err(e) => {
375375
self.inspect.goal_evaluation(goal_evaluation);
376376
return Err(e);
377377
}
378378
Ok(response) => response,
379379
};
380380

381-
let (normalization_nested_goals, certainty, has_changed) = self
382-
.instantiate_response_discarding_overflow(
383-
goal.param_env,
384-
orig_values,
385-
canonical_response,
386-
);
381+
let has_changed = !response.value.var_values.is_identity_modulo_regions()
382+
|| !response.value.external_constraints.opaque_types.is_empty();
383+
384+
let (normalization_nested_goals, certainty) =
385+
self.instantiate_and_apply_query_response(goal.param_env, orig_values, response);
387386
self.inspect.goal_evaluation(goal_evaluation);
388387
// FIXME: We previously had an assert here that checked that recomputing
389388
// a goal after applying its constraints did not change its response.
@@ -398,24 +397,6 @@ where
398397
Ok((normalization_nested_goals, has_changed, certainty))
399398
}
400399

401-
fn instantiate_response_discarding_overflow(
402-
&mut self,
403-
param_env: I::ParamEnv,
404-
original_values: Vec<I::GenericArg>,
405-
response: CanonicalResponse<I>,
406-
) -> (NestedNormalizationGoals<I>, Certainty, bool) {
407-
if let Certainty::Maybe(MaybeCause::Overflow { .. }) = response.value.certainty {
408-
return (NestedNormalizationGoals::empty(), response.value.certainty, false);
409-
}
410-
411-
let has_changed = !response.value.var_values.is_identity_modulo_regions()
412-
|| !response.value.external_constraints.opaque_types.is_empty();
413-
414-
let (normalization_nested_goals, certainty) =
415-
self.instantiate_and_apply_query_response(param_env, original_values, response);
416-
(normalization_nested_goals, certainty, has_changed)
417-
}
418-
419400
fn compute_goal(&mut self, goal: Goal<I, I::Predicate>) -> QueryResult<I> {
420401
let Goal { param_env, predicate } = goal;
421402
let kind = predicate.kind();

Diff for: compiler/rustc_trait_selection/src/solve/fulfill.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ fn fulfillment_error_for_stalled<'tcx>(
302302
Ok((_, Certainty::Maybe(MaybeCause::Overflow { suggest_increasing_limit }))) => (
303303
FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) },
304304
// Don't look into overflows because we treat overflows weirdly anyways.
305-
// In `instantiate_response_discarding_overflow` we set `has_changed = false`,
305+
// We discard the inference constraints from overflowing goals, so
306306
// recomputing the goal again during `find_best_leaf_obligation` may apply
307307
// inference guidance that makes other goals go from ambig -> pass, for example.
308308
//

Diff for: compiler/rustc_type_ir/src/solve/mod.rs

+2-8
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,8 @@ impl<I: Interner, P> Goal<I, P> {
117117
/// Why a specific goal has to be proven.
118118
///
119119
/// This is necessary as we treat nested goals different depending on
120-
/// their source.
120+
/// their source. This is currently mostly used by proof tree visitors
121+
/// but will be used by cycle handling in the future.
121122
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
122123
#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
123124
pub enum GoalSource {
@@ -126,13 +127,6 @@ pub enum GoalSource {
126127
///
127128
/// FIXME(-Znext-solver=coinductive): Explain how and why this
128129
/// changes whether cycles are coinductive.
129-
///
130-
/// This also impacts whether we erase constraints on overflow.
131-
/// Erasing constraints is generally very useful for perf and also
132-
/// results in better error messages by avoiding spurious errors.
133-
/// We do not erase overflow constraints in `normalizes-to` goals unless
134-
/// they are from an impl where-clause. This is necessary due to
135-
/// backwards compatibility, cc trait-system-refactor-initiatitive#70.
136130
ImplWhereBound,
137131
/// Instantiating a higher-ranked goal and re-proving it.
138132
InstantiateHigherRanked,

Diff for: tests/ui/traits/next-solver/issue-118950-root-region.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ LL | impl<T> Overlap<T> for T {}
3737
LL |
3838
LL | impl<T> Overlap<for<'a> fn(Assoc<'a, T>)> for T where Missing: Overlap<T> {}
3939
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `fn(_)`
40+
|
41+
= note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
4042

4143
error: aborting due to 3 previous errors; 1 warning emitted
4244

0 commit comments

Comments
 (0)