Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 1f2a26e

Browse files
authoredDec 4, 2021
Rollup merge of #90023 - b-naber:postpone_const_eval_infer_vars, r=nikomatsakis
Postpone the evaluation of constant expressions that depend on inference variables Previously `delay_span_bug` calls were triggered once an inference variable was included in the substs of a constant that was to be evaluated. Some of these would merely have resulted in trait candidates being rejected, hence no real error was ever encountered, but the triggering of the `delay_span_bug` then caused an ICE in later stages of the compiler due to no error ever occurring. We now postpone the evaluation of these constants, so any trait obligation fulfillment will simply stall on this constant and the existing type inference machinery of the compiler handles any type errors if present. Fixes #89320 Fixes #89146 Fixes #87964 Fixes #87470 Fixes #83288 Fixes #83249 Fixes #90654 I want to thank `@BoxyUwU` for cooperating on this and for providing some help. r? `@lcnr` maybe?
2 parents 29fe57d + 37ed2db commit 1f2a26e

File tree

11 files changed

+324
-33
lines changed

11 files changed

+324
-33
lines changed
 

‎compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs

+66-26
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::infer::type_variable::TypeVariableOriginKind;
22
use crate::infer::InferCtxt;
3+
use crate::rustc_middle::ty::TypeFoldable;
34
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
45
use rustc_hir as hir;
56
use rustc_hir::def::{DefKind, Namespace};
@@ -400,36 +401,75 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
400401
}
401402
}
402403
GenericArgKind::Const(ct) => {
403-
if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.val {
404-
let origin =
405-
self.inner.borrow_mut().const_unification_table().probe_value(vid).origin;
406-
if let ConstVariableOriginKind::ConstParameterDefinition(name, def_id) =
407-
origin.kind
408-
{
409-
return InferenceDiagnosticsData {
410-
name: name.to_string(),
404+
match ct.val {
405+
ty::ConstKind::Infer(InferConst::Var(vid)) => {
406+
let origin = self
407+
.inner
408+
.borrow_mut()
409+
.const_unification_table()
410+
.probe_value(vid)
411+
.origin;
412+
if let ConstVariableOriginKind::ConstParameterDefinition(name, def_id) =
413+
origin.kind
414+
{
415+
return InferenceDiagnosticsData {
416+
name: name.to_string(),
417+
span: Some(origin.span),
418+
kind: UnderspecifiedArgKind::Const { is_parameter: true },
419+
parent: InferenceDiagnosticsParentData::for_def_id(
420+
self.tcx, def_id,
421+
),
422+
};
423+
}
424+
425+
debug_assert!(!origin.span.is_dummy());
426+
let mut s = String::new();
427+
let mut printer =
428+
ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::ValueNS);
429+
if let Some(highlight) = highlight {
430+
printer.region_highlight_mode = highlight;
431+
}
432+
let _ = ct.print(printer);
433+
InferenceDiagnosticsData {
434+
name: s,
411435
span: Some(origin.span),
412-
kind: UnderspecifiedArgKind::Const { is_parameter: true },
413-
parent: InferenceDiagnosticsParentData::for_def_id(self.tcx, def_id),
414-
};
436+
kind: UnderspecifiedArgKind::Const { is_parameter: false },
437+
parent: None,
438+
}
415439
}
416-
417-
debug_assert!(!origin.span.is_dummy());
418-
let mut s = String::new();
419-
let mut printer =
420-
ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::ValueNS);
421-
if let Some(highlight) = highlight {
422-
printer.region_highlight_mode = highlight;
440+
ty::ConstKind::Unevaluated(ty::Unevaluated {
441+
substs_: Some(substs), ..
442+
}) => {
443+
assert!(substs.has_infer_types_or_consts());
444+
445+
// FIXME: We only use the first inference variable we encounter in
446+
// `substs` here, this gives insufficiently informative diagnostics
447+
// in case there are multiple inference variables
448+
for s in substs.iter() {
449+
match s.unpack() {
450+
GenericArgKind::Type(t) => match t.kind() {
451+
ty::Infer(_) => {
452+
return self.extract_inference_diagnostics_data(s, None);
453+
}
454+
_ => {}
455+
},
456+
GenericArgKind::Const(c) => match c.val {
457+
ty::ConstKind::Infer(InferConst::Var(_)) => {
458+
return self.extract_inference_diagnostics_data(s, None);
459+
}
460+
_ => {}
461+
},
462+
_ => {}
463+
}
464+
}
465+
bug!(
466+
"expected an inference variable in substs of unevaluated const {:?}",
467+
ct
468+
);
423469
}
424-
let _ = ct.print(printer);
425-
InferenceDiagnosticsData {
426-
name: s,
427-
span: Some(origin.span),
428-
kind: UnderspecifiedArgKind::Const { is_parameter: false },
429-
parent: None,
470+
_ => {
471+
bug!("unexpect const: {:?}", ct);
430472
}
431-
} else {
432-
bug!("unexpect const: {:?}", ct);
433473
}
434474
}
435475
GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"),

‎compiler/rustc_infer/src/infer/mod.rs

+19-4
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
2121
use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues};
2222
use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
2323
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
24+
use rustc_middle::mir::interpret::ErrorHandled;
2425
use rustc_middle::mir::interpret::EvalToConstValueResult;
2526
use rustc_middle::traits::select;
2627
use rustc_middle::ty::error::{ExpectedFound, TypeError};
@@ -1584,13 +1585,27 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
15841585
unevaluated: ty::Unevaluated<'tcx>,
15851586
span: Option<Span>,
15861587
) -> EvalToConstValueResult<'tcx> {
1587-
let mut original_values = OriginalQueryValues::default();
1588-
let canonical = self.canonicalize_query((param_env, unevaluated), &mut original_values);
1588+
let mut substs = unevaluated.substs(self.tcx);
1589+
substs = self.resolve_vars_if_possible(substs);
1590+
1591+
// Postpone the evaluation of constants whose substs depend on inference
1592+
// variables
1593+
if substs.has_infer_types_or_consts() {
1594+
return Err(ErrorHandled::TooGeneric);
1595+
}
1596+
1597+
let param_env_erased = self.tcx.erase_regions(param_env);
1598+
let substs_erased = self.tcx.erase_regions(substs);
1599+
1600+
let unevaluated = ty::Unevaluated {
1601+
def: unevaluated.def,
1602+
substs_: Some(substs_erased),
1603+
promoted: unevaluated.promoted,
1604+
};
15891605

