@@ -21,6 +21,64 @@ pub fn test_opaque_hidden_types(tcx: TyCtxt<'_>) {
21
21
}
22
22
}
23
23
24
+ /// Checks "defining uses" of opaque `impl Trait` in associated types.
25
+ /// These can only be defined by associated items of the same trait.
26
+ #[ instrument( skip( tcx) , level = "debug" ) ]
27
+ pub ( super ) fn find_opaque_ty_constraints_for_impl_trait_in_assoc_type (
28
+ tcx : TyCtxt < ' _ > ,
29
+ def_id : LocalDefId ,
30
+ ) -> Ty < ' _ > {
31
+ let mut parent_def_id = def_id;
32
+ while tcx. def_kind ( parent_def_id) == def:: DefKind :: OpaqueTy {
33
+ // Account for `type Alias = impl Trait<Foo = impl Trait>;` (#116031)
34
+ parent_def_id = tcx. local_parent ( parent_def_id) ;
35
+ }
36
+ let impl_def_id = tcx. local_parent ( parent_def_id) ;
37
+ match tcx. def_kind ( impl_def_id) {
38
+ DefKind :: Impl { of_trait : true } => { }
39
+ // Fixme(inherent_associated_types): what is even the expected behaviour of these?
40
+ DefKind :: Impl { of_trait : false } => {
41
+ return find_opaque_ty_constraints_for_tait ( tcx, def_id) ;
42
+ }
43
+ other => bug ! ( "invalid impl trait in assoc type parent: {other:?}" ) ,
44
+ }
45
+
46
+ let mut locator = TaitConstraintLocator { def_id, tcx, found : None , typeck_types : vec ! [ ] } ;
47
+
48
+ for & assoc_id in tcx. associated_item_def_ids ( impl_def_id) {
49
+ let assoc = tcx. associated_item ( assoc_id) ;
50
+ match assoc. kind {
51
+ ty:: AssocKind :: Const | ty:: AssocKind :: Fn => {
52
+ locator. check ( assoc_id. expect_local ( ) , true )
53
+ }
54
+ // Associated types don't have bodies, so they can't constrain hidden types
55
+ ty:: AssocKind :: Type => { }
56
+ }
57
+ }
58
+
59
+ if let Some ( hidden) = locator. found {
60
+ // Only check against typeck if we didn't already error
61
+ if !hidden. ty . references_error ( ) {
62
+ for concrete_type in locator. typeck_types {
63
+ if concrete_type. ty != tcx. erase_regions ( hidden. ty )
64
+ && !( concrete_type, hidden) . references_error ( )
65
+ {
66
+ hidden. report_mismatch ( & concrete_type, def_id, tcx) . emit ( ) ;
67
+ }
68
+ }
69
+ }
70
+
71
+ hidden. ty
72
+ } else {
73
+ let reported = tcx. dcx ( ) . emit_err ( UnconstrainedOpaqueType {
74
+ span : tcx. def_span ( def_id) ,
75
+ name : tcx. item_name ( parent_def_id. to_def_id ( ) ) ,
76
+ what : "impl" ,
77
+ } ) ;
78
+ Ty :: new_error ( tcx, reported)
79
+ }
80
+ }
81
+
24
82
/// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions
25
83
/// laid for "higher-order pattern unification".
26
84
/// This ensures that inference is tractable.
@@ -128,7 +186,7 @@ struct TaitConstraintLocator<'tcx> {
128
186
129
187
impl TaitConstraintLocator < ' _ > {
130
188
#[ instrument( skip( self ) , level = "debug" ) ]
131
- fn check ( & mut self , item_def_id : LocalDefId ) {
189
+ fn check ( & mut self , item_def_id : LocalDefId , impl_trait_in_assoc_type : bool ) {
132
190
// Don't try to check items that cannot possibly constrain the type.
133
191
if !self . tcx . has_typeck_results ( item_def_id) {
134
192
debug ! ( "no constraint: no typeck results" ) ;
@@ -158,7 +216,12 @@ impl TaitConstraintLocator<'_> {
158
216
continue ;
159
217
}
160
218
constrained = true ;
161
- if !self . tcx . opaque_types_defined_by ( item_def_id) . contains ( & self . def_id ) {
219
+ let opaque_types_defined_by = if impl_trait_in_assoc_type {
220
+ self . tcx . impl_trait_in_assoc_types_defined_by ( item_def_id)
221
+ } else {
222
+ self . tcx . opaque_types_defined_by ( item_def_id)
223
+ } ;
224
+ if !opaque_types_defined_by. contains ( & self . def_id ) {
162
225
self . tcx . dcx ( ) . emit_err ( TaitForwardCompat {
163
226
span : hidden_type. span ,
164
227
item_span : self
@@ -216,29 +279,29 @@ impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> {
216
279
}
217
280
fn visit_expr ( & mut self , ex : & ' tcx Expr < ' tcx > ) {
218
281
if let hir:: ExprKind :: Closure ( closure) = ex. kind {
219
- self . check ( closure. def_id ) ;
282
+ self . check ( closure. def_id , false ) ;
220
283
}
221
284
intravisit:: walk_expr ( self , ex) ;
222
285
}
223
286
fn visit_item ( & mut self , it : & ' tcx Item < ' tcx > ) {
224
287
trace ! ( ?it. owner_id) ;
225
288
// The opaque type itself or its children are not within its reveal scope.
226
289
if it. owner_id . def_id != self . def_id {
227
- self . check ( it. owner_id . def_id ) ;
290
+ self . check ( it. owner_id . def_id , false ) ;
228
291
intravisit:: walk_item ( self , it) ;
229
292
}
230
293
}
231
294
fn visit_impl_item ( & mut self , it : & ' tcx ImplItem < ' tcx > ) {
232
295
trace ! ( ?it. owner_id) ;
233
296
// The opaque type itself or its children are not within its reveal scope.
234
297
if it. owner_id . def_id != self . def_id {
235
- self . check ( it. owner_id . def_id ) ;
298
+ self . check ( it. owner_id . def_id , false ) ;
236
299
intravisit:: walk_impl_item ( self , it) ;
237
300
}
238
301
}
239
302
fn visit_trait_item ( & mut self , it : & ' tcx TraitItem < ' tcx > ) {
240
303
trace ! ( ?it. owner_id) ;
241
- self . check ( it. owner_id . def_id ) ;
304
+ self . check ( it. owner_id . def_id , false ) ;
242
305
intravisit:: walk_trait_item ( self , it) ;
243
306
}
244
307
fn visit_foreign_item ( & mut self , it : & ' tcx hir:: ForeignItem < ' tcx > ) {
0 commit comments