From 1b1b6eabaa9ea0090dd47e642b6bb6606cc52e8c Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 23 Sep 2020 16:28:45 +0200 Subject: [PATCH] Remove the "lift constant to reference" logic --- .../rustc_mir_build/src/build/matches/test.rs | 35 +---------------- .../src/thir/pattern/const_to_pat.rs | 39 +++++++++++++------ 2 files changed, 28 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 796815cf216..d81c3b68f48 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -409,40 +409,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let deref_ty = match *ty.kind() { ty::Ref(_, deref_ty, _) => deref_ty, - _ => { - trace!("non_scalar_compare called on non-reference type: {}", ty); - // Backcompat hack: due to non-structural matches not being a hard error, we can - // reach this for types that have manual `Eq` or `PartialEq` impls. - assert!(!ty.is_structural_eq_shallow(self.hir.tcx())); - let ref_ty = self.hir.tcx().mk_imm_ref(self.hir.tcx().lifetimes.re_erased, ty); - // let y = &place; - let y = self.temp(ref_ty, source_info.span); - self.cfg.push_assign( - block, - source_info, - y, - Rvalue::Ref(self.hir.tcx().lifetimes.re_erased, BorrowKind::Shared, place), - ); - val = Operand::Move(y); - // let temp = expect; - let temp = self.temp(ty, source_info.span); - self.cfg.push_assign( - block, - source_info, - temp, - Rvalue::Use(expect), - ); - // reftemp = &temp; - let reftemp = self.temp(ref_ty, source_info.span); - self.cfg.push_assign( - block, - source_info, - reftemp, - Rvalue::Ref(self.hir.tcx().lifetimes.re_erased, BorrowKind::Shared, temp), - ); - expect = Operand::Move(reftemp); - ty - }, + _ => bug!("non_scalar_compare called on non-reference type: {}", ty), }; let eq_def_id = self.hir.tcx().require_lang_item(LangItem::PartialEq, None); diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index ad0bcfeb367..4a50bbca066 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -58,6 +58,9 @@ struct ConstToPat<'a, 'tcx> { include_lint_checks: bool, } +#[derive(Debug)] +struct FallbackToConstRef; + impl<'a, 'tcx> ConstToPat<'a, 'tcx> { fn new( pat_ctxt: &PatCtxt<'_, 'tcx>, @@ -103,7 +106,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { // once indirect_structural_match is a full fledged error, this // level of indirection can be eliminated - let inlined_const_as_pat = self.recur(cv, mir_structural_match_violation); + let inlined_const_as_pat = self.recur(cv, mir_structural_match_violation).unwrap(); if self.include_lint_checks && !self.saw_const_match_error.get() { // If we were able to successfully convert the const to some pat, @@ -216,18 +219,22 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { } // Recursive helper for `to_pat`; invoke that (instead of calling this directly). - fn recur(&self, cv: &'tcx ty::Const<'tcx>, mir_structural_match_violation: bool) -> Pat<'tcx> { + fn recur( + &self, + cv: &'tcx ty::Const<'tcx>, + mir_structural_match_violation: bool, + ) -> Result, FallbackToConstRef> { let id = self.id; let span = self.span; let tcx = self.tcx(); let param_env = self.param_env; - let field_pats = |vals: &[&'tcx ty::Const<'tcx>]| { + let field_pats = |vals: &[&'tcx ty::Const<'tcx>]| -> Result<_, _> { vals.iter() .enumerate() .map(|(idx, val)| { let field = Field::new(idx); - FieldPat { field, pattern: self.recur(val, false) } + Ok(FieldPat { field, pattern: self.recur(val, false)? }) }) .collect() }; @@ -287,7 +294,10 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { |lint| lint.build(&msg).emit(), ); } - PatKind::Constant { value: cv } + // Since we are behind a reference, we can just bubble the error up so we get a + // constant at reference type, making it easy to let the fallback call + // `PartialEq::eq` on it. + return Err(FallbackToConstRef); } ty::Adt(adt_def, _) if !self.type_marked_structural(cv.ty) => { debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, cv.ty); @@ -309,12 +319,12 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { variant_index: destructured .variant .expect("destructed const of adt without variant id"), - subpatterns: field_pats(destructured.fields), + subpatterns: field_pats(destructured.fields)?, } } ty::Tuple(_) | ty::Adt(_, _) => { let destructured = tcx.destructure_const(param_env.and(cv)); - PatKind::Leaf { subpatterns: field_pats(destructured.fields) } + PatKind::Leaf { subpatterns: field_pats(destructured.fields)? } } ty::Array(..) => PatKind::Array { prefix: tcx @@ -322,7 +332,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { .fields .iter() .map(|val| self.recur(val, false)) - .collect(), + .collect::>()?, slice: None, suffix: Vec::new(), }, @@ -355,7 +365,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { .fields .iter() .map(|val| self.recur(val, false)) - .collect(), + .collect::>()?, slice: None, suffix: vec![], }), @@ -379,8 +389,13 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { // deref pattern. _ => { let old = self.behind_reference.replace(true); - let val = PatKind::Deref { - subpattern: self.recur(tcx.deref_const(self.param_env.and(cv)), false), + // In case there are structural-match violations somewhere in this subpattern, + // we fall back to a const pattern. If we do not do this, we may end up with + // a !structural-match constant that is not of reference type, which makes it + // very hard to invoke `PartialEq::eq` on it as a fallback. + let val = match self.recur(tcx.deref_const(self.param_env.and(cv)), false) { + Ok(subpattern) => PatKind::Deref { subpattern }, + Err(FallbackToConstRef) => PatKind::Constant { value: cv }, }; self.behind_reference.set(old); val @@ -439,6 +454,6 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { ); } - Pat { span, ty: cv.ty, kind: Box::new(kind) } + Ok(Pat { span, ty: cv.ty, kind: Box::new(kind) }) } }