@@ -128,6 +128,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
128128 & mut candidates,
129129 ) ;
130130 }
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+ }
131137 _ => {
132138 // We re-match here for traits that can have both builtin impls and user written impls.
133139 // 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> {
161167 self . assemble_closure_candidates ( obligation, & mut candidates) ;
162168 self . assemble_fn_pointer_candidates ( obligation, & mut candidates) ;
163169 }
164- Some ( LangItem :: Init ) => {
165- self . assemble_init_candidates ( obligation, & mut candidates) ;
166- }
167170 _ => { }
168171 }
169172
@@ -256,14 +259,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
256259 /// supplied to find out whether it is listed among them.
257260 ///
258261 /// Never affects the inference environment.
259- #[ instrument( level = "debug" , skip( self , stack, candidates) ) ]
262+ #[ instrument( level = "debug" , skip( self , stack, candidates) , fields ( ?stack . obligation ) ) ]
260263 fn assemble_candidates_from_caller_bounds < ' o > (
261264 & mut self ,
262265 stack : & TraitObligationStack < ' o , ' tcx > ,
263266 candidates : & mut SelectionCandidateSet < ' tcx > ,
264267 ) -> Result < ( ) , SelectionError < ' tcx > > {
265- debug ! ( ?stack. obligation) ;
266-
267268 let bounds = stack
268269 . obligation
269270 . param_env
@@ -588,17 +589,87 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
588589 }
589590
590591 #[ instrument( level = "debug" , skip( self , candidates) ) ]
591- fn assemble_init_candidates (
592+ fn assemble_init_candidates < ' o > (
592593 & mut self ,
593- obligation : & PolyTraitObligation < ' tcx > ,
594+ stack : & TraitObligationStack < ' o , ' tcx > ,
594595 candidates : & mut SelectionCandidateSet < ' tcx > ,
595- ) {
596+ ) -> Result < ( ) , SelectionError < ' tcx > > {
597+ let obligation = stack. obligation ;
596598 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
601667 }
668+ _ => { }
669+ }
670+ // Next candidate, the identity
671+ match self_ty. kind ( ) {
672+ ty:: Init ( _, _) => { }
602673 ty:: Bool
603674 | ty:: Char
604675 | ty:: Int ( _)
@@ -608,6 +679,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
608679 | ty:: Foreign ( _)
609680 | ty:: Str
610681 | ty:: Array ( _, _)
682+ | ty:: Alias ( _, _)
683+ | ty:: Param ( _)
611684 | ty:: Pat ( _, _)
612685 | ty:: Slice ( _)
613686 | ty:: RawPtr ( _, _)
@@ -621,8 +694,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
621694 | ty:: Coroutine ( _, _)
622695 | ty:: CoroutineWitness ( _, _)
623696 | ty:: Tuple ( _)
624- | ty:: Alias ( _, _)
625- | ty:: Param ( _)
626697 | ty:: Infer (
627698 ty:: IntVar ( _) | ty:: FloatVar ( _) | ty:: FreshIntTy ( _) | ty:: FreshFloatTy ( _) ,
628699 )
@@ -632,6 +703,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
632703 }
633704 ty:: Never | ty:: Placeholder ( _) | ty:: Infer ( _) | ty:: Error ( _) => { }
634705 }
706+ Ok ( ( ) )
635707 }
636708
637709 /// Searches for impls that might apply to `obligation`.
0 commit comments