Rollup merge of #140711 - compiler-errors:combine-maybes, r=lcnr

Do not discard constraints on overflow if there was candidate ambiguity

Fixes https://github.com/rust-lang/trait-system-refactor-initiative/issues/201.

There's a pretty chunky justification in the test.

r? lcnr
This commit is contained in:
Matthias Krüger
2025-05-08 08:14:18 +02:00
committed by GitHub
7 changed files with 130 additions and 24 deletions

View File

@@ -132,12 +132,14 @@ where
(Certainty::Yes, NestedNormalizationGoals(goals))
}
_ => {
let certainty = shallow_certainty.unify_with(goals_certainty);
let certainty = shallow_certainty.and(goals_certainty);
(certainty, NestedNormalizationGoals::empty())
}
};
if let Certainty::Maybe(cause @ MaybeCause::Overflow { .. }) = certainty {
if let Certainty::Maybe(cause @ MaybeCause::Overflow { keep_constraints: false, .. }) =
certainty
{
// 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
@@ -193,6 +195,7 @@ where
debug!(?num_non_region_vars, "too many inference variables -> overflow");
return Ok(self.make_ambiguous_response_no_constraints(MaybeCause::Overflow {
suggest_increasing_limit: true,
keep_constraints: false,
}));
}
}

View File

@@ -661,7 +661,7 @@ where
Certainty::Yes => {}
Certainty::Maybe(_) => {
self.nested_goals.push((source, with_resolved_vars));
unchanged_certainty = unchanged_certainty.map(|c| c.unify_with(certainty));
unchanged_certainty = unchanged_certainty.map(|c| c.and(certainty));
}
}
} else {
@@ -675,7 +675,7 @@ where
Certainty::Yes => {}
Certainty::Maybe(_) => {
self.nested_goals.push((source, goal));
unchanged_certainty = unchanged_certainty.map(|c| c.unify_with(certainty));
unchanged_certainty = unchanged_certainty.map(|c| c.and(certainty));
}
}
}

View File

@@ -253,16 +253,18 @@ where
}
fn bail_with_ambiguity(&mut self, responses: &[CanonicalResponse<I>]) -> CanonicalResponse<I> {
debug_assert!(!responses.is_empty());
if let Certainty::Maybe(maybe_cause) =
responses.iter().fold(Certainty::AMBIGUOUS, |certainty, response| {
certainty.unify_with(response.value.certainty)
})
{
self.make_ambiguous_response_no_constraints(maybe_cause)
} else {
panic!("expected flounder response to be ambiguous")
}
debug_assert!(responses.len() > 1);
let maybe_cause = responses.iter().fold(MaybeCause::Ambiguity, |maybe_cause, response| {
// Pull down the certainty of `Certainty::Yes` to ambiguity when combining
// these responses, b/c we're combining more than one response and this we
// don't know which one applies.
let candidate = match response.value.certainty {
Certainty::Yes => MaybeCause::Ambiguity,
Certainty::Maybe(candidate) => candidate,
};
maybe_cause.or(candidate)
});
self.make_ambiguous_response_no_constraints(maybe_cause)
}
/// If we fail to merge responses we flounder and return overflow or ambiguity.