Skip to content

Commit bf37847

Browse files
authored
Rollup merge of #140402 - lcnr:normalizes-to-certainty-yes, r=compiler-errors
only return nested goals for `Certainty::Yes` Ambiguous `NormalizesTo` goals can otherwise repeatedly add the same nested goals to the parent. r? ```@compiler-errors```
2 parents 469f03d + 016105c commit bf37847

File tree

3 files changed

+66
-32
lines changed

3 files changed

+66
-32
lines changed

compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs

+31-21
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,19 @@ where
8181
/// the values inferred while solving the instantiated goal.
8282
/// - `external_constraints`: additional constraints which aren't expressible
8383
/// using simple unification of inference variables.
84+
///
85+
/// This takes the `shallow_certainty` which represents whether we're confident
86+
/// that the final result of the current goal only depends on the nested goals.
87+
///
88+
/// In case this is `Certainy::Maybe`, there may still be additional nested goals
89+
/// or inference constraints required for this candidate to be hold. The candidate
90+
/// always requires all already added constraints and nested goals.
8491
#[instrument(level = "trace", skip(self), ret)]
8592
pub(in crate::solve) fn evaluate_added_goals_and_make_canonical_response(
8693
&mut self,
87-
certainty: Certainty,
94+
shallow_certainty: Certainty,
8895
) -> QueryResult<I> {
89-
self.inspect.make_canonical_response(certainty);
96+
self.inspect.make_canonical_response(shallow_certainty);
9097

9198
let goals_certainty = self.try_evaluate_added_goals()?;
9299
assert_eq!(
@@ -103,26 +110,29 @@ where
103110
NoSolution
104111
})?;
105112

