Rollup merge of #105292 - JulianKnodt:no_eager_commit, r=BoxyUwU

Change a commit_if_ok call to probe

Removes an over-eager `commit_if_ok` which makes inference worse.

I'm not entirely sure whether it's ok to remove the check that types are the same, because casting seems to cause equality checks with incorrect types?

Fixes #105037

r? ```@BoxyUwU```
This commit is contained in:
fee1-dead 2023-01-09 23:35:26 +08:00 committed by GitHub
commit b7587f1867
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 221 additions and 16 deletions

View file

@ -168,24 +168,27 @@ fn satisfied_from_param_env<'tcx>(
param_env: ty::ParamEnv<'tcx>,
infcx: &'a InferCtxt<'tcx>,
single_match: Option<Result<ty::Const<'tcx>, ()>>,
}
impl<'a, 'tcx> TypeVisitor<'tcx> for Visitor<'a, 'tcx> {
type BreakTy = ();
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
debug!("is_const_evaluatable: candidate={:?}", c);
if let Ok(()) = self.infcx.commit_if_ok(|_| {
if self.infcx.probe(|_| {
let ocx = ObligationCtxt::new_in_snapshot(self.infcx);
if let Ok(()) = ocx.eq(&ObligationCause::dummy(), self.param_env, c.ty(), self.ct.ty())
&& let Ok(()) = ocx.eq(&ObligationCause::dummy(), self.param_env, c, self.ct)
ocx.eq(&ObligationCause::dummy(), self.param_env, c.ty(), self.ct.ty()).is_ok()
&& ocx.eq(&ObligationCause::dummy(), self.param_env, c, self.ct).is_ok()
&& ocx.select_all_or_error().is_empty()
{
Ok(())
} else {
Err(())
}
}) {
ControlFlow::BREAK
} else if let ty::ConstKind::Expr(e) = c.kind() {
self.single_match = match self.single_match {
None => Some(Ok(c)),
Some(Ok(o)) if o == c => Some(Ok(c)),
Some(_) => Some(Err(())),
};
}
if let ty::ConstKind::Expr(e) = c.kind() {
e.visit_with(self)
} else {
// FIXME(generic_const_exprs): This doesn't recurse into `<T as Trait<U>>::ASSOC`'s substs.
@ -200,22 +203,29 @@ fn satisfied_from_param_env<'tcx>(
}
}
let mut single_match: Option<Result<ty::Const<'tcx>, ()>> = None;
for pred in param_env.caller_bounds() {
match pred.kind().skip_binder() {
ty::PredicateKind::ConstEvaluatable(ce) => {
let b_ct = tcx.expand_abstract_consts(ce);
let mut v = Visitor { ct, infcx, param_env };
let result = b_ct.visit_with(&mut v);
let mut v = Visitor { ct, infcx, param_env, single_match };
let _ = b_ct.visit_with(&mut v);
if let ControlFlow::Break(()) = result {
debug!("is_const_evaluatable: yes");
return true;
}
single_match = v.single_match;
}
_ => {} // don't care
}
}
if let Some(Ok(c)) = single_match {
let ocx = ObligationCtxt::new(infcx);
assert!(ocx.eq(&ObligationCause::dummy(), param_env, c.ty(), ct.ty()).is_ok());
assert!(ocx.eq(&ObligationCause::dummy(), param_env, c, ct).is_ok());
assert!(ocx.select_all_or_error().is_empty());
return true;
}
debug!("is_const_evaluatable: no");
false
}

View file

@ -0,0 +1,20 @@
#![feature(generic_const_exprs)]
#![allow(incomplete_features)]
fn foo<const N: usize, const M: usize>() -> [(); N+2]
where
[(); N + 1]:,
[(); M + 1]:,
{
bar()
//~^ ERROR: unconstrained
}
fn bar<const N: usize>() -> [(); N]
where
[(); N + 1]:,
{
[(); N]
}
fn main() {}

View file

