about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs2
-rw-r--r--compiler/rustc_infer/src/infer/canonical/mod.rs7
-rw-r--r--compiler/rustc_middle/src/infer/canonical.rs8
-rw-r--r--compiler/rustc_traits/src/chalk/mod.rs8
-rw-r--r--compiler/rustc_typeck/src/check/method/confirm.rs25
-rw-r--r--compiler/rustc_typeck/src/check/method/probe.rs26
-rw-r--r--src/test/ui/autoref-autoderef/deref-into-array.rs17
-rw-r--r--src/test/ui/const-generics/deref-into-array-generic.rs27
8 files changed, 84 insertions, 36 deletions
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 0e267179e30..9d40b3cba29 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -425,7 +425,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
                         // FIXME: perf problem described in #55921.
                         ui = ty::UniverseIndex::ROOT;
                         return self.canonicalize_const_var(
-                            CanonicalVarInfo { kind: CanonicalVarKind::Const(ui) },
+                            CanonicalVarInfo { kind: CanonicalVarKind::Const(ui, ct.ty) },
                             ct,
                         );
                     }
diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs
index 0c26639e9b0..2d2edb07d9e 100644
--- a/compiler/rustc_infer/src/infer/canonical/mod.rs
+++ b/compiler/rustc_infer/src/infer/canonical/mod.rs
@@ -137,12 +137,9 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
                 self.tcx.mk_region(ty::RePlaceholder(placeholder_mapped)).into()
             }
 
-            CanonicalVarKind::Const(ui) => self
+            CanonicalVarKind::Const(ui, ty) => self
                 .next_const_var_in_universe(
-                    self.next_ty_var_in_universe(
-                        TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span },
-                        universe_map(ui),
-                    ),
+                    ty,
                     ConstVariableOrigin { kind: ConstVariableOriginKind::MiscVariable, span },
                     universe_map(ui),
                 )
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index 605fff671db..28217aeab13 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -23,7 +23,7 @@
 
 use crate::infer::MemberConstraint;
 use crate::ty::subst::GenericArg;
-use crate::ty::{self, BoundVar, List, Region, TyCtxt};
+use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt};
 use rustc_index::vec::IndexVec;
 use rustc_macros::HashStable;
 use smallvec::SmallVec;
@@ -104,7 +104,7 @@ impl<'tcx> CanonicalVarInfo<'tcx> {
             CanonicalVarKind::PlaceholderTy(_) => false,
             CanonicalVarKind::Region(_) => true,
             CanonicalVarKind::PlaceholderRegion(..) => false,
-            CanonicalVarKind::Const(_) => true,
+            CanonicalVarKind::Const(..) => true,
             CanonicalVarKind::PlaceholderConst(_) => false,
         }
     }
@@ -130,7 +130,7 @@ pub enum CanonicalVarKind<'tcx> {
     PlaceholderRegion(ty::PlaceholderRegion),
 
     /// Some kind of const inference variable.
-    Const(ty::UniverseIndex),
+    Const(ty::UniverseIndex, Ty<'tcx>),
 
     /// A "placeholder" that represents "any const".
     PlaceholderConst(ty::PlaceholderConst<'tcx>),
@@ -147,7 +147,7 @@ impl<'tcx> CanonicalVarKind<'tcx> {
             CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe,
             CanonicalVarKind::Region(ui) => ui,
             CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe,
-            CanonicalVarKind::Const(ui) => ui,
+            CanonicalVarKind::Const(ui, _) => ui,
             CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.universe,
         }
     }
diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs
index a4d844e2eb8..09bfdabf473 100644
--- a/compiler/rustc_traits/src/chalk/mod.rs
+++ b/compiler/rustc_traits/src/chalk/mod.rs
@@ -85,7 +85,7 @@ crate fn evaluate_goal<'tcx>(
                         chalk_ir::VariableKind::Lifetime,
                         chalk_ir::UniverseIndex { counter: ui.index() },
                     ),
-                    CanonicalVarKind::Const(_ui) => unimplemented!(),
+                    CanonicalVarKind::Const(_ui, _ty) => unimplemented!(),
                     CanonicalVarKind::PlaceholderConst(_pc) => unimplemented!(),
                 }),
             ),
