diff --git a/src/librustc_infer/infer/at.rs b/src/librustc_infer/infer/at.rs index 5c62a1298b97b..d44b8f554143c 100644 --- a/src/librustc_infer/infer/at.rs +++ b/src/librustc_infer/infer/at.rs @@ -186,7 +186,6 @@ impl<'a, 'tcx> At<'a, 'tcx> { impl<'a, 'tcx> Trace<'a, 'tcx> { /// Makes `a <: b` where `a` may or may not be expected (if /// `a_is_expected` is true, then `a` is expected). - /// Makes `expected <: actual`. pub fn sub(self, a: &T, b: &T) -> InferResult<'tcx, ()> where T: Relate<'tcx>, diff --git a/src/librustc_middle/ty/relate.rs b/src/librustc_middle/ty/relate.rs index f4f0b6c41b92f..4bfa46367d0c4 100644 --- a/src/librustc_middle/ty/relate.rs +++ b/src/librustc_middle/ty/relate.rs @@ -11,6 +11,7 @@ use crate::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_hir as ast; use rustc_hir::def_id::DefId; +use rustc_span::DUMMY_SP; use rustc_target::spec::abi; use std::iter; use std::rc::Rc; @@ -507,6 +508,7 @@ pub fn super_relate_consts>( a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>, ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { + debug!("{}.super_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b); let tcx = relation.tcx(); let eagerly_eval = |x: &'tcx ty::Const<'tcx>| { @@ -561,7 +563,7 @@ pub fn super_relate_consts>( } } - (a_val @ ConstValue::Slice { .. }, b_val @ ConstValue::Slice { .. }) => { + (ConstValue::Slice { .. }, ConstValue::Slice { .. }) => { let a_bytes = get_slice_bytes(&tcx, a_val); let b_bytes = get_slice_bytes(&tcx, b_val); if a_bytes == b_bytes { @@ -571,7 +573,37 @@ pub fn super_relate_consts>( } } - // FIXME(const_generics): handle `ConstValue::ByRef`. + (ConstValue::ByRef { .. }, ConstValue::ByRef { .. }) => { + match a.ty.kind { + ty::Array(..) | ty::Adt(..) | ty::Tuple(..) => { + let a_destructured = tcx.destructure_const(relation.param_env().and(a)); + let b_destructured = tcx.destructure_const(relation.param_env().and(b)); + + // Both the variant and each field have to be equal. + if a_destructured.variant == b_destructured.variant { + for (a_field, b_field) in + a_destructured.fields.iter().zip(b_destructured.fields.iter()) + { + relation.consts(a_field, b_field)?; + } + + Ok(a_val) + } else { + Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))) + } + } + // FIXME(const_generics): There are probably some `TyKind`s + // which should be handled here. + _ => { + tcx.sess.delay_span_bug( + DUMMY_SP, + &format!("unexpected consts: a: {:?}, b: {:?}", a, b), + ); + Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))) + } + } + } + _ => Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))), }; diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 5d1a1a164855d..e3b16eaaef2a2 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -107,6 +107,7 @@ fn coerce_mutbls<'tcx>( } } +/// Do not require any adjustments, i.e. coerce `x -> x`. fn identity(_: Ty<'_>) -> Vec> { vec![] } @@ -115,6 +116,7 @@ fn simple(kind: Adjust<'tcx>) -> impl FnOnce(Ty<'tcx>) -> Vec> move |target| vec![Adjustment { kind, target }] } +/// This always returns `Ok(...)`. fn success<'tcx>( adj: Vec>, target: Ty<'tcx>, @@ -133,6 +135,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } pub fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> { + debug!("unify(a: {:?}, b: {:?}, use_lub: {})", a, b, self.use_lub); self.commit_if_ok(|_| { if self.use_lub { self.at(&self.cause, self.fcx.param_env).lub(b, a) diff --git a/src/test/ui/const-generics/different_byref.rs b/src/test/ui/const-generics/different_byref.rs new file mode 100644 index 0000000000000..c52a5b8061dbf --- /dev/null +++ b/src/test/ui/const-generics/different_byref.rs @@ -0,0 +1,11 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +struct Const {} + +fn main() { + let mut x = Const::<{ [3] }> {}; + x = Const::<{ [4] }> {}; + //~^ ERROR mismatched types + +} diff --git a/src/test/ui/const-generics/different_byref.stderr b/src/test/ui/const-generics/different_byref.stderr new file mode 100644 index 0000000000000..9ea2aace89aae --- /dev/null +++ b/src/test/ui/const-generics/different_byref.stderr @@ -0,0 +1,20 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/different_byref.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + +error[E0308]: mismatched types + --> $DIR/different_byref.rs:8:9 + | +LL | x = Const::<{ [4] }> {}; + | ^^^^^^^^^^^^^^^^^^^ expected `3usize`, found `4usize` + | + = note: expected struct `Const<[3usize]>` + found struct `Const<[4usize]>` + +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/issues/issue-68615-adt.rs b/src/test/ui/const-generics/issues/issue-68615-adt.rs new file mode 100644 index 0000000000000..140bb28ec5a4f --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-68615-adt.rs @@ -0,0 +1,11 @@ +// check-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +struct Const {} +type MyConst = Const<{ [] }>; + +fn main() { + let _x = Const::<{ [] }> {}; + let _y = MyConst {}; +} diff --git a/src/test/ui/const-generics/issues/issue-68615-array.rs b/src/test/ui/const-generics/issues/issue-68615-array.rs new file mode 100644 index 0000000000000..c384bc1e36d02 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-68615-array.rs @@ -0,0 +1,11 @@ +// check-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +struct Foo {} + +type MyFoo = Foo<{ [] }>; + +fn main() { + let _ = Foo::<{ [] }> {}; +}