Skip to content

Commit 32a3ed2

Browse files
committed
Auto merge of rust-lang#125671 - BoxyUwU:remove_const_ty_eq, r=compiler-errors
Do not equate `Const`'s ty in `super_combine_const` Fixes rust-lang#114456 In rust-lang#125451 we started relating the `Const`'s tys outside of a probe so it was no longer simply an assertion to catch bugs. This was done so that when we _do_ provide a wrongly typed const argument to an item if we wind up relating it with some other instantiation we'll have a `TypeError` we can bubble up and taint the resulting mir allowing const eval to skip evaluation. In this PR I instead change `ConstArgHasType` to correctly handle checking the types of const inference variables. Previously if we had something like `impl<const N: u32> Trait for [(); N]`, when using the impl we would instantiate it with infer vars and then check that `?x: u32` is of type `u32` and succeed. Then later we would infer `?x` to some `Const` of type `usize`. We now stall on `?x` in `ConstArgHasType` until it has a concrete value that we can determine the type of. This allows us to fail using the erroneous implementation of `Trait` which allows us to taint the mir. Long term we intend to remove the `ty` field on `Const` so we would have no way of accessing the `ty` of a const inference variable anyway and would have to do this. I did not fully update `ConstArgHasType` to avoid using the `ty` field as it's not entirely possible right now- we would need to lookup `ConstArgHasType` candidates in the env. --- As for _why_ I think we should do this, relating the types of const's is not necessary for soundness of the type system. Originally this check started off as a plain `==` in `super_relate_consts` and gradually has been growing in complexity as we support more complicated types. It was never actually required to ensure that const arguments are correctly typed for their parameters however. The way we currently check that a const argument has the correct type is a little convoluted and confusing (and will hopefully be less weird as time goes on). Every const argument has an anon const with its return type set to type of the const parameter it is an argument to. When type checking the anon const regular type checking rules require that the expression is the same type as the return type. This effectively ensure that no matter what every const argument _always_ has the correct type. An extra bit of complexity is that during `hir_ty_lowering` we do not represent everything as a `ConstKind::Unevaluated` corresponding to the anon const. For generic parameters i.e. `[(); N]` we simply represent them as `ConstKind::Param` as we do not want `ConstKind::Unevaluated` with generic substs on stable under min const generics. The anon const still gets type checked resulting in errors about type mismatches. Eventually we intend to not create anon consts for all const arguments (for example for `ConstKind::Param`) and instead check that the argument type is correct via `ConstArgHasType` obligations (these effectively also act as a check that the anon consts have the correctly set return type). What this all means is that the the only time we should ever have mismatched types when relating two `Const`s is if we have messed up our logic for ensuring that const arguments are of the correct type. Having this not be an assert is: - Confusing as it may incorrectly lead people to believe this is an important check that is actually required - Opens the possibility for bugs or behaviour reliant on this (unnecessary) check existing --- This PR makes two tests go from pass->ICE (`generic_const_exprs/ice-125520-layout-mismatch-mulwithoverflow.rs` and `tests/crashes/121858.rs`). This is caused by the fact that we evaluate anon consts even if their where clauses do not hold and is a pre-existing issue and only affects `generic_const_exprs`. I am comfortable exposing the brokenness of `generic_const_exprs` more with this PR This PR makes a test go from ICE->pass (`const-generics/issues/issue-105821.rs`). I have no idea why this PR affects that but I believe that ICE is an unrelated issue to do with the fact that under `generic_const_exprs`/`adt_const_params` we do not handle lifetimes in const parameter types correctly. This PR is likely just masking this bug. Note: this PR doesn't re-introduce the assertion that the two consts' tys are equal. I'm not really sure how I feel about this but tbh it has caused more ICEs than its found lately so 🤷‍♀️ r? `@oli-obk` `@compiler-errors`
2 parents caa187f + d5bd4e2 commit 32a3ed2

30 files changed

+206
-327
lines changed

compiler/rustc_infer/src/infer/relate/combine.rs

