1
1
use crate :: traits:: specialization_graph;
2
2
3
3
use super :: assembly:: { self , structural_traits} ;
4
- use super :: EvalCtxt ;
4
+ use super :: { EvalCtxt , SolverMode } ;
5
5
use rustc_errors:: ErrorGuaranteed ;
6
6
use rustc_hir:: def:: DefKind ;
7
7
use rustc_hir:: def_id:: DefId ;
@@ -167,17 +167,34 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
167
167
. map ( |pred| goal. with ( tcx, pred) ) ;
168
168
ecx. add_goals ( where_clause_bounds) ;
169
169
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 (
174
171
ecx,
175
172
goal. param_env ,
176
173
goal_trait_ref,
177
174
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
+ } ,
181
198
} ;
182
199
183
200
if !assoc_def. item . defaultness ( tcx) . has_value ( ) {
@@ -574,6 +591,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
574
591
}
575
592
}
576
593
594
+ #[ derive( Debug ) ]
595
+ enum NotAvailableReason {
596
+ ErrorGuaranteed ( ErrorGuaranteed ) ,
597
+ DefaultItem ,
598
+ }
599
+
577
600
/// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code.
578
601
///
579
602
/// 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>(
585
608
goal_trait_ref : ty:: TraitRef < ' tcx > ,
586
609
trait_assoc_def_id : DefId ,
587
610
impl_def_id : DefId ,
588
- ) -> Result < Option < LeafDef > , NoSolution > {
611
+ ) -> Result < LeafDef , NotAvailableReason > {
589
612
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 ) ?;
591
614
592
- let eligible = if node_item. is_final ( ) {
615
+ if node_item. is_final ( ) {
593
616
// Non-specializable items are always projectable.
594
- true
617
+ Ok ( node_item )
595
618
} else {
596
619
// Only reveal a specializable default if we're past type-checking
597
620
// and the obligation is monomorphic, otherwise passes such as
598
621
// transmute checking and polymorphic MIR optimizations could
599
622
// get a result which isn't correct for all monomorphizations.
600
623
if param_env. reveal ( ) == Reveal :: All {
601
624
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
+ }
603
635
} else {
604
- debug ! ( ?node_item. item. def_id, "not eligible due to default" ) ;
605
- false
636
+ Err ( NotAvailableReason :: DefaultItem )
606
637
}
607
- } ;
608
-
609
- if eligible { Ok ( Some ( node_item) ) } else { Ok ( None ) }
638
+ }
610
639
}
0 commit comments