handle consts with param/infer in const_eval_resolve better

This commit is contained in:
Michael Goulet 2022-07-22 01:46:43 +00:00
parent 6dbae3ad19
commit f1618e8924
4 changed files with 47 additions and 62 deletions

View File

@ -21,7 +21,7 @@
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult};
use rustc_middle::traits::select;
use rustc_middle::ty::abstract_const::AbstractConst;
use rustc_middle::ty::abstract_const::{AbstractConst, FailureKind};
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::relate::RelateResult;
@ -1683,7 +1683,7 @@ pub fn try_const_eval_resolve(
#[instrument(skip(self), level = "debug")]
pub fn const_eval_resolve(
&self,
param_env: ty::ParamEnv<'tcx>,
mut param_env: ty::ParamEnv<'tcx>,
unevaluated: ty::Unevaluated<'tcx>,
span: Option<Span>,
) -> EvalToValTreeResult<'tcx> {
@ -1694,12 +1694,47 @@ pub fn const_eval_resolve(
// variables
if substs.has_infer_types_or_consts() {
let ac = AbstractConst::new(self.tcx, unevaluated.shrink());
if let Ok(None) = ac {
match ac {
Ok(None) => {
substs = InternalSubsts::identity_for_item(self.tcx, unevaluated.def.did);
param_env = self.tcx.param_env(unevaluated.def.did);
}
Ok(Some(ct)) => {
if ct.unify_failure_kind(self.tcx) == FailureKind::Concrete {
substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(idx, arg)| {
let needs_replacement =
arg.has_param_types_or_consts() || arg.has_infer_types_or_consts();
match arg.unpack() {
GenericArgKind::Type(_) if needs_replacement => self
.tcx
.mk_ty(ty::Placeholder(ty::PlaceholderType {
universe: ty::UniverseIndex::ROOT,
name: ty::BoundVar::from_usize(idx),
}))
.into(),
GenericArgKind::Const(ct) if needs_replacement => self
.tcx
.mk_const(ty::ConstS {
ty: ct.ty(),
kind: ty::ConstKind::Placeholder(ty::PlaceholderConst {
universe: ty::UniverseIndex::ROOT,
name: ty::BoundConst {
var: ty::BoundVar::from_usize(idx),
ty: ct.ty(),
},
}),
})
.into(),
_ => arg,
}
}));
} else {
return Err(ErrorHandled::TooGeneric);
}
}
Err(guar) => return Err(ErrorHandled::Reported(guar)),
}
}
let param_env_erased = self.tcx.erase_regions(param_env);
let substs_erased = self.tcx.erase_regions(substs);

View File

@ -185,21 +185,12 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
}
let concrete = infcx.const_eval_resolve(param_env, uv.expand(), Some(span));
match concrete {
Err(ErrorHandled::TooGeneric) => Err(if uv.has_infer_types_or_consts() {
NotConstEvaluatable::MentionsInfer
} else if uv.has_param_types_or_consts() {
infcx
.tcx
.sess
.delay_span_bug(span, &format!("unexpected `TooGeneric` for {:?}", uv));
NotConstEvaluatable::MentionsParam
} else {
let guar = infcx.tcx.sess.delay_span_bug(
Err(ErrorHandled::TooGeneric) => {
Err(NotConstEvaluatable::Error(infcx.tcx.sess.delay_span_bug(
span,
format!("Missing value for constant, but no error reported?"),
);
NotConstEvaluatable::Error(guar)
}),
)))
}
Err(ErrorHandled::Linted) => {
let reported = infcx
.tcx

View File

@ -1,3 +1,5 @@
// check-pass
#![feature(generic_const_exprs)]
#![allow(incomplete_features)]
@ -21,11 +23,6 @@ fn foo<T, const N: usize>(_: T) -> <() as Foo<{ N + 1 }>>::Assoc
}
fn main() {
// FIXME(generic_const_exprs): We can't correctly infer `T` which requires
// evaluating `{ N + 1 }` which has substs containing an inference var
let mut _q = Default::default();
//~^ ERROR type annotations needed
_q = foo::<_, 2>(_q);
//~^ ERROR type annotations needed
}

View File

@ -1,38 +0,0 @@
error[E0282]: type annotations needed
--> $DIR/const_eval_resolve_canonical.rs:26:9
|
LL | let mut _q = Default::default();
| ^^^^^^
|
help: consider giving `_q` an explicit type
|
LL | let mut _q: _ = Default::default();
| +++
error[E0283]: type annotations needed
--> $DIR/const_eval_resolve_canonical.rs:29:10
|
LL | _q = foo::<_, 2>(_q);
| ^^^^^^^^^^^ cannot infer the value of the constant `{ N + 1 }`
|
note: multiple `impl`s satisfying `(): Foo<{ N + 1 }>` found
--> $DIR/const_eval_resolve_canonical.rs:8:1
|
LL | impl Foo<0> for () {
| ^^^^^^^^^^^^^^^^^^
...
LL | impl Foo<3> for () {
| ^^^^^^^^^^^^^^^^^^
note: required by a bound in `foo`
--> $DIR/const_eval_resolve_canonical.rs:18:9
|
LL | fn foo<T, const N: usize>(_: T) -> <() as Foo<{ N + 1 }>>::Assoc
| --- required by a bound in this
LL | where
LL | (): Foo<{ N + 1 }>,
| ^^^^^^^^^^^^^^ required by this bound in `foo`
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0282, E0283.
For more information about an error, try `rustc --explain E0282`.