+1-8
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,10 @@ use super::glb::Glb;
2222
use super::lub::Lub;
2323
use super::type_relating::TypeRelating;
2424
use super::StructurallyRelateAliases;
25-
use crate::infer::{DefineOpaqueTypes, InferCtxt, InferOk, TypeTrace};
25+
use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace};
2626
use crate::traits::{Obligation, PredicateObligations};
2727
use rustc_middle::bug;
2828
use rustc_middle::infer::unify_key::EffectVarValue;
29-
use rustc_middle::traits::ObligationCause;
3029
use rustc_middle::ty::error::{ExpectedFound, TypeError};
3130
use rustc_middle::ty::relate::{RelateResult, TypeRelation};
3231
use rustc_middle::ty::{self, InferConst, Ty, TyCtxt, TypeVisitableExt, Upcast};
@@ -170,12 +169,6 @@ impl<'tcx> InferCtxt<'tcx> {
170169
let a = self.shallow_resolve_const(a);
171170
let b = self.shallow_resolve_const(b);
172171

173-
// It is always an error if the types of two constants that are related are not equal.
174-
let InferOk { value: (), obligations } = self
175-
.at(&ObligationCause::dummy_with_span(relation.span()), relation.param_env())
176-
.eq(DefineOpaqueTypes::No, a.ty(), b.ty())?;
177-
relation.register_obligations(obligations);
178-
179172
match (a.kind(), b.kind()) {
180173
(
181174
ty::ConstKind::Infer(InferConst::Var(a_vid)),

compiler/rustc_trait_selection/src/solve/mod.rs

+24-2
Original file line numberDiff line numberDiff line change
@@ -197,8 +197,30 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
197197
goal: Goal<'tcx, (ty::Const<'tcx>, Ty<'tcx>)>,
198198
) -> QueryResult<'tcx> {
199199
let (ct, ty) = goal.predicate;
200-
self.eq(goal.param_env, ct.ty(), ty)?;
201-
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
200+
201+
// FIXME(BoxyUwU): Really we should not be calling `ct.ty()` for any variant
202+
// other than `ConstKind::Value`. Unfortunately this would require looking in the
203+
// env for any `ConstArgHasType` assumptions for parameters and placeholders. I
204+
// have not yet gotten around to implementing this though.
205+
//
206+
// We do still stall on infer vars though as otherwise a goal like:
207+
// `ConstArgHasType(?x: usize, usize)` can succeed even though it might later
208+
// get unified with some const that is not of type `usize`.
209+
match ct.kind() {
210+
// FIXME: Ignore effect vars because canonicalization doesn't handle them correctly
211+
// and if we stall on the var then we wind up creating ambiguity errors in a probe
212+
// for this goal which contains an effect var. Which then ends up ICEing.
213+
ty::ConstKind::Infer(ty::InferConst::Var(_)) => {
214+
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
215+
}
216+
ty::ConstKind::Error(_) => {
217+
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
218+
}
219+
_ => {
220+
self.eq(goal.param_env, ct.ty(), ty)?;
221+
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
222+
}
223+
}
202224
}
203225
}
204226

compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs

