1
+ use rustc_errors:: StashKey ;
1
2
use rustc_hir:: def_id:: LocalDefId ;
2
3
use rustc_hir:: intravisit:: { self , Visitor } ;
3
4
use rustc_hir:: { self as hir, Expr , ImplItem , Item , Node , TraitItem } ;
@@ -59,7 +60,20 @@ pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: Local
59
60
}
60
61
}
61
62
62
- let Some ( hidden) = locator. found else {
63
+ if let Some ( hidden) = locator. found {
64
+ // Only check against typeck if we didn't already error
65
+ if !hidden. ty . references_error ( ) {
66
+ for concrete_type in locator. typeck_types {
67
+ if concrete_type. ty != tcx. erase_regions ( hidden. ty )
68
+ && !( concrete_type, hidden) . references_error ( )
69
+ {
70
+ hidden. report_mismatch ( & concrete_type, def_id, tcx) . emit ( ) ;
71
+ }
72
+ }
73
+ }
74
+
75
+ hidden. ty
76
+ } else {
63
77
let reported = tcx. sess . emit_err ( UnconstrainedOpaqueType {
64
78
span : tcx. def_span ( def_id) ,
65
79
name : tcx. item_name ( tcx. local_parent ( def_id) . to_def_id ( ) ) ,
@@ -70,21 +84,8 @@ pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: Local
70
84
_ => "item" ,
71
85
} ,
72
86
} ) ;
73
- return tcx. ty_error ( reported) ;
74
- } ;
75
-
76
- // Only check against typeck if we didn't already error
77
- if !hidden. ty . references_error ( ) {
78
- for concrete_type in locator. typeck_types {
79
- if concrete_type. ty != tcx. erase_regions ( hidden. ty )
80
- && !( concrete_type, hidden) . references_error ( )
81
- {
82
- hidden. report_mismatch ( & concrete_type, def_id, tcx) . emit ( ) ;
83
- }
84
- }
87
+ tcx. ty_error ( reported)
85
88
}
86
-
87
- hidden. ty
88
89
}
89
90
90
91
struct TaitConstraintLocator < ' tcx > {
@@ -130,13 +131,28 @@ impl TaitConstraintLocator<'_> {
130
131
self . found = Some ( ty:: OpaqueHiddenType { span : DUMMY_SP , ty : self . tcx . ty_error ( guar) } ) ;
131
132
return ;
132
133
}
133
- let Some ( & typeck_hidden_ty) = tables. concrete_opaque_types . get ( & self . def_id ) else {
134
+
135
+ let mut constrained = false ;
136
+ for ( & opaque_type_key, & hidden_type) in & tables. concrete_opaque_types {
137
+ if opaque_type_key. def_id != self . def_id {
138
+ continue ;
139
+ }
140
+ constrained = true ;
141
+ let concrete_type =
142
+ self . tcx . erase_regions ( hidden_type. remap_generic_params_to_declaration_params (
143
+ opaque_type_key,
144
+ self . tcx ,
145
+ true ,
146
+ ) ) ;
147
+ if self . typeck_types . iter ( ) . all ( |prev| prev. ty != concrete_type. ty ) {
148
+ self . typeck_types . push ( concrete_type) ;
149
+ }
150
+ }
151
+
152
+ if !constrained {
134
153
debug ! ( "no constraints in typeck results" ) ;
135
154
return ;
136
155
} ;
137
- if self . typeck_types . iter ( ) . all ( |prev| prev. ty != typeck_hidden_ty. ty ) {
138
- self . typeck_types . push ( typeck_hidden_ty) ;
139
- }
140
156
141
157
// Use borrowck to get the type with unerased regions.
142
158
let concrete_opaque_types = & self . tcx . mir_borrowck ( item_def_id) . concrete_opaque_types ;
@@ -190,45 +206,74 @@ impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> {
190
206
}
191
207
}
192
208
193
- pub ( super ) fn find_opaque_ty_constraints_for_rpit (
194
- tcx : TyCtxt < ' _ > ,
209
+ pub ( super ) fn find_opaque_ty_constraints_for_rpit < ' tcx > (
210
+ tcx : TyCtxt < ' tcx > ,
195
211
def_id : LocalDefId ,
196
212
owner_def_id : LocalDefId ,
197
213
) -> Ty < ' _ > {
198
- let concrete = tcx. mir_borrowck ( owner_def_id) . concrete_opaque_types . get ( & def_id) . copied ( ) ;
214
+ let tables = tcx. typeck ( owner_def_id) ;
215
+
216
+ // Check that all of the opaques we inferred during HIR are compatible.
217
+ // FIXME: We explicitly don't check that the types inferred during HIR
218
+ // typeck are compatible with the one that we infer during borrowck,
219
+ // because that one actually sometimes has consts evaluated eagerly so
220
+ // using strict type equality will fail.
221
+ let mut hir_opaque_ty: Option < ty:: OpaqueHiddenType < ' tcx > > = None ;
222
+ if tables. tainted_by_errors . is_none ( ) {
223
+ for ( & opaque_type_key, & hidden_type) in & tables. concrete_opaque_types {
224
+ if opaque_type_key. def_id != def_id {
225
+ continue ;
226
+ }
227
+ let concrete_type = tcx. erase_regions (
228
+ hidden_type. remap_generic_params_to_declaration_params ( opaque_type_key, tcx, true ) ,
229
+ ) ;
230
+ if let Some ( prev) = & mut hir_opaque_ty {
231
+ if concrete_type. ty != prev. ty && !( concrete_type, prev. ty ) . references_error ( ) {
232
+ prev. report_mismatch ( & concrete_type, def_id, tcx) . stash (
233
+ tcx. def_span ( opaque_type_key. def_id ) ,
234
+ StashKey :: OpaqueHiddenTypeMismatch ,
235
+ ) ;
236
+ }
237
+ } else {
238
+ hir_opaque_ty = Some ( concrete_type) ;
239
+ }
240
+ }
241
+ }
199
242
200
- if let Some ( concrete) = concrete {
243
+ let mir_opaque_ty = tcx. mir_borrowck ( owner_def_id) . concrete_opaque_types . get ( & def_id) . copied ( ) ;
244
+ if let Some ( mir_opaque_ty) = mir_opaque_ty {
201
245
let scope = tcx. hir ( ) . local_def_id_to_hir_id ( owner_def_id) ;
202
246
debug ! ( ?scope) ;
203
- let mut locator = RpitConstraintChecker { def_id, tcx, found : concrete } ;
247
+ let mut locator = RpitConstraintChecker { def_id, tcx, found : mir_opaque_ty } ;
204
248
205
249
match tcx. hir ( ) . get ( scope) {
206
250
Node :: Item ( it) => intravisit:: walk_item ( & mut locator, it) ,
207
251
Node :: ImplItem ( it) => intravisit:: walk_impl_item ( & mut locator, it) ,
208
252
Node :: TraitItem ( it) => intravisit:: walk_trait_item ( & mut locator, it) ,
209
253
other => bug ! ( "{:?} is not a valid scope for an opaque type item" , other) ,
210
254
}
211
- }
212
255
213
- concrete. map ( |concrete| concrete. ty ) . unwrap_or_else ( || {
214
- let table = tcx. typeck ( owner_def_id) ;
215
- if let Some ( guar) = table. tainted_by_errors {
216
- // Some error in the
217
- // owner fn prevented us from populating
256
+ mir_opaque_ty. ty
257
+ } else {
258
+ if let Some ( guar) = tables. tainted_by_errors {
259
+ // Some error in the owner fn prevented us from populating
218
260
// the `concrete_opaque_types` table.
219
261
tcx. ty_error ( guar)
220
262
} else {
221
- table. concrete_opaque_types . get ( & def_id) . map ( |ty| ty. ty ) . unwrap_or_else ( || {
263
+ // Fall back to the RPIT we inferred during HIR typeck
264
+ if let Some ( hir_opaque_ty) = hir_opaque_ty {
265
+ hir_opaque_ty. ty
266
+ } else {
222
267
// We failed to resolve the opaque type or it
223
268
// resolves to itself. We interpret this as the
224
269
// no values of the hidden type ever being constructed,
225
270
// so we can just make the hidden type be `!`.
226
271
// For backwards compatibility reasons, we fall back to
227
272
// `()` until we the diverging default is changed.
228
273
tcx. mk_diverging_default ( )
229
- } )
274
+ }
230
275
}
231
- } )
276
+ }
232
277
}
233
278
234
279
struct RpitConstraintChecker < ' tcx > {
0 commit comments