Split out make_ambiguous_response_no_constraints

This commit is contained in:
Michael Goulet 2023-04-26 22:33:33 +00:00
parent 5fa82092ae
commit ee8942138a
2 changed files with 52 additions and 29 deletions

View File

@ -70,25 +70,14 @@ pub(in crate::solve) fn evaluate_added_goals_and_make_canonical_response(
// 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,
}
//
// This may prevent us from potentially useful inference, e.g.
// 2 candidates, one ambiguous and one overflow, which both
// have the same inference constraints.
//
// Changing this to retain some constraints in the future
// won't be a breaking change, so this is good enough for now.
return Ok(self.make_ambiguous_response_no_constraints(MaybeCause::Overflow));
}
};
@ -101,6 +90,40 @@ pub(in crate::solve) fn evaluate_added_goals_and_make_canonical_response(
Ok(canonical)
}
/// Constructs a totally unconstrained, ambiguous response to a goal.
///
/// Take care when using this, since often it's useful to respond with
/// ambiguity but return constrained variables to guide inference.
pub(in crate::solve) fn make_ambiguous_response_no_constraints(
&self,
maybe_cause: MaybeCause,
) -> CanonicalResponse<'tcx> {
let unconstrained_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: Certainty::Maybe(maybe_cause),
};
Canonicalizer::canonicalize(
self.infcx,
CanonicalizeMode::Response { max_input_universe: self.max_input_universe },
&mut Default::default(),
unconstrained_response,
)
}
#[instrument(level = "debug", skip(self), ret)]
fn compute_external_query_constraints(&self) -> Result<ExternalConstraints<'tcx>, NoSolution> {
// Cannot use `take_registered_region_obligations` as we may compute the response

View File

@ -340,17 +340,17 @@ fn flounder(&mut self, responses: &[CanonicalResponse<'tcx>]) -> QueryResult<'tc
if responses.is_empty() {
return Err(NoSolution);
}
let certainty = responses.iter().fold(Certainty::AMBIGUOUS, |certainty, response| {
certainty.unify_with(response.value.certainty)
});
let response = self.evaluate_added_goals_and_make_canonical_response(certainty);
if let Ok(response) = response {
assert!(response.has_no_inference_or_external_constraints());
Ok(response)
} else {
bug!("failed to make floundered response: {responses:?}");
}
let Certainty::Maybe(maybe_cause) = responses.iter().fold(
Certainty::AMBIGUOUS,
|certainty, response| {
certainty.unify_with(response.value.certainty)
},
) else {
bug!("expected flounder response to be ambiguous")
};
Ok(self.make_ambiguous_response_no_constraints(maybe_cause))
}
}