+16
Original file line numberDiff line numberDiff line change
@@ -2685,6 +2685,22 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
26852685
.with_span_label(span, format!("cannot satisfy `{predicate}`"))
26862686
}
26872687
}
2688+
2689+
// Given some `ConstArgHasType(?x, usize)`, we should not emit an error such as
2690+
// "type annotations needed: cannot satisfy the constant `_` has type `usize`"
2691+
// Instead we should emit a normal error suggesting the user to turbofish the
2692+
// const parameter that is currently being inferred. Unfortunately we cannot
2693+
// nicely emit such an error so we delay an ICE incase nobody else reports it
2694+
// for us.
2695+
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
2696+
return self.tcx.sess.dcx().span_delayed_bug(
2697+
span,
2698+
format!(
2699+
"`ambiguous ConstArgHasType({:?}, {:?}) unaccompanied by inference error`",
2700+
ct, ty
2701+
),
2702+
);
2703+
}
26882704
_ => {
26892705
if let Some(e) = self.tainted_by_errors() {
26902706
return e;

compiler/rustc_trait_selection/src/traits/fulfill.rs

+31-10
Original file line numberDiff line numberDiff line change
@@ -429,16 +429,37 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
429429
// This is because this is not ever a useful obligation to report
430430
// as the cause of an overflow.
431431
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
432-
match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq(
433-
// Only really excercised by generic_const_exprs
434-
DefineOpaqueTypes::Yes,
435-
ct.ty(),
436-
ty,
437-
) {
438-
Ok(inf_ok) => ProcessResult::Changed(mk_pending(inf_ok.into_obligations())),
439-
Err(_) => ProcessResult::Error(FulfillmentErrorCode::Select(
440-
SelectionError::Unimplemented,
441-
)),
432+
// FIXME(BoxyUwU): Really we should not be calling `ct.ty()` for any variant
433+
// other than `ConstKind::Value`. Unfortunately this would require looking in the
434+
// env for any `ConstArgHasType` assumptions for parameters and placeholders. I
435+
// don't really want to implement this in the old solver so I haven't.
436+
//
437+
// We do still stall on infer vars though as otherwise a goal like:
438+
// `ConstArgHasType(?x: usize, usize)` can succeed even though it might later
439+
// get unified with some const that is not of type `usize`.
440+
let ct = self.selcx.infcx.shallow_resolve_const(ct);
441+
match ct.kind() {
442+
ty::ConstKind::Infer(ty::InferConst::Var(vid)) => {
443+
pending_obligation.stalled_on.clear();
444+
pending_obligation.stalled_on.extend([TyOrConstInferVar::Const(vid)]);
445+
ProcessResult::Unchanged
446+
}
447+
ty::ConstKind::Error(_) => return ProcessResult::Changed(vec![]),
448+
_ => {
449+
match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq(
450+
// Only really excercised by generic_const_exprs
451+
DefineOpaqueTypes::Yes,
452+
ct.ty(),
453+
ty,
454+
) {
455+
Ok(inf_ok) => {
456+
ProcessResult::Changed(mk_pending(inf_ok.into_obligations()))
457+
}
458+
Err(_) => ProcessResult::Error(FulfillmentErrorCode::Select(
459+
SelectionError::Unimplemented,
460+
)),
461+
}
462+
}
442463
}
443464
}
444465

compiler/rustc_trait_selection/src/traits/select/mod.rs

+18-1
Original file line numberDiff line numberDiff line change
@@ -995,10 +995,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
995995
}
996996
ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig),
997997
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
998+
// FIXME(BoxyUwU): Really we should not be calling `ct.ty()` for any variant
999+
// other than `ConstKind::Value`. Unfortunately this would require looking in the
1000+
// env for any `ConstArgHasType` assumptions for parameters and placeholders. I
1001+
// don't really want to implement this in the old solver so I haven't.
1002+
//
1003+
// We do still stall on infer vars though as otherwise a goal like:
1004+
// `ConstArgHasType(?x: usize, usize)` can succeed even though it might later
1005+
// get unified with some const that is not of type `usize`.
1006+
let ct = self.infcx.shallow_resolve_const(ct);
1007+
let ct_ty = match ct.kind() {
1008+
ty::ConstKind::Infer(ty::InferConst::Var(_)) => {
1009+
return Ok(EvaluatedToAmbig);
1010+
}
1011+
ty::ConstKind::Error(_) => return Ok(EvaluatedToOk),
1012+
_ => ct.ty(),
1013+
};
1014+
9981015
match self.infcx.at(&obligation.cause, obligation.param_env).eq(
9991016
// Only really excercised by generic_const_exprs
10001017
DefineOpaqueTypes::Yes,
1001-
ct.ty(),
1018+
ct_ty,
10021019
ty,
10031020
) {
10041021
Ok(inf_ok) => self.evaluate_predicates_recursively(
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
1+
//@ known-bug: #121858
12
#![feature(generic_const_exprs)]
2-
#![allow(incomplete_features)]
33

44
struct Outer<const A: i64, const B: usize>();
55
impl<const A: usize, const B: usize> Outer<A, B>
6-
//~^ ERROR: `A` is not of type `i64`
7-
//~| ERROR: mismatched types
86
where
97
[(); A + (B * 2)]:,
108
{
11-
fn o() {}
9+
fn o() -> Union {}
1210
}
1311

1412
fn main() {
1513
Outer::<1, 1>::o();
16-
//~^ ERROR: no function or associated item named `o` found
1714
}

tests/crashes/122638.rs

-12
This file was deleted.

tests/crashes/123141-2.rs

-23
This file was deleted.

tests/crashes/123141.rs

+14-13
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
11
//@ known-bug: #123141
2-
trait ConstChunksExactTrait<T> {
3-
fn const_chunks_exact<const N: usize>(&self) -> ConstChunksExact<'_, T, { N }>;
2+
3+
trait Trait {
4+
fn next(self) -> Self::Item;
5+
type Item;
46
}
57

6-
impl<T> ConstChunksExactTrait<T> for [T] {}
8+
struct Foo<T: ?Sized>(T);
79

8-
struct ConstChunksExact<'a, T: 'a, const N: usize> {}
10+
impl<T: ?Sized, U> Trait for Foo<U> {
11+
type Item = Foo<T>;
12+
fn next(self) -> Self::Item {
13+
loop {}
14+
}
15+
}
916

10-
impl<'a, T, const N: usize> Iterator for ConstChunksExact<'a, T, { rem }> {
11-
type Item = &'a [T; N];
17+
fn opaque() -> impl Trait {
18+
Foo::<_>(10_u32)
1219
}
1320

1421
fn main() {
15-
let slice = &[1i32, 2, 3, 4, 5, 6, 7, 7, 9, 1i32];
16-
17-
let mut iter = [[1, 2, 3], [4, 5, 6], [7, 8, 9]].iter();
18-
19-
for a in slice.const_chunks_exact::<3>() {
20-
assert_eq!(a, iter.next().unwrap());
21-
}
22+
opaque().next();
2223
}

tests/ui/coherence/negative-coherence/generic_const_type_mismatch.rs

+1
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@ impl<const N: u8> Trait for [(); N] {}
88
//~^ ERROR: mismatched types
99
impl<const N: i8> Trait for [(); N] {}
1010
//~^ ERROR: mismatched types
11+
//~| ERROR: conflicting implementations of trait `Trait`
1112

1213
fn main() {}

tests/ui/coherence/negative-coherence/generic_const_type_mismatch.stderr

+12-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
error[E0119]: conflicting implementations of trait `Trait` for type `[(); _]`
2+
--> $DIR/generic_const_type_mismatch.rs:9:1
3+
|
4+
LL | impl<const N: u8> Trait for [(); N] {}
5+
| ----------------------------------- first implementation here
6+
LL |
7+
LL | impl<const N: i8> Trait for [(); N] {}
8+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `[(); _]`
9+
110
error[E0308]: mismatched types
211
--> $DIR/generic_const_type_mismatch.rs:7:34
312
|
@@ -10,6 +19,7 @@ error[E0308]: mismatched types
1019
LL | impl<const N: i8> Trait for [(); N] {}
1120
| ^ expected `usize`, found `i8`
1221

13-
error: aborting due to 2 previous errors
22+
error: aborting due to 3 previous errors
1423

15-
For more information about this error, try `rustc --explain E0308`.
24+
Some errors have detailed explanations: E0119, E0308.
25+
For more information about an error, try `rustc --explain E0119`.

tests/crashes/114456.rs renamed to tests/ui/const-generics/adt_const_params/alias_const_param_ty-1.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
//@ known-bug: #114456
1+
//@ check-pass
22
#![feature(adt_const_params, lazy_type_alias)]
3+
//~^ WARN: the feature `adt_const_params` is incomplete
4+
//~| WARN: the feature `lazy_type_alias` is incomplete
35

46
pub type Matrix = [usize; 1];
57
const EMPTY_MATRIX: Matrix = [0; 1];
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/alias_const_param_ty-1.rs:2:12
3+
|
4+
LL | #![feature(adt_const_params, lazy_type_alias)]
5+
| ^^^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information
8+
= note: `#[warn(incomplete_features)]` on by default
9+
10+
warning: the feature `lazy_type_alias` is incomplete and may not be safe to use and/or cause compiler crashes
11+
--> $DIR/alias_const_param_ty-1.rs:2:30
12+
|
13+
LL | #![feature(adt_const_params, lazy_type_alias)]
14+
| ^^^^^^^^^^^^^^^
15+
|
16+
= note: see issue #112792 <https://github.com/rust-lang/rust/issues/112792> for more information
17+
18+
warning: 2 warnings emitted
19+

tests/crashes/114456-2.rs renamed to tests/ui/const-generics/adt_const_params/alias_const_param_ty-2.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
//@ known-bug: #114456
1+
//@ check-pass
22
#![feature(adt_const_params)]
3+
//~^ WARN: the feature `adt_const_params` is incomplete
34

45
const EMPTY_MATRIX: <Type as Trait>::Matrix = [0; 1];
56

@@ -12,8 +13,12 @@ impl Walk<EMPTY_MATRIX> {
1213
}
1314

1415
pub enum Type {}
15-
pub trait Trait { type Matrix; }
16-
impl Trait for Type { type Matrix = [usize; 1]; }
16+
pub trait Trait {
17+
type Matrix;
18+
}
19+
impl Trait for Type {
20+
type Matrix = [usize; 1];
21+
}
1722

1823
fn main() {
1924
let _ = Walk::new();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/alias_const_param_ty-2.rs:2:12
3+
|
4+
LL | #![feature(adt_const_params)]
5+
| ^^^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information
8+
= note: `#[warn(incomplete_features)]` on by default
9+
10+
warning: 1 warning emitted
11+

tests/ui/const-generics/bad-subst-const-kind.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,7 @@ impl<const N: u64> Q for [u8; N] {
1010
const ASSOC: usize = 1;
1111
}
1212

13-
pub fn test() -> [u8; <[u8; 13] as Q>::ASSOC] { todo!() }
14-
//~^ ERROR: `[u8; 13]: Q` is not satisfied
13+
pub fn test() -> [u8; <[u8; 13] as Q>::ASSOC] {
14+
//~^ ERROR: the constant `13` is not of type `u64`
15+
todo!()
16+
}
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
1-
error[E0277]: the trait bound `[u8; 13]: Q` is not satisfied
1+
error: the constant `13` is not of type `u64`
22
--> $DIR/bad-subst-const-kind.rs:13:24
33
|
4-
LL | pub fn test() -> [u8; <[u8; 13] as Q>::ASSOC] { todo!() }
5-
| ^^^^^^^^ the trait `Q` is not implemented for `[u8; 13]`
4+
LL | pub fn test() -> [u8; <[u8; 13] as Q>::ASSOC] {
5+
| ^^^^^^^^ expected `u64`, found `usize`
66
|
7-
= help: the trait `Q` is implemented for `[u8; N]`
7+
note: required for `[u8; 13]` to implement `Q`
8+
--> $DIR/bad-subst-const-kind.rs:8:20
9+
|
10+
LL | impl<const N: u64> Q for [u8; N] {
11+
| ------------ ^ ^^^^^^^
12+
| |
13+
| unsatisfied trait bound introduced here
814

915
error[E0308]: mismatched types
1016
--> $DIR/bad-subst-const-kind.rs:8:31
@@ -14,5 +20,4 @@ LL | impl<const N: u64> Q for [u8; N] {
1420

1521
error: aborting due to 2 previous errors
1622

17-
Some errors have detailed explanations: E0277, E0308.
18-
For more information about an error, try `rustc --explain E0277`.
23+
For more information about this error, try `rustc --explain E0308`.

tests/ui/const-generics/defaults/doesnt_infer.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
struct Foo<const N: u32 = 2>;
44

55
impl<const N: u32> Foo<N> {
6-
fn foo() -> Self { loop {} }
6+
fn foo() -> Self {
7+
loop {}
8+
}
79
}
810

911
fn main() {

0 commit comments

Comments
 (0)