@@ -271,64 +271,32 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
271271 & mut self ,
272272 goal : Goal < ' tcx , G > ,
273273 ) -> Vec < Candidate < ' tcx > > {
274- debug_assert_eq ! ( goal, self . resolve_vars_if_possible( goal) ) ;
275- if let Some ( ambig) = self . assemble_self_ty_infer_ambiguity_response ( goal) {
276- return vec ! [ ambig] ;
277- }
278-
279- let mut candidates = self . assemble_candidates_via_self_ty ( goal, 0 ) ;
280-
281- self . assemble_unsize_to_dyn_candidate ( goal, & mut candidates) ;
282-
283- self . assemble_blanket_impl_candidates ( goal, & mut candidates) ;
284-
285- self . assemble_param_env_candidates ( goal, & mut candidates) ;
286-
287- self . assemble_coherence_unknowable_candidates ( goal, & mut candidates) ;
288-
289- candidates
290- }
291-
292- /// `?0: Trait` is ambiguous, because it may be satisfied via a builtin rule,
293- /// object bound, alias bound, etc. We are unable to determine this until we can at
294- /// least structurally resolve the type one layer.
295- ///
296- /// It would also require us to consider all impls of the trait, which is both pretty
297- /// bad for perf and would also constrain the self type if there is just a single impl.
298- fn assemble_self_ty_infer_ambiguity_response < G : GoalKind < ' tcx > > (
299- & mut self ,
300- goal : Goal < ' tcx , G > ,
301- ) -> Option < Candidate < ' tcx > > {
302- if goal. predicate . self_ty ( ) . is_ty_var ( ) {
303- debug ! ( "adding self_ty_infer_ambiguity_response" ) ;
274+ let dummy_candidate = |this : & mut EvalCtxt < ' _ , ' tcx > , certainty| {
304275 let source = CandidateSource :: BuiltinImpl ( BuiltinImplSource :: Misc ) ;
305- let result = self
306- . evaluate_added_goals_and_make_canonical_response ( Certainty :: AMBIGUOUS )
307- . unwrap ( ) ;
308- let mut dummy_probe = self . inspect . new_probe ( ) ;
276+ let result = this. evaluate_added_goals_and_make_canonical_response ( certainty) . unwrap ( ) ;
277+ let mut dummy_probe = this. inspect . new_probe ( ) ;
309278 dummy_probe. probe_kind ( ProbeKind :: TraitCandidate { source, result : Ok ( result) } ) ;
310- self . inspect . finish_probe ( dummy_probe) ;
311- Some ( Candidate { source, result } )
312- } else {
313- None
279+ this. inspect . finish_probe ( dummy_probe) ;
280+ vec ! [ Candidate { source, result } ]
281+ } ;
282+
283+ let Some ( normalized_self_ty) =
284+ self . try_normalize_ty ( goal. param_env , goal. predicate . self_ty ( ) )
285+ else {
286+ debug ! ( "overflow while evaluating self type" ) ;
287+ return dummy_candidate ( self , Certainty :: OVERFLOW ) ;
288+ } ;
289+
290+ if normalized_self_ty. is_ty_var ( ) {
291+ debug ! ( "self type has been normalized to infer" ) ;
292+ return dummy_candidate ( self , Certainty :: AMBIGUOUS ) ;
314293 }
315- }
316294
317- /// Assemble candidates which apply to the self type. This only looks at candidate which
318- /// apply to the specific self type and ignores all others.
319- ///
320- /// Returns `None` if the self type is still ambiguous.
321- fn assemble_candidates_via_self_ty < G : GoalKind < ' tcx > > (
322- & mut self ,
323- goal : Goal < ' tcx , G > ,
324- num_steps : usize ,
325- ) -> Vec < Candidate < ' tcx > > {
295+ let goal =
296+ goal. with ( self . tcx ( ) , goal. predicate . with_self_ty ( self . tcx ( ) , normalized_self_ty) ) ;
326297 debug_assert_eq ! ( goal, self . resolve_vars_if_possible( goal) ) ;
327- if let Some ( ambig) = self . assemble_self_ty_infer_ambiguity_response ( goal) {
328- return vec ! [ ambig] ;
329- }
330298
331- let mut candidates = Vec :: new ( ) ;
299+ let mut candidates = vec ! [ ] ;
332300
333301 self . assemble_non_blanket_impl_candidates ( goal, & mut candidates) ;
334302
@@ -338,61 +306,15 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
338306
339307 self . assemble_object_bound_candidates ( goal, & mut candidates) ;
340308
341- self . assemble_candidates_after_normalizing_self_ty ( goal, & mut candidates, num_steps) ;
342- candidates
343- }
309+ self . assemble_unsize_to_dyn_candidate ( goal, & mut candidates) ;
344310
345- /// If the self type of a goal is an alias we first try to normalize the self type
346- /// and compute the candidates for the normalized self type in case that succeeds.
347- ///
348- /// These candidates are used in addition to the ones with the alias as a self type.
349- /// We do this to simplify both builtin candidates and for better performance.
350- ///
351- /// We generate the builtin candidates on the fly by looking at the self type, e.g.
352- /// add `FnPtr` candidates if the self type is a function pointer. Handling builtin
353- /// candidates while the self type is still an alias seems difficult. This is similar
354- /// to `try_structurally_resolve_type` during hir typeck (FIXME once implemented).
355- ///
356- /// Looking at all impls for some trait goal is prohibitively expensive. We therefore
357- /// only look at implementations with a matching self type. Because of this function,
358- /// we can avoid looking at all existing impls if the self type is an alias.
359- #[ instrument( level = "debug" , skip_all) ]
360- fn assemble_candidates_after_normalizing_self_ty < G : GoalKind < ' tcx > > (
361- & mut self ,
362- goal : Goal < ' tcx , G > ,
363- candidates : & mut Vec < Candidate < ' tcx > > ,
364- num_steps : usize ,
365- ) {
366- let tcx = self . tcx ( ) ;
367- let & ty:: Alias ( _, alias) = goal. predicate . self_ty ( ) . kind ( ) else { return } ;
368-
369- candidates. extend ( self . probe ( |_| ProbeKind :: NormalizedSelfTyAssembly ) . enter ( |ecx| {
370- if tcx. recursion_limit ( ) . value_within_limit ( num_steps) {
371- let normalized_ty = ecx. next_ty_infer ( ) ;
372- let normalizes_to_goal =
373- goal. with ( tcx, ty:: NormalizesTo { alias, term : normalized_ty. into ( ) } ) ;
374- ecx. add_goal ( GoalSource :: Misc , normalizes_to_goal) ;
375- if let Err ( NoSolution ) = ecx. try_evaluate_added_goals ( ) {
376- debug ! ( "self type normalization failed" ) ;
377- return vec ! [ ] ;
378- }
379- let normalized_ty = ecx. resolve_vars_if_possible ( normalized_ty) ;
380- debug ! ( ?normalized_ty, "self type normalized" ) ;
381- // NOTE: Alternatively we could call `evaluate_goal` here and only
382- // have a `Normalized` candidate. This doesn't work as long as we
383- // use `CandidateSource` in winnowing.
384- let goal = goal. with ( tcx, goal. predicate . with_self_ty ( tcx, normalized_ty) ) ;
385- ecx. assemble_candidates_via_self_ty ( goal, num_steps + 1 )
386- } else {
387- match ecx. evaluate_added_goals_and_make_canonical_response ( Certainty :: OVERFLOW ) {
388- Ok ( result) => vec ! [ Candidate {
389- source: CandidateSource :: BuiltinImpl ( BuiltinImplSource :: Misc ) ,
390- result,
391- } ] ,
392- Err ( NoSolution ) => vec ! [ ] ,
393- }
394- }
395- } ) ) ;
311+ self . assemble_blanket_impl_candidates ( goal, & mut candidates) ;
312+
313+ self . assemble_param_env_candidates ( goal, & mut candidates) ;
314+
315+ self . assemble_coherence_unknowable_candidates ( goal, & mut candidates) ;
316+
317+ candidates
396318 }
397319
398320 #[ instrument( level = "debug" , skip_all) ]
0 commit comments