@@ -366,29 +366,80 @@ impl<T: Ord, const N: usize> Ord for [T; N] {
366
366
}
367
367
}
368
368
369
- // The Default impls cannot be done with const generics because `[T; 0]` doesn't
370
- // require Default to be implemented, and having different impl blocks for
371
- // different numbers isn't supported yet.
372
-
373
- macro_rules! array_impl_default {
374
- { $n: expr, $t: ident $( $ts: ident) * } => {
375
- #[ stable( since = "1.4.0" , feature = "array_default" ) ]
376
- impl <T > Default for [ T ; $n] where T : Default {
377
- fn default ( ) -> [ T ; $n] {
378
- [ $t:: default ( ) , $( $ts:: default ( ) ) ,* ]
369
+ #[ cfg( bootstrap) ]
370
+ mod array_defaults {
371
+ macro_rules! array_impl_default {
372
+ { $n: expr, $t: ident $( $ts: ident) * } => {
373
+ #[ stable( since = "1.4.0" , feature = "array_default" ) ]
374
+ impl <T > Default for [ T ; $n] where T : Default {
375
+ fn default ( ) -> [ T ; $n] {
376
+ [ $t:: default ( ) , $( $ts:: default ( ) ) ,* ]
377
+ }
379
378
}
380
- }
381
- array_impl_default!{ ( $n - 1 ) , $( $ts) * }
382
- } ;
383
- { $n: expr, } => {
384
- #[ stable( since = "1.4.0" , feature = "array_default" ) ]
385
- impl <T > Default for [ T ; $n] {
386
- fn default ( ) -> [ T ; $n] { [ ] }
387
- }
388
- } ;
379
+ array_impl_default!{ ( $n - 1 ) , $( $ts) * }
380
+ } ;
381
+ { $n: expr, } => {
382
+ #[ stable( since = "1.4.0" , feature = "array_default" ) ]
383
+ impl <T > Default for [ T ; $n] {
384
+ fn default ( ) -> [ T ; $n] { [ ] }
385
+ }
386
+ } ;
387
+ }
388
+
389
+ array_impl_default ! { 32 , T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T }
389
390
}
390
391
391
- array_impl_default ! { 32 , T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T }
392
+ #[ cfg( not( bootstrap) ) ]
393
+ mod array_defaults {
394
+ // We use auto traits to get overlapping impls without relying on nightly features.
395
+ //
396
+ // As the auto impl for `SendToDefault` is only considered if the manual impl does not apply,
397
+ // we have to use the generic impl for `T: Default` as the impl for the `N = 0` case would
398
+ // influence type inference in undesirable ways.
399
+ //
400
+ // While we are now able to implement `Default` exactly for the array types we want,
401
+ // we're still not able to actually write the body of the `Default` function without
402
+ // some further hacks.
403
+ //
404
+ // The idea here is that `array_default_hack` is resolved to itself only if `N = 0`
405
+ // and is otherwise replaced with `T::default()`.
406
+ //
407
+ // This would cause issues if `T` doesn't actually implement default but as this function
408
+ // is private and only used in the default impl itself this can not happen.
409
+
410
+ struct ZeroToSend < T , const N : usize > ( * mut ( ) , T ) ;
411
+ unsafe impl < T > Send for ZeroToSend < T , 0 > { }
412
+
413
+ /// This struct implements `Send` either because of the manual impl for `N` is `0` or
414
+ /// because all its fields implement `Send`, which is the case if `T` implements `Default`.
415
+ #[ unstable(
416
+ feature = "array_default_impl" ,
417
+ issue = "none" ,
418
+ reason = "internal implementation detail for `[T; N]: Default`"
419
+ ) ]
420
+ #[ allow( missing_debug_implementations) ]
421
+ pub struct SendToDefault < T , const N : usize > ( ZeroToSend < T , N > ) ;
422
+ #[ unstable( feature = "array_default_impl" , issue = "none" ) ]
423
+ unsafe impl < T : Default , const N : usize > Send for SendToDefault < T , N > { }
424
+
425
+ // This function must not get called for `N != 0` if `T` does not implement `Default`.
426
+ #[ lang = "array_default_hack" ]
427
+ unsafe fn array_default_hack < T , const N : usize > ( ) -> T {
428
+ unreachable ! ( "array_default_hack used for array with length {}" , N ) ;
429
+ }
430
+
431
+ #[ stable( since = "1.4.0" , feature = "array_default" ) ]
432
+ impl < T , const N : usize > Default for [ T ; N ]
433
+ where
434
+ SendToDefault < T , N > : Send ,
435
+ {
436
+ fn default ( ) -> [ T ; N ] {
437
+ // SAFETY: The only case where `T` does not implement `Default` is
438
+ // when `N` is zero, in which case `array_default_hack` isn't called.
439
+ [ ( ) ; N ] . map ( |( ) | unsafe { array_default_hack :: < T , N > ( ) } )
440
+ }
441
+ }
442
+ }
392
443
393
444
#[ lang = "array" ]
394
445
impl < T , const N : usize > [ T ; N ] {
0 commit comments