11use crate :: traits:: specialization_graph;
22
33use super :: assembly:: { self , structural_traits} ;
4- use super :: EvalCtxt ;
4+ use super :: { EvalCtxt , SolverMode } ;
55use rustc_errors:: ErrorGuaranteed ;
66use rustc_hir:: def:: DefKind ;
77use rustc_hir:: def_id:: DefId ;
@@ -167,17 +167,34 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
167167 . map ( |pred| goal. with ( tcx, pred) ) ;
168168 ecx. add_goals ( where_clause_bounds) ;
169169
170- // In case the associated item is hidden due to specialization, we have to
171- // return ambiguity this would otherwise be incomplete, resulting in
172- // unsoundness during coherence (#105782).
173- let Some ( assoc_def) = fetch_eligible_assoc_item_def (
170+ let assoc_def = match fetch_eligible_assoc_item_def (
174171 ecx,
175172 goal. param_env ,
176173 goal_trait_ref,
177174 goal. predicate . def_id ( ) ,
178- impl_def_id
179- ) ? else {
180- return ecx. evaluate_added_goals_and_make_canonical_response ( Certainty :: AMBIGUOUS ) ;
175+ impl_def_id,
176+ ) {
177+ Ok ( assoc_def) => assoc_def,
178+ Err ( NotAvailableReason :: ErrorGuaranteed ( guar) ) => {
179+ let error_term = ecx. term_error_of_kind ( goal. predicate . term , guar) ;
180+ ecx. eq ( goal. param_env , goal. predicate . term , error_term)
181+ . expect ( "expected goal term to be fully unconstrained" ) ;
182+ return ecx. evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes ) ;
183+ }
184+ // In case the associated item is hidden due to specialization, we have to
185+ // return ambiguity during coherence as it would otherwise be incomplete,
186+ // resulting in unsoundness (#105782).
187+ //
188+ // Outside of coherence we want to fail here as we want to treat defaulted
189+ // associated items as opaque.
190+ Err ( NotAvailableReason :: DefaultItem ) => match ecx. solver_mode ( ) {
191+ SolverMode :: Normal => return Err ( NoSolution ) ,
192+ SolverMode :: Coherence => {
193+ return ecx. evaluate_added_goals_and_make_canonical_response (
194+ Certainty :: AMBIGUOUS ,
195+ ) ;
196+ }
197+ } ,
181198 } ;
182199
183200 if !assoc_def. item . defaultness ( tcx) . has_value ( ) {
@@ -574,6 +591,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
574591 }
575592}
576593
594+ #[ derive( Debug ) ]
595+ enum NotAvailableReason {
596+ ErrorGuaranteed ( ErrorGuaranteed ) ,
597+ DefaultItem ,
598+ }
599+
577600/// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code.
578601///
579602/// FIXME: We should merge these 3 implementations as it's likely that they otherwise
@@ -585,26 +608,32 @@ fn fetch_eligible_assoc_item_def<'tcx>(
585608 goal_trait_ref : ty:: TraitRef < ' tcx > ,
586609 trait_assoc_def_id : DefId ,
587610 impl_def_id : DefId ,
588- ) -> Result < Option < LeafDef > , NoSolution > {
611+ ) -> Result < LeafDef , NotAvailableReason > {
589612 let node_item = specialization_graph:: assoc_def ( ecx. tcx ( ) , impl_def_id, trait_assoc_def_id)
590- . map_err ( | ErrorGuaranteed { .. } | NoSolution ) ?;
613+ . map_err ( NotAvailableReason :: ErrorGuaranteed ) ?;
591614
592- let eligible = if node_item. is_final ( ) {
615+ if node_item. is_final ( ) {
593616 // Non-specializable items are always projectable.
594- true
617+ Ok ( node_item )
595618 } else {
596619 // Only reveal a specializable default if we're past type-checking
597620 // and the obligation is monomorphic, otherwise passes such as
598621 // transmute checking and polymorphic MIR optimizations could
599622 // get a result which isn't correct for all monomorphizations.
600623 if param_env. reveal ( ) == Reveal :: All {
601624 let poly_trait_ref = ecx. resolve_vars_if_possible ( goal_trait_ref) ;
602- !poly_trait_ref. still_further_specializable ( )
625+ if poly_trait_ref. still_further_specializable ( ) {
626+ // We'd have to deal with inference variables and return
627+ // ambiguity or something, that's annoying so I am going to
628+ // just ICE here until there's a need to actually implement
629+ // this.
630+ assert ! ( !poly_trait_ref. has_infer( ) ) ;
631+ Err ( NotAvailableReason :: DefaultItem )
632+ } else {
633+ Ok ( node_item)
634+ }
603635 } else {
604- debug ! ( ?node_item. item. def_id, "not eligible due to default" ) ;
605- false
636+ Err ( NotAvailableReason :: DefaultItem )
606637 }
607- } ;
608-
609- if eligible { Ok ( Some ( node_item) ) } else { Ok ( None ) }
638+ }
610639}
0 commit comments