@@ -127,9 +127,9 @@ crate fn evaluate_goal<'tcx>(
                     chalk_ir::VariableKind::Lifetime => CanonicalVarKind::Region(
                         ty::UniverseIndex::from_usize(var.skip_kind().counter),
                     ),
-                    chalk_ir::VariableKind::Const(_) => CanonicalVarKind::Const(
-                        ty::UniverseIndex::from_usize(var.skip_kind().counter),
-                    ),
+                    // FIXME(compiler-errors): We don't currently have a way of turning
+                    // a Chalk ty back into a rustc ty, right?
+                    chalk_ir::VariableKind::Const(_) => todo!(),
                 };
                 CanonicalVarInfo { kind }
             })
diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_typeck/src/check/method/confirm.rs
index dabfe92190b..27c39934ba8 100644
--- a/compiler/rustc_typeck/src/check/method/confirm.rs
+++ b/compiler/rustc_typeck/src/check/method/confirm.rs
@@ -149,7 +149,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
         // time writing the results into the various typeck results.
         let mut autoderef =
             self.autoderef_overloaded_span(self.span, unadjusted_self_ty, self.call_expr.span);
-        let (_, n) = match autoderef.nth(pick.autoderefs) {
+        let (ty, n) = match autoderef.nth(pick.autoderefs) {
             Some(n) => n,
             None => {
                 return self.tcx.ty_error_with_message(
@@ -161,14 +161,15 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
         assert_eq!(n, pick.autoderefs);
 
         let mut adjustments = self.adjust_steps(&autoderef);
+        let mut target = self.structurally_resolved_type(autoderef.span(), ty);
 
-        let mut target =
-            self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));
-
-        match &pick.autoref_or_ptr_adjustment {
+        match pick.autoref_or_ptr_adjustment {
             Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, unsize }) => {
                 let region = self.next_region_var(infer::Autoref(self.span));
-                target = self.tcx.mk_ref(region, ty::TypeAndMut { mutbl: *mutbl, ty: target });
+                // Type we're wrapping in a reference, used later for unsizing
+                let base_ty = target;
+
+                target = self.tcx.mk_ref(region, ty::TypeAndMut { mutbl, ty: target });
                 let mutbl = match mutbl {
                     hir::Mutability::Not => AutoBorrowMutability::Not,
                     hir::Mutability::Mut => AutoBorrowMutability::Mut {
@@ -182,10 +183,18 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
                     target,
                 });
 
-                if let Some(unsize_target) = unsize {
+                if unsize {
+                    let unsized_ty = if let ty::Array(elem_ty, _) = base_ty.kind() {
+                        self.tcx.mk_slice(elem_ty)
+                    } else {
+                        bug!(
+                            "AutorefOrPtrAdjustment's unsize flag should only be set for array ty, found {}",
+                            base_ty
+                        )
+                    };
                     target = self
                         .tcx
-                        .mk_ref(region, ty::TypeAndMut { mutbl: mutbl.into(), ty: unsize_target });
+                        .mk_ref(region, ty::TypeAndMut { mutbl: mutbl.into(), ty: unsized_ty });
                     adjustments
                         .push(Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), target });
                 }
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs
index b704ff8c7cb..86f3568d2e3 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_typeck/src/check/method/probe.rs
@@ -167,26 +167,26 @@ enum ProbeResult {
 /// T`, we could convert it to `*const T`, then autoref to `&*const T`. However, currently we do
 /// (at most) one of these. Either the receiver has type `T` and we convert it to `&T` (or with
 /// `mut`), or it has type `*mut T` and we convert it to `*const T`.
-#[derive(Debug, PartialEq, Clone)]
-pub enum AutorefOrPtrAdjustment<'tcx> {
+#[derive(Debug, PartialEq, Copy, Clone)]
+pub enum AutorefOrPtrAdjustment {
     /// Receiver has type `T`, add `&` or `&mut` (it `T` is `mut`), and maybe also "unsize" it.
     /// Unsizing is used to convert a `[T; N]` to `[T]`, which only makes sense when autorefing.
     Autoref {
         mutbl: hir::Mutability,
 
-        /// Indicates that the source expression should be "unsized" to a target type. This should
-        /// probably eventually go away in favor of just coercing method receivers.
-        unsize: Option<Ty<'tcx>>,
+        /// Indicates that the source expression should be "unsized" to a target type.
+        /// This is special-cased for just arrays unsizing to slices.
+        unsize: bool,
     },
     /// Receiver has type `*mut T`, convert to `*const T`
     ToConstPtr,
 }
 
-impl<'tcx> AutorefOrPtrAdjustment<'tcx> {
-    fn get_unsize(&self) -> Option<Ty<'tcx>> {
+impl AutorefOrPtrAdjustment {
+    fn get_unsize(&self) -> bool {
         match self {
             AutorefOrPtrAdjustment::Autoref { mutbl: _, unsize } => *unsize,
-            AutorefOrPtrAdjustment::ToConstPtr => None,
+            AutorefOrPtrAdjustment::ToConstPtr => false,
         }
     }
 }
@@ -204,7 +204,7 @@ pub struct Pick<'tcx> {
 
     /// Indicates that we want to add an autoref (and maybe also unsize it), or if the receiver is
     /// `*mut T`, convert it to `*const T`.
-    pub autoref_or_ptr_adjustment: Option<AutorefOrPtrAdjustment<'tcx>>,
+    pub autoref_or_ptr_adjustment: Option<AutorefOrPtrAdjustment>,
     pub self_ty: Ty<'tcx>,
 }
 
@@ -1202,7 +1202,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                     pick.autoderefs += 1;
                     pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref {
                         mutbl,
-                        unsize: pick.autoref_or_ptr_adjustment.and_then(|a| a.get_unsize()),
+                        unsize: pick.autoref_or_ptr_adjustment.map_or(false, |a| a.get_unsize()),
                     })
                 }
 
@@ -1227,10 +1227,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         self.pick_method(autoref_ty, unstable_candidates).map(|r| {
             r.map(|mut pick| {
                 pick.autoderefs = step.autoderefs;
-                pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref {
-                    mutbl,
-                    unsize: step.unsize.then_some(self_ty),
-                });
+                pick.autoref_or_ptr_adjustment =
+                    Some(AutorefOrPtrAdjustment::Autoref { mutbl, unsize: step.unsize });
                 pick
             })
         })
