Partially implement ConstArgHasType

This commit is contained in:
Boxy 2024-05-29 17:06:50 +01:00
parent da159eb331
commit d5bd4e233d
30 changed files with 206 additions and 327 deletions

View file

@ -197,8 +197,30 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
goal: Goal<'tcx, (ty::Const<'tcx>, Ty<'tcx>)>,
) -> QueryResult<'tcx> {
let (ct, ty) = goal.predicate;
self.eq(goal.param_env, ct.ty(), ty)?;
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
// FIXME(BoxyUwU): Really we should not be calling `ct.ty()` for any variant
// other than `ConstKind::Value`. Unfortunately this would require looking in the
// env for any `ConstArgHasType` assumptions for parameters and placeholders. I
// have not yet gotten around to implementing this though.
//
// We do still stall on infer vars though as otherwise a goal like:
// `ConstArgHasType(?x: usize, usize)` can succeed even though it might later
// get unified with some const that is not of type `usize`.
match ct.kind() {
// FIXME: Ignore effect vars because canonicalization doesn't handle them correctly
// and if we stall on the var then we wind up creating ambiguity errors in a probe
// for this goal which contains an effect var. Which then ends up ICEing.
ty::ConstKind::Infer(ty::InferConst::Var(_)) => {
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
}
ty::ConstKind::Error(_) => {
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}
_ => {
self.eq(goal.param_env, ct.ty(), ty)?;
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}
}
}
}

View file

@ -2685,6 +2685,22 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
.with_span_label(span, format!("cannot satisfy `{predicate}`"))
}
}
// Given some `ConstArgHasType(?x, usize)`, we should not emit an error such as
// "type annotations needed: cannot satisfy the constant `_` has type `usize`"
// Instead we should emit a normal error suggesting the user to turbofish the
// const parameter that is currently being inferred. Unfortunately we cannot
// nicely emit such an error so we delay an ICE incase nobody else reports it
// for us.
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
return self.tcx.sess.dcx().span_delayed_bug(
span,
format!(
"`ambiguous ConstArgHasType({:?}, {:?}) unaccompanied by inference error`",
ct, ty
),
);
}
_ => {
if let Some(e) = self.tainted_by_errors() {
return e;

View file

@ -429,16 +429,37 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
// This is because this is not ever a useful obligation to report
// as the cause of an overflow.
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq(
// Only really excercised by generic_const_exprs
DefineOpaqueTypes::Yes,
ct.ty(),
ty,
) {
Ok(inf_ok) => ProcessResult::Changed(mk_pending(inf_ok.into_obligations())),
Err(_) => ProcessResult::Error(FulfillmentErrorCode::Select(
SelectionError::Unimplemented,
)),
// FIXME(BoxyUwU): Really we should not be calling `ct.ty()` for any variant
// other than `ConstKind::Value`. Unfortunately this would require looking in the
// env for any `ConstArgHasType` assumptions for parameters and placeholders. I
// don't really want to implement this in the old solver so I haven't.
//
// We do still stall on infer vars though as otherwise a goal like:
// `ConstArgHasType(?x: usize, usize)` can succeed even though it might later
// get unified with some const that is not of type `usize`.
let ct = self.selcx.infcx.shallow_resolve_const(ct);
match ct.kind() {
ty::ConstKind::Infer(ty::InferConst::Var(vid)) => {
pending_obligation.stalled_on.clear();
pending_obligation.stalled_on.extend([TyOrConstInferVar::Const(vid)]);
ProcessResult::Unchanged
}
ty::ConstKind::Error(_) => return ProcessResult::Changed(vec![]),
_ => {
match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq(
// Only really excercised by generic_const_exprs
DefineOpaqueTypes::Yes,
ct.ty(),
ty,
) {
Ok(inf_ok) => {
ProcessResult::Changed(mk_pending(inf_ok.into_obligations()))
}
Err(_) => ProcessResult::Error(FulfillmentErrorCode::Select(
SelectionError::Unimplemented,
)),
}
}
}
}

View file

@ -992,10 +992,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig),
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
// FIXME(BoxyUwU): Really we should not be calling `ct.ty()` for any variant
// other than `ConstKind::Value`. Unfortunately this would require looking in the
// env for any `ConstArgHasType` assumptions for parameters and placeholders. I
// don't really want to implement this in the old solver so I haven't.
//
// We do still stall on infer vars though as otherwise a goal like:
// `ConstArgHasType(?x: usize, usize)` can succeed even though it might later
// get unified with some const that is not of type `usize`.
let ct = self.infcx.shallow_resolve_const(ct);
let ct_ty = match ct.kind() {
ty::ConstKind::Infer(ty::InferConst::Var(_)) => {
return Ok(EvaluatedToAmbig);
}
ty::ConstKind::Error(_) => return Ok(EvaluatedToOk),
_ => ct.ty(),
};
match self.infcx.at(&obligation.cause, obligation.param_env).eq(
// Only really excercised by generic_const_exprs
DefineOpaqueTypes::Yes,
ct.ty(),
ct_ty,
ty,
) {
Ok(inf_ok) => self.evaluate_predicates_recursively(