@@ -3,10 +3,13 @@ use rustc_infer::infer::TyCtxtInferExt;
33use rustc_middle:: query:: Providers ;
44use rustc_middle:: ty:: { ParamEnvAnd , TyCtxt } ;
55use rustc_trait_selection:: infer:: InferCtxtBuilderExt ;
6+ use rustc_trait_selection:: traits:: error_reporting:: TypeErrCtxtExt ;
67use rustc_trait_selection:: traits:: query:: {
78 normalize:: NormalizationResult , CanonicalProjectionGoal , NoSolution ,
89} ;
9- use rustc_trait_selection:: traits:: { self , ObligationCause , SelectionContext } ;
10+ use rustc_trait_selection:: traits:: {
11+ self , FulfillmentErrorCode , ObligationCause , SelectionContext ,
12+ } ;
1013use std:: sync:: atomic:: Ordering ;
1114
1215pub ( crate ) fn provide ( p : & mut Providers ) {
@@ -40,6 +43,27 @@ fn normalize_projection_ty<'tcx>(
4043 & mut obligations,
4144 ) ;
4245 ocx. register_obligations ( obligations) ;
46+ // #112047: With projections and opaques, we are able to create opaques that
47+ // are recursive (given some substitution of the opaque's type variables).
48+ // In that case, we may only realize a cycle error when calling
49+ // `normalize_erasing_regions` in mono.
50+ if !ocx. infcx . next_trait_solver ( ) {
51+ let errors = ocx. select_where_possible ( ) ;
52+ if !errors. is_empty ( ) {
53+ // Rustdoc may attempt to normalize type alias types which are not
54+ // well-formed. Rustdoc also normalizes types that are just not
55+ // well-formed, since we don't do as much HIR analysis (checking
56+ // that impl vars are constrained by the signature, for example).
57+ if !tcx. sess . opts . actually_rustdoc {
58+ for error in & errors {
59+ if let FulfillmentErrorCode :: CodeCycle ( cycle) = & error. code {
60+ ocx. infcx . err_ctxt ( ) . report_overflow_obligation_cycle ( cycle) ;
61+ }
62+ }
63+ }
64+ return Err ( NoSolution ) ;
65+ }
66+ }
4367 // FIXME(associated_const_equality): All users of normalize_projection_ty expected
4468 // a type, but there is the possibility it could've been a const now. Maybe change
4569 // it to a Term later?
0 commit comments