diff --git a/src/test/ui/autoref-autoderef/deref-into-array.rs b/src/test/ui/autoref-autoderef/deref-into-array.rs
new file mode 100644
index 00000000000..855a82d2f9c
--- /dev/null
+++ b/src/test/ui/autoref-autoderef/deref-into-array.rs
@@ -0,0 +1,17 @@
+// check-pass
+
+struct Test<T>([T; 1]);
+
+impl<T> std::ops::Deref for Test<T> {
+    type Target = [T; 1];
+
+    fn deref(&self) -> &[T; 1] {
+        &self.0
+    }
+}
+
+fn main() {
+    let out = Test([(); 1]);
+    let blah = out.len();
+    println!("{}", blah);
+}
diff --git a/src/test/ui/const-generics/deref-into-array-generic.rs b/src/test/ui/const-generics/deref-into-array-generic.rs
new file mode 100644
index 00000000000..7d75af12bdf
--- /dev/null
+++ b/src/test/ui/const-generics/deref-into-array-generic.rs
@@ -0,0 +1,27 @@
+// check-pass
+
+struct Test<T, const N: usize>([T; N]);
+
+impl<T: Copy + Default, const N: usize> Default for Test<T, N> {
+    fn default() -> Self {
+        Self([T::default(); N])
+    }
+}
+
+impl<T, const N: usize> std::ops::Deref for Test<T, N> {
+    type Target = [T; N];
+
+    fn deref(&self) -> &[T; N] {
+        &self.0
+    }
+}
+
+fn test() -> Test<u64, 16> {
+    let test = Test::default();
+    println!("{}", test.len());
+    test
+}
+
+fn main() {
+    test();
+}