1590-
let (param_env, unevaluated) = canonical.value;
15911606
// The return value is the evaluated value which doesn't contain any reference to inference
15921607
// variables, thus we don't need to substitute back the original values.
1593-
self.tcx.const_eval_resolve(param_env, unevaluated, span)
1608+
self.tcx.const_eval_resolve(param_env_erased, unevaluated, span)
15941609
}
15951610

15961611
/// If `typ` is a type variable of some kind, resolve it one level

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

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// run-pass
21
#![feature(generic_const_exprs)]
32
#![allow(incomplete_features)]
43

@@ -22,8 +21,11 @@ where
2221
}
2322

2423
fn main() {
25-
// Test that we can correctly infer `T` which requires evaluating
26-
// `{ N + 1 }` which has substs containing an inference var
24+
// FIXME(generic_const_exprs): We can't correctly infer `T` which requires
25+
// evaluating `{ N + 1 }` which has substs containing an inference var
2726
let mut _q = Default::default();
27+
//~^ ERROR type annotations needed
28+
2829
_q = foo::<_, 2>(_q);
30+
//~^ ERROR type annotations needed
2931
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
error[E0282]: type annotations needed
2+
--> $DIR/const_eval_resolve_canonical.rs:26:9
3+
|
4+
LL | let mut _q = Default::default();
5+
| ^^^^^^ consider giving `_q` a type
6+
7+
error[E0283]: type annotations needed
8+
--> $DIR/const_eval_resolve_canonical.rs:29:10
9+
|
10+
LL | _q = foo::<_, 2>(_q);
11+
| ^^^^^^^^^^^ cannot infer type
12+
|
13+
note: multiple `impl`s satisfying `(): Foo<{ N + 1 }>` found
14+
--> $DIR/const_eval_resolve_canonical.rs:8:1
15+
|
16+
LL | impl Foo<0> for () {
17+
| ^^^^^^^^^^^^^^^^^^
18+
...
19+
LL | impl Foo<3> for () {
20+
| ^^^^^^^^^^^^^^^^^^
21+
note: required by a bound in `foo`
22+
--> $DIR/const_eval_resolve_canonical.rs:18:9
23+
|
24+
LL | fn foo<T, const N: usize>(_: T) -> <() as Foo<{ N + 1 }>>::Assoc
25+
| --- required by a bound in this
26+
LL | where
27+
LL | (): Foo<{ N + 1 }>,
28+
| ^^^^^^^^^^^^^^ required by this bound in `foo`
29+
30+
error: aborting due to 2 previous errors
31+
32+
Some errors have detailed explanations: E0282, E0283.
33+
For more information about an error, try `rustc --explain E0282`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#![allow(incomplete_features)]
2+
#![feature(generic_const_exprs)]
3+
4+
trait Foo {
5+
const N: usize;
6+
}
7+
8+
impl Foo for u8 {
9+
const N: usize = 1;
10+
}
11+
12+
fn foo<T: Foo>(_: [u8; T::N]) -> T {
13+
todo!()
14+
}
15+
16+
pub fn bar() {
17+
let _: u8 = foo([0; 1]);
18+
19+
let _ = foo([0; 1]);
20+
//~^ ERROR type annotations needed
21+
}
22+
23+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0282]: type annotations needed
2+
--> $DIR/issue-83249.rs:19:13
3+
|
4+
LL | let _ = foo([0; 1]);
5+
| - ^^^ cannot infer type for type parameter `T` declared on the function `foo`
6+
| |
7+
| consider giving this pattern a type
8+
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0282`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// build-pass
2+
3+
#![allow(incomplete_features)]
4+
#![feature(generic_const_exprs)]
5+
6+
use std::{marker::PhantomData, ops::Mul};
7+
8+
pub enum Nil {}
9+
pub struct Cons<T, L> {
10+
_phantom: PhantomData<(T, L)>,
11+
}
12+
13+
pub trait Indices<const N: usize> {
14+
const RANK: usize;
15+
const NUM_ELEMS: usize;
16+
}
17+
18+
impl<const N: usize> Indices<N> for Nil {
19+
const RANK: usize = 0;
20+
const NUM_ELEMS: usize = 1;
21+
}
22+
23+
impl<T, I: Indices<N>, const N: usize> Indices<N> for Cons<T, I> {
24+
const RANK: usize = I::RANK + 1;
25+
const NUM_ELEMS: usize = I::NUM_ELEMS * N;
26+
}
27+
28+
pub trait Concat<J> {
29+
type Output;
30+
}
31+
32+
impl<J> Concat<J> for Nil {
33+
type Output = J;
34+
}
35+
36+
impl<T, I, J> Concat<J> for Cons<T, I>
37+
where
38+
I: Concat<J>,
39+
{
40+
type Output = Cons<T, <I as Concat<J>>::Output>;
41+
}
42+
43+
pub struct Tensor<I: Indices<N>, const N: usize>
44+
where
45+
[u8; I::NUM_ELEMS]: Sized,
46+
{
47+
pub data: [u8; I::NUM_ELEMS],
48+
_phantom: PhantomData<I>,
49+
}
50+
51+
impl<I: Indices<N>, J: Indices<N>, const N: usize> Mul<Tensor<J, N>> for Tensor<I, N>
52+
where
53+
I: Concat<J>,
54+
<I as Concat<J>>::Output: Indices<N>,
55+
[u8; I::NUM_ELEMS]: Sized,
56+
[u8; J::NUM_ELEMS]: Sized,
57+
[u8; <I as Concat<J>>::Output::NUM_ELEMS]: Sized,
58+
{
59+
type Output = Tensor<<I as Concat<J>>::Output, N>;
60+
61+
fn mul(self, _rhs: Tensor<J, N>) -> Self::Output {
62+
Tensor {
63+
data: [0u8; <I as Concat<J>>::Output::NUM_ELEMS],
64+
_phantom: PhantomData,
65+
}
66+
}
67+
}
68+
69+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// build-pass
2+
3+
#![feature(generic_const_exprs)]
4+
#![allow(incomplete_features)]
5+
6+
pub trait TraitWithConst {
7+
const SOME_CONST: usize;
8+
}
9+
10+
pub trait OtherTrait: TraitWithConst {
11+
fn some_fn(self) -> [u8 ; <Self as TraitWithConst>::SOME_CONST];
12+
}
13+
14+
impl TraitWithConst for f32 {
15+
const SOME_CONST: usize = 32;
16+
}
17+
18+
impl OtherTrait for f32 {
19+
fn some_fn(self) -> [u8 ; <Self as TraitWithConst>::SOME_CONST] {
20+
[0; 32]
21+
}
22+
}
23+
24+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// build-pass
2+
3+
#![feature(generic_const_exprs)]
4+
#![allow(incomplete_features)]
5+
6+
pub trait Target {
7+
const LENGTH: usize;
8+
}
9+
10+
11+
pub struct Container<T: Target>
12+
where
13+
[(); T::LENGTH]: Sized,
14+
{
15+
_target: T,
16+
}
17+
18+
impl<T: Target> Container<T>
19+
where
20+
[(); T::LENGTH]: Sized,
21+
{
22+
pub fn start(
23+
_target: T,
24+
) -> Container<T> {
25+
Container { _target }
26+
}
27+
}
28+
29+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// build-pass
2+
3+
#![allow(incomplete_features)]
4+
#![feature(generic_const_exprs)]
5+
6+
pub trait Foo {
7+
const SIZE: usize;
8+
9+
fn to_bytes(&self) -> [u8; Self::SIZE];
10+
}
11+
12+
pub fn bar<G: Foo>(a: &G) -> u8
13+
where
14+
[(); G::SIZE]: Sized,
15+
{
16+
deeper_bar(a)
17+
}
18+
19+
fn deeper_bar<G: Foo>(a: &G) -> u8
20+
where
21+
[(); G::SIZE]: Sized,
22+
{
23+
a.to_bytes()[0]
24+
}
25+
26+
fn main() {}
There was a problem loading the remainder of the diff.

0 commit comments

Comments
 (0)
Failed to load comments.