From 67ce547f474fbe34e8aafe4bfc284c3856673744 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 29 Apr 2022 18:56:57 +0000 Subject: [PATCH] Refactor and document the repeat length check --- compiler/rustc_typeck/src/check/expr.rs | 41 +++++++++++++------------ 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 8dd288e5555f..a1e8d2040dd8 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -1304,31 +1304,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { element_ty: Ty<'tcx>, ) { let tcx = self.tcx; - let is_const = match &element.kind { - hir::ExprKind::ConstBlock(..) => true, + // Actual constants as the repeat element get inserted repeatedly instead of getting copied via Copy. + match &element.kind { + hir::ExprKind::ConstBlock(..) => return, hir::ExprKind::Path(qpath) => { let res = self.typeck_results.borrow().qpath_res(qpath, element.hir_id); - matches!( - res, - Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::AnonConst, _) - ) + if let Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::AnonConst, _) = res + { + return; + } } + _ => {} + } + // If someone calls a const fn, they can extract that call out into a separate constant (or a const + // block in the future), so we check that to tell them that in the diagnostic. Does not affect typeck. + let is_const_fn = match element.kind { + hir::ExprKind::Call(func, _args) => match *self.node_ty(func.hir_id).kind() { + ty::FnDef(def_id, _) => tcx.is_const_fn(def_id), + _ => false, + }, _ => false, }; - if !is_const { - let is_const_fn = match element.kind { - hir::ExprKind::Call(func, _args) => match *self.node_ty(func.hir_id).kind() { - ty::FnDef(def_id, _) => tcx.is_const_fn(def_id), - _ => false, - }, - _ => false, - }; - if count.try_eval_usize(tcx, self.param_env).map_or(true, |len| len > 1) { - let lang_item = self.tcx.require_lang_item(LangItem::Copy, None); - let code = traits::ObligationCauseCode::RepeatElementCopy { is_const_fn }; - self.require_type_meets(element_ty, element.span, code, lang_item); - } + // If the length is 0, we don't create any elements, so we don't copy any. If the length is 1, we + // don't copy that one element, we move it. Only check for Copy if the length is larger. + if count.try_eval_usize(tcx, self.param_env).map_or(true, |len| len > 1) { + let lang_item = self.tcx.require_lang_item(LangItem::Copy, None); + let code = traits::ObligationCauseCode::RepeatElementCopy { is_const_fn }; + self.require_type_meets(element_ty, element.span, code, lang_item); } }