106-
// When normalizing, we've replaced the expected term with an unconstrained
107-
// inference variable. This means that we dropped information which could
108-
// have been important. We handle this by instead returning the nested goals
109-
// to the caller, where they are then handled.
110-
//
111-
// As we return all ambiguous nested goals, we can ignore the certainty returned
112-
// by `try_evaluate_added_goals()`.
113-
let (certainty, normalization_nested_goals) = match self.current_goal_kind {
114-
CurrentGoalKind::NormalizesTo => {
115-
let goals = std::mem::take(&mut self.nested_goals);
116-
if goals.is_empty() {
117-
assert!(matches!(goals_certainty, Certainty::Yes));
113+
let (certainty, normalization_nested_goals) =
114+
match (self.current_goal_kind, shallow_certainty) {
115+
// When normalizing, we've replaced the expected term with an unconstrained
116+
// inference variable. This means that we dropped information which could
117+
// have been important. We handle this by instead returning the nested goals
118+
// to the caller, where they are then handled. We only do so if we do not
119+
// need to recompute the `NormalizesTo` goal afterwards to avoid repeatedly
120+
// uplifting its nested goals. This is the case if the `shallow_certainty` is
121+
// `Certainty::Yes`.
122+
(CurrentGoalKind::NormalizesTo, Certainty::Yes) => {
123+
let goals = std::mem::take(&mut self.nested_goals);
124+
// As we return all ambiguous nested goals, we can ignore the certainty
125+
// returned by `self.try_evaluate_added_goals()`.
126+
if goals.is_empty() {
127+
assert!(matches!(goals_certainty, Certainty::Yes));
128+
}
129+
(Certainty::Yes, NestedNormalizationGoals(goals))
118130
}
119-
(certainty, NestedNormalizationGoals(goals))
120-
}
121-
CurrentGoalKind::Misc | CurrentGoalKind::CoinductiveTrait => {
122-
let certainty = certainty.unify_with(goals_certainty);
123-
(certainty, NestedNormalizationGoals::empty())
124-
}
125-
};
131+
_ => {
132+
let certainty = shallow_certainty.unify_with(goals_certainty);
133+
(certainty, NestedNormalizationGoals::empty())
134+
}
135+
};
126136

127137
if let Certainty::Maybe(cause @ MaybeCause::Overflow { .. }) = certainty {
128138
// If we have overflow, it's probable that we're substituting a type

compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs

+28-10
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ mod opaque_types;
66
use rustc_type_ir::fast_reject::DeepRejectCtxt;
77
use rustc_type_ir::inherent::*;
88
use rustc_type_ir::lang_items::TraitSolverLangItem;
9-
use rustc_type_ir::{self as ty, Interner, NormalizesTo, Upcast as _};
9+
use rustc_type_ir::{self as ty, Interner, NormalizesTo, PredicateKind, Upcast as _};
1010
use tracing::instrument;
1111

1212
use crate::delegate::SolverDelegate;
@@ -227,13 +227,21 @@ where
227227
Ok(Some(target_item_def_id)) => target_item_def_id,
228228
Ok(None) => {
229229
match ecx.typing_mode() {
230-
// In case the associated item is hidden due to specialization, we have to
231-
// return ambiguity this would otherwise be incomplete, resulting in
232-
// unsoundness during coherence (#105782).
230+
// In case the associated item is hidden due to specialization,
231+
// normalizing this associated item is always ambiguous. Treating
232+
// the associated item as rigid would be incomplete and allow for
233+
// overlapping impls, see #105782.
234+
//
235+
// As this ambiguity is unavoidable we emit a nested ambiguous
236+
// goal instead of using `Certainty::AMBIGUOUS`. This allows us to
237+
// return the nested goals to the parent `AliasRelate` goal. This
238+
// would be relevant if any of the nested goals refer to the `term`.
239+
// This is not the case here and we only prefer adding an ambiguous
240+
// nested goal for consistency.
233241
ty::TypingMode::Coherence => {
234-
return ecx.evaluate_added_goals_and_make_canonical_response(
235-
Certainty::AMBIGUOUS,
236-
);
242+
ecx.add_goal(GoalSource::Misc, goal.with(cx, PredicateKind::Ambiguous));
243+
return ecx
244+
.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
237245
}
238246
// Outside of coherence, we treat the associated item as rigid instead.
239247
ty::TypingMode::Analysis { .. }
@@ -260,10 +268,20 @@ where
260268
// treat it as rigid.
261269
if cx.impl_self_is_guaranteed_unsized(impl_def_id) {
262270
match ecx.typing_mode() {
271+
// Trying to normalize such associated items is always ambiguous
272+
// during coherence to avoid cyclic reasoning. See the example in
273+
// tests/ui/traits/trivial-unsized-projection-in-coherence.rs.
274+
//
275+
// As this ambiguity is unavoidable we emit a nested ambiguous
276+
// goal instead of using `Certainty::AMBIGUOUS`. This allows us to
277+
// return the nested goals to the parent `AliasRelate` goal. This
278+
// would be relevant if any of the nested goals refer to the `term`.
279+
// This is not the case here and we only prefer adding an ambiguous
280+
// nested goal for consistency.
263281
ty::TypingMode::Coherence => {
264-
return ecx.evaluate_added_goals_and_make_canonical_response(
265-
Certainty::AMBIGUOUS,
266-
);
282+
ecx.add_goal(GoalSource::Misc, goal.with(cx, PredicateKind::Ambiguous));
283+
return ecx
284+
.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
267285
}
268286
ty::TypingMode::Analysis { .. }
269287
| ty::TypingMode::Borrowck { .. }

compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
44
use rustc_index::bit_set::GrowableBitSet;
55
use rustc_type_ir::inherent::*;
6+
use rustc_type_ir::solve::GoalSource;
67
use rustc_type_ir::{self as ty, Interner, TypingMode, fold_regions};
78

89
use crate::delegate::SolverDelegate;
@@ -31,7 +32,12 @@ where
3132
goal.param_env,
3233
expected,
3334
);
34-
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
35+
// Trying to normalize an opaque type during coherence is always ambiguous.
36+
// We add a nested ambiguous goal here instead of using `Certainty::AMBIGUOUS`.
37+
// This allows us to return the nested goals to the parent `AliasRelate` goal.
38+
// This can then allow nested goals to fail after we've constrained the `term`.
39+
self.add_goal(GoalSource::Misc, goal.with(cx, ty::PredicateKind::Ambiguous));
40+
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
3541
}
3642
TypingMode::Analysis { defining_opaque_types_and_generators } => {
3743
let Some(def_id) = opaque_ty

0 commit comments

Comments
 (0)