Skip to content

Commit a35e26d

Browse files
authored
Rollup merge of rust-lang#99618 - compiler-errors:uhh-idk, r=lcnr
handle consts with param/infer in `const_eval_resolve` better This PR addresses [this thread here](rust-lang#99449 (comment)). Was this the change you were looking for `@lcnr?` Interestingly, one test has begun to pass. Was that expected? r? `@lcnr`
2 parents b629c85 + b248647 commit a35e26d

File tree

4 files changed

+61
-62
lines changed

4 files changed

+61
-62
lines changed

compiler/rustc_infer/src/infer/mod.rs

+55-6
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
2121
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
2222
use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult};
2323
use rustc_middle::traits::select;
24-
use rustc_middle::ty::abstract_const::AbstractConst;
24+
use rustc_middle::ty::abstract_const::{AbstractConst, FailureKind};
2525
use rustc_middle::ty::error::{ExpectedFound, TypeError};
2626
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
2727
use rustc_middle::ty::relate::RelateResult;
@@ -1675,7 +1675,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
16751675
#[instrument(skip(self), level = "debug")]
16761676
pub fn const_eval_resolve(
16771677
&self,
1678-
param_env: ty::ParamEnv<'tcx>,
1678+
mut param_env: ty::ParamEnv<'tcx>,
16791679
unevaluated: ty::Unevaluated<'tcx>,
16801680
span: Option<Span>,
16811681
) -> EvalToValTreeResult<'tcx> {
@@ -1686,10 +1686,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
16861686
// variables
16871687
if substs.has_infer_types_or_consts() {
16881688
let ac = AbstractConst::new(self.tcx, unevaluated.shrink());
1689-
if let Ok(None) = ac {
1690-
substs = InternalSubsts::identity_for_item(self.tcx, unevaluated.def.did);
1691-
} else {
1692-
return Err(ErrorHandled::TooGeneric);
1689+
match ac {
1690+
Ok(None) => {
1691+
substs = InternalSubsts::identity_for_item(self.tcx, unevaluated.def.did);
1692+
param_env = self.tcx.param_env(unevaluated.def.did);
1693+
}
1694+
Ok(Some(ct)) => {
1695+
if ct.unify_failure_kind(self.tcx) == FailureKind::Concrete {
1696+
substs = replace_param_and_infer_substs_with_placeholder(self.tcx, substs);
1697+
} else {
1698+
return Err(ErrorHandled::TooGeneric);
1699+
}
1700+
}
1701+
Err(guar) => return Err(ErrorHandled::Reported(guar)),
16931702
}
16941703
}
16951704

@@ -2000,3 +2009,43 @@ impl<'tcx> fmt::Debug for RegionObligation<'tcx> {
20002009
)
20012010
}
20022011
}
2012+
2013+
/// Replaces substs that reference param or infer variables with suitable
2014+
/// placeholders. This function is meant to remove these param and infer
2015+
/// substs when they're not actually needed to evaluate a constant.
2016+
fn replace_param_and_infer_substs_with_placeholder<'tcx>(
2017+
tcx: TyCtxt<'tcx>,
2018+
substs: SubstsRef<'tcx>,
2019+
) -> SubstsRef<'tcx> {
2020+
tcx.mk_substs(substs.iter().enumerate().map(|(idx, arg)| {
2021+
match arg.unpack() {
2022+
GenericArgKind::Type(_)
2023+
if arg.has_param_types_or_consts() || arg.has_infer_types_or_consts() =>
2024+
{
2025+
tcx.mk_ty(ty::Placeholder(ty::PlaceholderType {
2026+
universe: ty::UniverseIndex::ROOT,
2027+
name: ty::BoundVar::from_usize(idx),
2028+
}))
2029+
.into()
2030+
}
2031+
GenericArgKind::Const(ct)
2032+
if ct.has_infer_types_or_consts() || ct.has_param_types_or_consts() =>
2033+
{
2034+
let ty = ct.ty();
2035+
// If the type references param or infer, replace that too...
2036+
if ty.has_param_types_or_consts() || ty.has_infer_types_or_consts() {
2037+
bug!("const `{ct}`'s type should not reference params or types");
2038+
}
2039+
tcx.mk_const(ty::ConstS {
2040+
ty,
2041+
kind: ty::ConstKind::Placeholder(ty::PlaceholderConst {
2042+
universe: ty::UniverseIndex::ROOT,
2043+
name: ty::BoundConst { ty, var: ty::BoundVar::from_usize(idx) },
2044+
}),
2045+
})
2046+
.into()
2047+
}
2048+
_ => arg,
2049+
}
2050+
}))
2051+
}

compiler/rustc_trait_selection/src/traits/const_evaluatable.rs

+4-13
Original file line numberDiff line numberDiff line change
@@ -185,21 +185,12 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
185185
}
186186
let concrete = infcx.const_eval_resolve(param_env, uv.expand(), Some(span));
187187
match concrete {
188-
Err(ErrorHandled::TooGeneric) => Err(if uv.has_infer_types_or_consts() {
189-
NotConstEvaluatable::MentionsInfer
190-
} else if uv.has_param_types_or_consts() {
191-
infcx
192-
.tcx
193-
.sess
194-
.delay_span_bug(span, &format!("unexpected `TooGeneric` for {:?}", uv));
195-
NotConstEvaluatable::MentionsParam
196-
} else {
197-
let guar = infcx.tcx.sess.delay_span_bug(
188+
Err(ErrorHandled::TooGeneric) => {
189+
Err(NotConstEvaluatable::Error(infcx.tcx.sess.delay_span_bug(
198190
span,
199191
format!("Missing value for constant, but no error reported?"),
200-
);
201-
NotConstEvaluatable::Error(guar)
202-
}),
192+
)))
193+
}
203194
Err(ErrorHandled::Linted) => {
204195
let reported = infcx
205196
.tcx

src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// check-pass
2+
13
#![feature(generic_const_exprs)]
24
#![allow(incomplete_features)]
35

@@ -21,11 +23,6 @@ where
2123
}
2224

2325
fn main() {
24-
// FIXME(generic_const_exprs): We can't correctly infer `T` which requires
25-
// evaluating `{ N + 1 }` which has substs containing an inference var
2626
let mut _q = Default::default();
27-
//~^ ERROR type annotations needed
28-
2927
_q = foo::<_, 2>(_q);
30-
//~^ ERROR type annotations needed
3128
}

src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.stderr

-38
This file was deleted.

0 commit comments

Comments
 (0)