@@ -128,6 +128,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
128
128
& mut candidates,
129
129
) ;
130
130
}
131
+ Some ( LangItem :: Init ) => {
132
+ // User defined `Init` comes first but are applicable only on `struct`s and `enums`
133
+ self . assemble_candidates_from_impls ( obligation, & mut candidates) ;
134
+ self . assemble_candidates_from_object_ty ( obligation, & mut candidates) ;
135
+ self . assemble_init_candidates ( stack, & mut candidates) ?;
136
+ }
131
137
_ => {
132
138
// We re-match here for traits that can have both builtin impls and user written impls.
133
139
// After the builtin impls we need to also add user written impls, which we do not want to
@@ -161,9 +167,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
161
167
self . assemble_closure_candidates ( obligation, & mut candidates) ;
162
168
self . assemble_fn_pointer_candidates ( obligation, & mut candidates) ;
163
169
}
164
- Some ( LangItem :: Init ) => {
165
- self . assemble_init_candidates ( obligation, & mut candidates) ;
166
- }
167
170
_ => { }
168
171
}
169
172
@@ -256,14 +259,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
256
259
/// supplied to find out whether it is listed among them.
257
260
///
258
261
/// Never affects the inference environment.
259
- #[ instrument( level = "debug" , skip( self , stack, candidates) ) ]
262
+ #[ instrument( level = "debug" , skip( self , stack, candidates) , fields ( ?stack . obligation ) ) ]
260
263
fn assemble_candidates_from_caller_bounds < ' o > (
261
264
& mut self ,
262
265
stack : & TraitObligationStack < ' o , ' tcx > ,
263
266
candidates : & mut SelectionCandidateSet < ' tcx > ,
264
267
) -> Result < ( ) , SelectionError < ' tcx > > {
265
- debug ! ( ?stack. obligation) ;
266
-
267
268
let bounds = stack
268
269
. obligation
269
270
. param_env
@@ -588,17 +589,87 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
588
589
}
589
590
590
591
#[ instrument( level = "debug" , skip( self , candidates) ) ]
591
- fn assemble_init_candidates (
592
+ fn assemble_init_candidates < ' o > (
592
593
& mut self ,
593
- obligation : & PolyTraitObligation < ' tcx > ,
594
+ stack : & TraitObligationStack < ' o , ' tcx > ,
594
595
candidates : & mut SelectionCandidateSet < ' tcx > ,
595
- ) {
596
+ ) -> Result < ( ) , SelectionError < ' tcx > > {
597
+ let obligation = stack. obligation ;
596
598
let self_ty = obligation. self_ty ( ) . skip_binder ( ) ;
597
- match self_ty. kind ( ) {
598
- ty:: Init ( _, _) => {
599
- debug ! ( "init candidate" ) ;
600
- candidates. vec . push ( InitCandidate ) ;
599
+ debug ! ( kind = ?self_ty. kind( ) ) ;
600
+ let tcx = self . tcx ( ) ;
601
+ let bounds =
602
+ obligation. param_env . caller_bounds ( ) . iter ( ) . filter_map ( |p| p. as_trait_clause ( ) ) . filter (
603
+ |p| {
604
+ tcx. is_lang_item ( p. def_id ( ) , LangItem :: Init )
605
+ && matches ! ( p. polarity( ) , ty:: PredicatePolarity :: Positive )
606
+ } ,
607
+ ) ;
608
+ if let ty:: Init ( _, _) = self_ty. kind ( ) {
609
+ debug ! ( "init candidate" ) ;
610
+ candidates. vec . push ( InitCandidate ) ;
611
+ // Short circuiting
612
+ // .. because this is the most specific `Init` impl
613
+ // there can be.
614
+ // During the confirmation stage we will figure out whether
615
+ // an unsizing `Init` should be used
616
+ return Ok ( ( ) ) ;
617
+ }
618
+ let target_ty = self
619
+ . infcx
620
+ . resolve_vars_if_possible ( obligation. predicate . skip_binder ( ) . trait_ref . args . type_at ( 1 ) ) ;
621
+ // Try to take from the typing environment, in order of specificity:
622
+ let drcx = DeepRejectCtxt :: relate_rigid_rigid ( tcx) ;
623
+ match target_ty. kind ( ) {
624
+ // 1) S: Init<[T; N]>
625
+ // ________________ init_unsize_array
626
+ // S: Init<[T]>
627
+ & ty:: Slice ( elem_ty) => {
628
+ // todo
629
+ let mut candidate = None :: < ty:: PolyTraitPredicate < ' _ > > ;
630
+ for bound in bounds {
631
+ let target_ty = bound. skip_binder ( ) . trait_ref . args . type_at ( 1 ) ;
632
+ let & ty:: Array ( other_elem_ty, _) = target_ty. kind ( ) else {
633
+ continue ;
634
+ } ;
635
+ if !drcx. types_may_unify ( self_ty, bound. self_ty ( ) . skip_binder ( ) )
636
+ || !drcx. types_may_unify ( elem_ty, other_elem_ty)
637
+ {
638
+ continue ;
639
+ }
640
+
641
+ let wc =
642
+ self . where_clause_may_apply ( stack, bound. map_bound ( |b| b. trait_ref ) ) ?;
643
+ if !wc. may_apply ( ) {
644
+ continue ;
645
+ }
646
+ // Okay we have one candidate by unsizing the array
647
+ // but rejects when there are multiple different impls.
648
+ // There is a potential issue: what if there are multiple `Init<[T; N]>`
649
+ // with potentially different `N` or un-unifiable `T`?
650
+ // This can become an opportunity to bait-and-switch.
651
+ if let Some ( candidate) = candidate {
652
+ let other_target_ty = candidate. skip_binder ( ) . trait_ref . args . type_at ( 1 ) ;
653
+ if !drcx. types_may_unify ( target_ty, other_target_ty) {
654
+ debug ! ( ?candidate, another_candidate = ?bound, "ambiguous array unsizing init" ) ;
655
+ candidates. ambiguous = true ;
656
+ return Ok ( ( ) ) ;
657
+ }
658
+ // We will keep to the first discovery
659
+ } else {
660
+ candidate = Some ( bound) ;
661
+ }
662
+ }
663
+ candidates. vec . extend ( candidate. map ( ArrayUnsizeInitCandidate ) ) ;
664
+ }
665
+ & ty:: Adt ( _def, _args) => {
666
+ // NOTE: unify for unsizing ADTs too
601
667
}
668
+ _ => { }
669
+ }
670
+ // Next candidate, the identity
671
+ match self_ty. kind ( ) {
672
+ ty:: Init ( _, _) => { }
602
673
ty:: Bool
603
674
| ty:: Char
604
675
| ty:: Int ( _)
@@ -608,6 +679,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
608
679
| ty:: Foreign ( _)
609
680
| ty:: Str
610
681
| ty:: Array ( _, _)
682
+ | ty:: Alias ( _, _)
683
+ | ty:: Param ( _)
611
684
| ty:: Pat ( _, _)
612
685
| ty:: Slice ( _)
613
686
| ty:: RawPtr ( _, _)
@@ -621,8 +694,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
621
694
| ty:: Coroutine ( _, _)
622
695
| ty:: CoroutineWitness ( _, _)
623
696
| ty:: Tuple ( _)
624
- | ty:: Alias ( _, _)
625
- | ty:: Param ( _)
626
697
| ty:: Infer (
627
698
ty:: IntVar ( _) | ty:: FloatVar ( _) | ty:: FreshIntTy ( _) | ty:: FreshFloatTy ( _) ,
628
699
)
@@ -632,6 +703,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
632
703
}
633
704
ty:: Never | ty:: Placeholder ( _) | ty:: Infer ( _) | ty:: Error ( _) => { }
634
705
}
706
+ Ok ( ( ) )
635
707
}
636
708
637
709
/// Searches for impls that might apply to `obligation`.
0 commit comments