@@ -4,10 +4,10 @@ use itertools::Itertools;
4
4
use rustc_data_structures:: fx:: FxIndexSet ;
5
5
use rustc_errors:: codes:: * ;
6
6
use rustc_errors:: { Applicability , Diag , ErrorGuaranteed , MultiSpan , a_or_an, listify, pluralize} ;
7
- use rustc_hir:: def:: { CtorOf , DefKind , Res } ;
7
+ use rustc_hir:: def:: { CtorKind , CtorOf , DefKind , Res } ;
8
8
use rustc_hir:: def_id:: DefId ;
9
9
use rustc_hir:: intravisit:: Visitor ;
10
- use rustc_hir:: { ExprKind , HirId , Node , QPath } ;
10
+ use rustc_hir:: { ExprKind , HirId , LangItem , Node , QPath } ;
11
11
use rustc_hir_analysis:: check:: potentially_plural_count;
12
12
use rustc_hir_analysis:: hir_ty_lowering:: HirTyLowerer ;
13
13
use rustc_index:: IndexVec ;
@@ -104,24 +104,96 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
104
104
pub ( in super :: super ) fn check_repeat_exprs ( & self ) {
105
105
let mut deferred_repeat_expr_checks = self . deferred_repeat_expr_checks . borrow_mut ( ) ;
106
106
debug ! ( "FnCtxt::check_repeat_exprs: {} deferred checks" , deferred_repeat_expr_checks. len( ) ) ;
107
- for ( element, element_ty, count) in deferred_repeat_expr_checks. drain ( ..) {
108
- // We want to emit an error if the const is not structurally resolveable as otherwise
109
- // we can find up conservatively proving `Copy` which may infer the repeat expr count
110
- // to something that never required `Copy` in the first place.
111
- let count =
112
- self . structurally_resolve_const ( element. span , self . normalize ( element. span , count) ) ;
113
-
114
- // Avoid run on "`NotCopy: Copy` is not implemented" errors when the repeat expr count
115
- // is erroneous/unknown. The user might wind up specifying a repeat count of 0/1.
116
- if count. references_error ( ) {
117
- continue ;
118
- }
119
107
120
- // If the length is 0, we don't create any elements, so we don't copy any.
121
- // If the length is 1, we don't copy that one element, we move it. Only check
122
- // for `Copy` if the length is larger.
123
- if count. try_to_target_usize ( self . tcx ) . is_none_or ( |x| x > 1 ) {
124
- self . enforce_repeat_element_needs_copy_bound ( element, element_ty) ;
108
+ let deferred_repeat_expr_checks = deferred_repeat_expr_checks
109
+ . drain ( ..)
110
+ . flat_map ( |( element, element_ty, count) | {
111
+ // Actual constants as the repeat element are inserted repeatedly instead
112
+ // of being copied via `Copy`, so we don't need to attempt to structurally
113
+ // resolve the repeat count which may unnecessarily error.
114
+ match & element. kind {
115
+ hir:: ExprKind :: ConstBlock ( ..) => return None ,
116
+ hir:: ExprKind :: Path ( qpath) => {
117
+ let res = self . typeck_results . borrow ( ) . qpath_res ( qpath, element. hir_id ) ;
118
+ if let Res :: Def ( DefKind :: Const | DefKind :: AssocConst , _) = res {
119
+ return None ;
120
+ }
121
+ }
122
+ _ => { }
123
+ }
124
+
125
+ // We want to emit an error if the const is not structurally resolveable
126
+ // as otherwise we can wind up conservatively proving `Copy` which may
127
+ // infer the repeat expr count to something that never required `Copy` in
128
+ // the first place.
129
+ let count = self
130
+ . structurally_resolve_const ( element. span , self . normalize ( element. span , count) ) ;
131
+
132
+ // Avoid run on "`NotCopy: Copy` is not implemented" errors when the
133
+ // repeat expr count is erroneous/unknown. The user might wind up
134
+ // specifying a repeat count of 0/1.
135
+ if count. references_error ( ) {
136
+ return None ;
137
+ }
138
+
139
+ Some ( ( element, element_ty, count) )
140
+ } )
141
+ // We collect to force the side effects of structurally resolving the repeat
142
+ // count to happen in one go, to avoid side effects from proving `Copy`
143
+ // affecting whether repeat counts are known or not. If we did not do this we
144
+ // would get results that depend on the order that we evaluate each repeat
145
+ // expr's `Copy` check.
146
+ . collect :: < Vec < _ > > ( ) ;
147
+
148
+ let enforce_copy_bound = |element : & hir:: Expr < ' _ > , element_ty| {
149
+ // If someone calls a const fn or constructs a const value, they can extract that
150
+ // out into a separate constant (or a const block in the future), so we check that
151
+ // to tell them that in the diagnostic. Does not affect typeck.
152
+ let is_constable = match element. kind {
153
+ hir:: ExprKind :: Call ( func, _args) => match * self . node_ty ( func. hir_id ) . kind ( ) {
154
+ ty:: FnDef ( def_id, _) if self . tcx . is_stable_const_fn ( def_id) => {
155
+ traits:: IsConstable :: Fn
156
+ }
157
+ _ => traits:: IsConstable :: No ,
158
+ } ,
159
+ hir:: ExprKind :: Path ( qpath) => {
160
+ match self . typeck_results . borrow ( ) . qpath_res ( & qpath, element. hir_id ) {
161
+ Res :: Def ( DefKind :: Ctor ( _, CtorKind :: Const ) , _) => traits:: IsConstable :: Ctor ,
162
+ _ => traits:: IsConstable :: No ,
163
+ }
164
+ }
165
+ _ => traits:: IsConstable :: No ,
166
+ } ;
167
+
168
+ let lang_item = self . tcx . require_lang_item ( LangItem :: Copy , None ) ;
169
+ let code = traits:: ObligationCauseCode :: RepeatElementCopy {
170
+ is_constable,
171
+ elt_span : element. span ,
172
+ } ;
173
+ self . require_type_meets ( element_ty, element. span , code, lang_item) ;
174
+ } ;
175
+
176
+ for ( element, element_ty, count) in deferred_repeat_expr_checks {
177
+ match count. kind ( ) {
178
+ ty:: ConstKind :: Value ( val) => {
179
+ if val. try_to_target_usize ( self . tcx ) . is_none_or ( |count| count > 1 ) {
180
+ enforce_copy_bound ( element, element_ty)
181
+ } else {
182
+ // If the length is 0 or 1 we don't actually copy the element, we either don't create it
183
+ // or we just use the one value.
184
+ }
185
+ }
186
+
187
+ // If the length is a generic parameter or some rigid alias then conservatively
188
+ // require `element_ty: Copy` as it may wind up being `>1` after monomorphization.
189
+ ty:: ConstKind :: Param ( _)
190
+ | ty:: ConstKind :: Expr ( _)
191
+ | ty:: ConstKind :: Placeholder ( _)
192
+ | ty:: ConstKind :: Unevaluated ( _) => enforce_copy_bound ( element, element_ty) ,
193
+
194
+ ty:: ConstKind :: Bound ( _, _) | ty:: ConstKind :: Infer ( _) | ty:: ConstKind :: Error ( _) => {
195
+ unreachable ! ( )
196
+ }
125
197
}
126
198
}
127
199
}
0 commit comments