From 012910dab253e8b64dd06e2a91de1943d518439b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 7 Jan 2022 09:13:00 -0800 Subject: [PATCH 1/3] Canonicalize const variables correctly --- compiler/rustc_infer/src/infer/canonical/canonicalizer.rs | 2 +- compiler/rustc_infer/src/infer/canonical/mod.rs | 7 ++----- compiler/rustc_middle/src/infer/canonical.rs | 8 ++++---- compiler/rustc_traits/src/chalk/mod.rs | 8 ++++---- 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 6023973665360..f29aaf56150ce 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 0c26639e9b0fe..2d2edb07d9eda 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 605fff671db06..28217aeab13ee 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 a4d844e2eb8cc..09bfdabf47373 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 } }) From 9bf9fe07dc2775a8499326990a2fa4bc4af88f8f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 7 Jan 2022 01:23:07 -0800 Subject: [PATCH 2/3] Don't leak inference variables in array unsizing --- .../rustc_typeck/src/check/method/confirm.rs | 25 ++++++++++++------ .../rustc_typeck/src/check/method/probe.rs | 26 +++++++++---------- 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_typeck/src/check/method/confirm.rs index dabfe92190b33..27c39934ba8e9 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 5615a08369dff..8ce1c27f81dcc 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>, + /// 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> { +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>, + pub autoref_or_ptr_adjustment: Option, 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 }) }) From 7bf0cb76710e723ac71257e04f4a1bfbbfc87c3c Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 7 Jan 2022 10:26:17 -0800 Subject: [PATCH 3/3] Add new tests, fix up old tests --- .../ui/autoref-autoderef/deref-into-array.rs | 17 ++++++++++++ .../deref-into-array-generic.rs | 27 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 src/test/ui/autoref-autoderef/deref-into-array.rs create mode 100644 src/test/ui/const-generics/deref-into-array-generic.rs 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 0000000000000..855a82d2f9c8f --- /dev/null +++ b/src/test/ui/autoref-autoderef/deref-into-array.rs @@ -0,0 +1,17 @@ +// check-pass + +struct Test([T; 1]); + +impl std::ops::Deref for Test { + 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 0000000000000..7d75af12bdfb5 --- /dev/null +++ b/src/test/ui/const-generics/deref-into-array-generic.rs @@ -0,0 +1,27 @@ +// check-pass + +struct Test([T; N]); + +impl Default for Test { + fn default() -> Self { + Self([T::default(); N]) + } +} + +impl std::ops::Deref for Test { + type Target = [T; N]; + + fn deref(&self) -> &[T; N] { + &self.0 + } +} + +fn test() -> Test { + let test = Test::default(); + println!("{}", test.len()); + test +} + +fn main() { + test(); +}