@ -0,0 +1,18 @@
error: unconstrained generic constant
--> $DIR/ensure_is_evaluatable.rs:9:5
|
LL | bar()
| ^^^
|
= help: try adding a `where` bound using this expression: `where [(); N + 1]:`
note: required by a bound in `bar`
--> $DIR/ensure_is_evaluatable.rs:15:10
|
LL | fn bar<const N: usize>() -> [(); N]
| --- required by a bound in this
LL | where
LL | [(); N + 1]:,
| ^^^^^ required by this bound in `bar`
error: aborting due to previous error

View file

@ -0,0 +1,23 @@
#![feature(generic_const_exprs)]
#![allow(incomplete_features)]
const fn both(_: usize, b: usize) -> usize {
b
}
fn foo<const N: usize, const M: usize>() -> [(); N + 2]
where
[(); both(N + 1, M + 1)]:,
{
bar()
//~^ ERROR: unconstrained generic constant
}
fn bar<const N: usize>() -> [(); N]
where
[(); N + 1]:,
{
[(); N]
}
fn main() {}

View file

@ -0,0 +1,18 @@
error: unconstrained generic constant
--> $DIR/fn_with_two_const_inputs.rs:12:5
|
LL | bar()
| ^^^
|
= help: try adding a `where` bound using this expression: `where [(); N + 1]:`
note: required by a bound in `bar`
--> $DIR/fn_with_two_const_inputs.rs:18:10
|
LL | fn bar<const N: usize>() -> [(); N]
| --- required by a bound in this
LL | where
LL | [(); N + 1]:,
| ^^^^^ required by this bound in `bar`
error: aborting due to previous error

View file

@ -0,0 +1,22 @@
// check-pass
#![feature(generic_const_exprs)]
#![allow(incomplete_features)]
const fn both(_: usize, b: usize) -> usize {
b
}
fn foo<const N: usize>()
where
[(); both(N + 1, N + 1)]:,
{
bar::<N>();
}
fn bar<const N: usize>()
where
[(); N + 1]:,
{
}
fn main() {}

View file

@ -0,0 +1,35 @@
// run-pass
#![feature(generic_const_exprs)]
#![allow(incomplete_features)]
#![allow(dead_code)]
trait Table<const D: usize>: Sync {
const COLUMNS: usize;
}
struct Table1<const D: usize>;
impl<const D: usize> Table<D> for Table1<D> {
const COLUMNS: usize = 123;
}
struct Table2<const D: usize>;
impl<const D: usize> Table<D> for Table2<D> {
const COLUMNS: usize = 456;
}
fn process_table<T: Table<D>, const D: usize>(_table: T)
where
[(); T::COLUMNS]:,
{
}
fn process_all_tables<const D: usize>()
where
[(); Table2::<D>::COLUMNS]:,
[(); Table1::<D>::COLUMNS]:,
{
process_table(Table1::<D>);
process_table(Table2::<D>);
}
fn main() {}

View file

@ -0,0 +1,19 @@
// check-pass
#![feature(generic_const_exprs)]
#![allow(incomplete_features)]
fn foo<const N: usize>()
where
[(); N + 1]:,
[(); N + 1]:,
{
bar::<N>();
}
fn bar<const N: usize>()
where
[(); N + 1]:,
{
}
fn main() {}

View file

@ -0,0 +1,18 @@
#![feature(generic_const_exprs)]
#![allow(incomplete_features)]
fn foo<const N: usize>()
where
[(); N + 1 + 1]:,
{
bar();
//~^ ERROR: type annotations
}
fn bar<const N: usize>()
where
[(); N + 1]:,
{
}
fn main() {}

View file

@ -0,0 +1,22 @@
error[E0284]: type annotations needed
--> $DIR/unify_with_nested_expr.rs:8:5
|
LL | bar();
| ^^^ cannot infer the value of the const parameter `N` declared on the function `bar`
|
note: required by a bound in `bar`
--> $DIR/unify_with_nested_expr.rs:14:10
|
LL | fn bar<const N: usize>()
| --- required by a bound in this
LL | where
LL | [(); N + 1]:,
| ^^^^^ required by this bound in `bar`
help: consider specifying the generic argument
|
LL | bar::<N>();
| +++++
error: aborting due to previous error
For more information about this error, try `rustc --explain E0284`.