@@ -42,8 +42,11 @@ mod typeck_root_ctxt;
42
42
mod upvar;
43
43
mod writeback;
44
44
45
+ use core:: ops:: ControlFlow ;
46
+
45
47
pub use coercion:: can_coerce;
46
48
use fn_ctxt:: FnCtxt ;
49
+ use rustc_data_structures:: fx:: FxHashSet ;
47
50
use rustc_data_structures:: unord:: UnordSet ;
48
51
use rustc_errors:: codes:: * ;
49
52
use rustc_errors:: { struct_span_code_err, Applicability , ErrorGuaranteed } ;
@@ -55,7 +58,7 @@ use rustc_hir_analysis::check::check_abi;
55
58
use rustc_hir_analysis:: hir_ty_lowering:: HirTyLowerer ;
56
59
use rustc_infer:: traits:: { ObligationCauseCode , ObligationInspector , WellFormedLoc } ;
57
60
use rustc_middle:: query:: Providers ;
58
- use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
61
+ use rustc_middle:: ty:: { self , Ty , TyCtxt , TypeSuperVisitable , TypeVisitable , TypeVisitor } ;
59
62
use rustc_middle:: { bug, span_bug} ;
60
63
use rustc_session:: config;
61
64
use rustc_span:: def_id:: LocalDefId ;
@@ -116,6 +119,41 @@ pub fn inspect_typeck<'tcx>(
116
119
typeck_with_fallback ( tcx, def_id, fallback, Some ( inspect) )
117
120
}
118
121
122
+ struct RecursiveHasErrorVisitor < ' tcx > {
123
+ tcx : TyCtxt < ' tcx > ,
124
+ // To avoid cycle when visiting recursive types.
125
+ visited_tys : FxHashSet < Ty < ' tcx > > ,
126
+ }
127
+
128
+ impl < ' tcx > RecursiveHasErrorVisitor < ' tcx > {
129
+ fn new ( tcx : TyCtxt < ' tcx > ) -> Self {
130
+ RecursiveHasErrorVisitor { tcx, visited_tys : Default :: default ( ) }
131
+ }
132
+ }
133
+
134
+ impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for RecursiveHasErrorVisitor < ' tcx > {
135
+ type Result = ControlFlow < ErrorGuaranteed > ;
136
+
137
+ fn visit_ty ( & mut self , t : Ty < ' tcx > ) -> Self :: Result {
138
+ self . visited_tys . insert ( t. clone ( ) ) ;
139
+ if let ty:: Adt ( def, args) = t. kind ( ) {
140
+ let field_tys: Vec < _ > = def. all_fields ( ) . map ( |f| f. ty ( self . tcx , args) ) . collect ( ) ;
141
+ for field_ty in field_tys {
142
+ if !self . visited_tys . contains ( & field_ty) {
143
+ // Force early return with `Break`.
144
+ // Visitors don't bail by default.
145
+ field_ty. visit_with ( self ) ?;
146
+ }
147
+ }
148
+ }
149
+ t. super_visit_with ( self )
150
+ }
151
+
152
+ fn visit_error ( & mut self , guar : ErrorGuaranteed ) -> Self :: Result {
153
+ ControlFlow :: Break ( guar)
154
+ }
155
+ }
156
+
119
157
#[ instrument( level = "debug" , skip( tcx, fallback, inspector) , ret) ]
120
158
fn typeck_with_fallback < ' tcx > (
121
159
tcx : TyCtxt < ' tcx > ,
@@ -168,6 +206,11 @@ fn typeck_with_fallback<'tcx>(
168
206
169
207
let expected_type = fcx. normalize ( body. value . span , expected_type) ;
170
208
209
+ let mut error_visitor = RecursiveHasErrorVisitor :: new ( tcx) ;
210
+ if let ControlFlow :: Break ( guar) = expected_type. visit_with ( & mut error_visitor) {
211
+ fcx. set_tainted_by_errors ( guar) ;
212
+ }
213
+
171
214
let wf_code = ObligationCauseCode :: WellFormed ( Some ( WellFormedLoc :: Ty ( def_id) ) ) ;
172
215
fcx. register_wf_obligation ( expected_type. into ( ) , body. value . span , wf_code) ;
173
216
0 commit comments