diff --git a/src/librustc_infer/infer/combine.rs b/src/librustc_infer/infer/combine.rs index 4ef4ed47cb11a..4bc1c84cd851f 100644 --- a/src/librustc_infer/infer/combine.rs +++ b/src/librustc_infer/infer/combine.rs @@ -343,7 +343,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { for_vid: ty::TyVid, dir: RelationDir, ) -> RelateResult<'tcx, Generalization<'tcx>> { - debug!("generalize(ty={:?}, for_vid={:?}, dir={:?}", ty, for_vid, dir); + debug!("generalize(ty={:?}, for_vid={:?}, dir={:?})", ty, for_vid, dir); // Determine the ambient variance within which `ty` appears. // The surrounding equation is: // @@ -649,27 +649,47 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { assert_eq!(c, c2); // we are abusing TypeRelation here; both LHS and RHS ought to be == + debug!("generalize: consts c={:?}", c); match c.val { ty::ConstKind::Infer(InferConst::Var(vid)) => { - let mut inner = self.infcx.inner.borrow_mut(); - let variable_table = &mut inner.const_unification_table(); - let var_value = variable_table.probe_value(vid); + let var_value = + self.infcx.inner.borrow_mut().const_unification_table().probe_value(vid); match var_value.val { ConstVariableValue::Known { value: u } => self.relate(&u, &u), ConstVariableValue::Unknown { universe } => { if self.for_universe.can_name(universe) { Ok(c) } else { - let new_var_id = variable_table.new_key(ConstVarValue { - origin: var_value.origin, - val: ConstVariableValue::Unknown { universe: self.for_universe }, - }); + let new_var_id = + self.infcx.inner.borrow_mut().const_unification_table().new_key( + ConstVarValue { + origin: var_value.origin, + val: ConstVariableValue::Unknown { + universe: self.for_universe, + }, + }, + ); Ok(self.tcx().mk_const_var(new_var_id, c.ty)) } } } } - ty::ConstKind::Unevaluated(..) if self.tcx().lazy_normalization() => Ok(c), + ty::ConstKind::Unevaluated(did, substs, promoted) + if self.tcx().lazy_normalization() => + { + // We have to generalize inference variables used in the generic substitutions, + // as unevaluated consts may otherwise contain invalid inference variables. + let new_substs = + self.relate_with_variance(ty::Variance::Invariant, &substs, &substs)?; + if new_substs != substs { + Ok(self.tcx().mk_const(ty::Const { + ty: c.ty, + val: ty::ConstKind::Unevaluated(did, new_substs, promoted), + })) + } else { + Ok(c) + } + } _ => relate::super_relate_consts(self, c, c), } } diff --git a/src/librustc_middle/ty/structural_impls.rs b/src/librustc_middle/ty/structural_impls.rs index f736037b5c15a..5e4eed71791bc 100644 --- a/src/librustc_middle/ty/structural_impls.rs +++ b/src/librustc_middle/ty/structural_impls.rs @@ -885,6 +885,7 @@ impl<'tcx> TypeFoldable<'tcx> for interpret::GlobalId<'tcx> { impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { fn super_fold_with>(&self, folder: &mut F) -> Self { + debug!("Ty::super_fold_with({:?})", self); let kind = match self.kind { ty::RawPtr(tm) => ty::RawPtr(tm.fold_with(folder)), ty::Array(typ, sz) => ty::Array(typ.fold_with(folder), sz.fold_with(folder)), @@ -1040,6 +1041,7 @@ impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Const<'tcx> { fn super_fold_with>(&self, folder: &mut F) -> Self { + debug!("Const::super_fold_with({:?})", self); let ty = self.ty.fold_with(folder); let val = self.val.fold_with(folder); if ty != self.ty || val != self.val { diff --git a/src/test/ui/const-generics/issues/issue-69654-run-pass.rs b/src/test/ui/const-generics/issues/issue-69654-run-pass.rs new file mode 100644 index 0000000000000..7ca87db149973 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-69654-run-pass.rs @@ -0,0 +1,19 @@ +#![feature(const_generics)] +#![allow(incomplete_features, unused_braces)] + +trait Bar {} +impl Bar for [u8; {7}] {} + +struct Foo {} +impl Foo +where + [u8; N]: Bar<[(); N]>, +{ + fn foo() {} +} + +fn main() { + Foo::foo(); + //~^ ERROR no function or associated item named `foo` + // FIXME(const_generics): The above should not error +} diff --git a/src/test/ui/const-generics/issues/issue-69654-run-pass.stderr b/src/test/ui/const-generics/issues/issue-69654-run-pass.stderr new file mode 100644 index 0000000000000..a95cc0f2a1c32 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-69654-run-pass.stderr @@ -0,0 +1,15 @@ +error[E0599]: no function or associated item named `foo` found for struct `Foo<{_: usize}>` in the current scope + --> $DIR/issue-69654-run-pass.rs:16:10 + | +LL | struct Foo {} + | -------------------------- function or associated item `foo` not found for this +... +LL | Foo::foo(); + | ^^^ function or associated item not found in `Foo<{_: usize}>` + | + = note: the method `foo` exists but the following trait bounds were not satisfied: + `[u8; _]: Bar<[(); _]>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/const-generics/issues/issue-69654.rs b/src/test/ui/const-generics/issues/issue-69654.rs new file mode 100644 index 0000000000000..a941de601c14d --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-69654.rs @@ -0,0 +1,19 @@ +#![feature(const_generics)] +#![allow(incomplete_features)] + +trait Bar {} +impl Bar for [u8; T] {} +//~^ ERROR expected value, found type parameter `T` + +struct Foo {} +impl Foo +where + [u8; N]: Bar<[(); N]>, +{ + fn foo() {} +} + +fn main() { + Foo::foo(); + //~^ ERROR no function or associated item named `foo` +} diff --git a/src/test/ui/const-generics/issues/issue-69654.stderr b/src/test/ui/const-generics/issues/issue-69654.stderr new file mode 100644 index 0000000000000..69cd0806fcd42 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-69654.stderr @@ -0,0 +1,22 @@ +error[E0423]: expected value, found type parameter `T` + --> $DIR/issue-69654.rs:5:25 + | +LL | impl Bar for [u8; T] {} + | ^ not a value + +error[E0599]: no function or associated item named `foo` found for struct `Foo<{_: usize}>` in the current scope + --> $DIR/issue-69654.rs:17:10 + | +LL | struct Foo {} + | -------------------------- function or associated item `foo` not found for this +... +LL | Foo::foo(); + | ^^^ function or associated item not found in `Foo<{_: usize}>` + | + = note: the method `foo` exists but the following trait bounds were not satisfied: + `[u8; _]: Bar<[(); _]>` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0423, E0599. +For more information about an error, try `rustc --explain E0423`. diff --git a/src/test/ui/const-generics/unused-substs/unused-substs-1.rs b/src/test/ui/const-generics/unused-substs/unused-substs-1.rs new file mode 100644 index 0000000000000..edda245c0ad4f --- /dev/null +++ b/src/test/ui/const-generics/unused-substs/unused-substs-1.rs @@ -0,0 +1,12 @@ +#![feature(const_generics)] //~ WARN the feature `const_generics` is incomplete +trait Bar {} +impl Bar for A<{ 6 + 1 }> {} + +struct A +where + A: Bar; + +fn main() { + let _ = A; + //~^ ERROR mismatched types +} diff --git a/src/test/ui/const-generics/unused-substs/unused-substs-2.rs b/src/test/ui/const-generics/unused-substs/unused-substs-2.rs new file mode 100644 index 0000000000000..8ed1fd1257b10 --- /dev/null +++ b/src/test/ui/const-generics/unused-substs/unused-substs-2.rs @@ -0,0 +1,26 @@ +#![feature(const_generics)] //~ WARN the feature `const_generics` is incomplete + +// The goal is is to get an unevaluated const `ct` with a `Ty::Infer(TyVar(_#1t)` subst. +// +// If we are then able to infer `ty::Infer(TyVar(_#1t) := Ty` we introduced an +// artificial inference cycle. +struct Foo; + +trait Bind { + fn bind() -> (T, Self); +} + +// `N` has to be `ConstKind::Unevaluated`. +impl Bind for Foo<{ 6 + 1 }> { + fn bind() -> (T, Self) { + (panic!(), Foo) + } +} + +fn main() { + let (mut t, foo) = Foo::bind(); + // `t` is `ty::Infer(TyVar(_#1t))` + // `foo` contains `ty::Infer(TyVar(_#1t))` in its substs + t = foo; + //~^ ERROR mismatched types +} diff --git a/src/test/ui/const-generics/unused-substs/unused-substs-2.stderr b/src/test/ui/const-generics/unused-substs/unused-substs-2.stderr new file mode 100644 index 0000000000000..29a9e5050a767 --- /dev/null +++ b/src/test/ui/const-generics/unused-substs/unused-substs-2.stderr @@ -0,0 +1,18 @@ +warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/unused-substs-2.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44580 for more information + +error[E0308]: mismatched types + --> $DIR/unused-substs-2.rs:24:9 + | +LL | t = foo; + | ^^^ cyclic type of infinite size + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/unused-substs/unused-substs-3.rs b/src/test/ui/const-generics/unused-substs/unused-substs-3.rs new file mode 100644 index 0000000000000..188698d41ab17 --- /dev/null +++ b/src/test/ui/const-generics/unused-substs/unused-substs-3.rs @@ -0,0 +1,18 @@ + +#![feature(const_generics)] //~ WARN the feature `const_generics` is incomplete + +// The goal is is to get an unevaluated const `ct` with a `Ty::Infer(TyVar(_#1t)` subst. +// +// If we are then able to infer `ty::Infer(TyVar(_#1t) := Ty` we introduced an +// artificial inference cycle. +fn bind() -> (T, [u8; 6 + 1]) { + todo!() +} + +fn main() { + let (mut t, foo) = bind(); + // `t` is `ty::Infer(TyVar(_#1t))` + // `foo` contains `ty::Infer(TyVar(_#1t))` in its substs + t = foo; + //~^ ERROR mismatched types +} diff --git a/src/test/ui/const-generics/unused-substs/unused-substs-3.stderr b/src/test/ui/const-generics/unused-substs/unused-substs-3.stderr new file mode 100644 index 0000000000000..88f50ce9aacc2 --- /dev/null +++ b/src/test/ui/const-generics/unused-substs/unused-substs-3.stderr @@ -0,0 +1,21 @@ +warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/unused-substs-3.rs:2:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44580 for more information + +error[E0308]: mismatched types + --> $DIR/unused-substs-3.rs:16:9 + | +LL | t = foo; + | ^^^ + | | + | cyclic type of infinite size + | help: try using a conversion method: `foo.to_vec()` + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0308`.