1
1
use rustc_data_structures:: fx:: FxHashSet ;
2
- use rustc_errors:: ErrorGuaranteed ;
3
2
use rustc_hir:: { def:: DefKind , def_id:: LocalDefId } ;
4
3
use rustc_middle:: query:: Providers ;
5
4
use rustc_middle:: ty:: util:: { CheckRegions , NotUniqueParam } ;
@@ -19,21 +18,26 @@ struct OpaqueTypeCollector<'tcx> {
19
18
20
19
/// Avoid infinite recursion due to recursive declarations.
21
20
seen : FxHashSet < LocalDefId > ,
21
+
22
+ span : Option < Span > ,
22
23
}
23
24
24
25
impl < ' tcx > OpaqueTypeCollector < ' tcx > {
25
- fn collect (
26
- tcx : TyCtxt < ' tcx > ,
27
- item : LocalDefId ,
28
- val : ty:: Binder < ' tcx , impl TypeVisitable < TyCtxt < ' tcx > > > ,
29
- ) -> Vec < LocalDefId > {
30
- let mut collector = Self { tcx, opaques : Vec :: new ( ) , item, seen : Default :: default ( ) } ;
31
- val. skip_binder ( ) . visit_with ( & mut collector) ;
32
- collector. opaques
26
+ fn new ( tcx : TyCtxt < ' tcx > , item : LocalDefId ) -> Self {
27
+ Self { tcx, opaques : Vec :: new ( ) , item, seen : Default :: default ( ) , span : None }
33
28
}
34
29
35
30
fn span ( & self ) -> Span {
36
- self . tcx . def_span ( self . item )
31
+ self . span . unwrap_or_else ( || {
32
+ self . tcx . def_ident_span ( self . item ) . unwrap_or_else ( || self . tcx . def_span ( self . item ) )
33
+ } )
34
+ }
35
+
36
+ fn visit_spanned ( & mut self , span : Span , value : impl TypeVisitable < TyCtxt < ' tcx > > ) {
37
+ let old = self . span ;
38
+ self . span = Some ( span) ;
39
+ value. visit_with ( self ) ;
40
+ self . span = old;
37
41
}
38
42
39
43
fn parent_trait_ref ( & self ) -> Option < ty:: TraitRef < ' tcx > > {
@@ -60,53 +64,57 @@ impl<'tcx> OpaqueTypeCollector<'tcx> {
60
64
}
61
65
62
66
impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for OpaqueTypeCollector < ' tcx > {
63
- type BreakTy = ErrorGuaranteed ;
64
-
65
67
#[ instrument( skip( self ) , ret, level = "trace" ) ]
66
- fn visit_ty ( & mut self , t : Ty < ' tcx > ) -> ControlFlow < ErrorGuaranteed > {
68
+ fn visit_ty ( & mut self , t : Ty < ' tcx > ) -> ControlFlow < !> {
69
+ t. super_visit_with ( self ) ?;
67
70
match t. kind ( ) {
68
71
ty:: Alias ( ty:: Opaque , alias_ty) if alias_ty. def_id . is_local ( ) => {
69
72
if !self . seen . insert ( alias_ty. def_id . expect_local ( ) ) {
70
73
return ControlFlow :: Continue ( ( ) ) ;
71
74
}
75
+
76
+ self . opaques . push ( alias_ty. def_id . expect_local ( ) ) ;
77
+
72
78
match self . tcx . uses_unique_generic_params ( alias_ty. substs , CheckRegions :: Bound ) {
73
79
Ok ( ( ) ) => {
74
80
// FIXME: implement higher kinded lifetime bounds on nested opaque types. They are not
75
81
// supported at all, so this is sound to do, but once we want to support them, you'll
76
82
// start seeing the error below.
77
83
78
- self . opaques . push ( alias_ty. def_id . expect_local ( ) ) ;
79
-
80
84
// Collect opaque types nested within the associated type bounds of this opaque type.
81
- for ( pred, _span) in self
85
+ // We use identity substs here, because we already know that the opaque type uses
86
+ // only generic parameters, and thus substituting would not give us more information.
87
+ for ( pred, span) in self
82
88
. tcx
83
89
. explicit_item_bounds ( alias_ty. def_id )
84
- . subst_iter_copied ( self . tcx , alias_ty . substs )
90
+ . subst_identity_iter_copied ( )
85
91
{
86
92
trace ! ( ?pred) ;
87
- pred . visit_with ( self ) ? ;
93
+ self . visit_spanned ( span , pred ) ;
88
94
}
89
-
90
- ControlFlow :: Continue ( ( ) )
91
95
}
92
96
Err ( NotUniqueParam :: NotParam ( arg) ) => {
93
- let err = self . tcx . sess . emit_err ( NotParam {
97
+ self . tcx . sess . emit_err ( NotParam {
94
98
arg,
95
99
span : self . span ( ) ,
96
100
opaque_span : self . tcx . def_span ( alias_ty. def_id ) ,
97
101
} ) ;
98
- ControlFlow :: Break ( err)
99
102
}
100
103
Err ( NotUniqueParam :: DuplicateParam ( arg) ) => {
101
- let err = self . tcx . sess . emit_err ( DuplicateArg {
104
+ self . tcx . sess . emit_err ( DuplicateArg {
102
105
arg,
103
106
span : self . span ( ) ,
104
107
opaque_span : self . tcx . def_span ( alias_ty. def_id ) ,
105
108
} ) ;
106
- ControlFlow :: Break ( err)
107
109
}
108
110
}
109
111
}
112
+ ty:: Alias ( ty:: Weak , alias_ty) if alias_ty. def_id . is_local ( ) => {
113
+ self . tcx
114
+ . type_of ( alias_ty. def_id )
115
+ . subst ( self . tcx , alias_ty. substs )
116
+ . visit_with ( self ) ?;
117
+ }
110
118
ty:: Alias ( ty:: Projection , alias_ty) => {
111
119
// This avoids having to do normalization of `Self::AssocTy` by only
112
120
// supporting the case of a method defining opaque types from assoc types
@@ -136,26 +144,44 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
136
144
ty:: InternalSubsts :: identity_for_item ( self . tcx , parent) ,
137
145
) ;
138
146
139
- if !check_substs_compatible ( self . tcx , assoc, impl_substs) {
147
+ if check_substs_compatible ( self . tcx , assoc, impl_substs) {
148
+ return self
149
+ . tcx
150
+ . type_of ( assoc. def_id )
151
+ . subst ( self . tcx , impl_substs)
152
+ . visit_with ( self ) ;
153
+ } else {
140
154
self . tcx . sess . delay_span_bug (
141
155
self . tcx . def_span ( assoc. def_id ) ,
142
156
"item had incorrect substs" ,
143
157
) ;
144
- return ControlFlow :: Continue ( ( ) ) ;
145
158
}
146
-
147
- return self
148
- . tcx
149
- . type_of ( assoc. def_id )
150
- . subst ( self . tcx , impl_substs)
151
- . visit_with ( self ) ;
152
159
}
153
160
}
154
161
}
155
- t. super_visit_with ( self )
156
162
}
157
- _ => t. super_visit_with ( self ) ,
163
+ ty:: Adt ( def, _) if def. did ( ) . is_local ( ) => {
164
+ if !self . seen . insert ( def. did ( ) . expect_local ( ) ) {
165
+ return ControlFlow :: Continue ( ( ) ) ;
166
+ }
167
+ for variant in def. variants ( ) . iter ( ) {
168
+ for field in variant. fields . iter ( ) {
169
+ // Don't use the `ty::Adt` substs, we either
170
+ // * found the opaque in the substs
171
+ // * will find the opaque in the unsubstituted fields
172
+ // The only other situation that can occur is that after substituting,
173
+ // some projection resolves to an opaque that we would have otherwise
174
+ // not found. While we could substitute and walk those, that would mean we
175
+ // would have to walk all substitutions of an Adt, which can quickly
176
+ // degenerate into looking at an exponential number of types.
177
+ let ty = self . tcx . type_of ( field. did ) . subst_identity ( ) ;
178
+ self . visit_spanned ( self . tcx . def_span ( field. did ) , ty) ;
179
+ }
180
+ }
181
+ }
182
+ _ => trace ! ( kind=?t. kind( ) ) ,
158
183
}
184
+ ControlFlow :: Continue ( ( ) )
159
185
}
160
186
}
161
187
@@ -166,21 +192,29 @@ fn opaque_types_defined_by<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx [
166
192
match kind {
167
193
// We're also doing this for `AssocTy` for the wf checks in `check_opaque_meets_bounds`
168
194
DefKind :: Fn | DefKind :: AssocFn | DefKind :: AssocTy | DefKind :: AssocConst => {
169
- let defined_opaques = match kind {
170
- DefKind :: Fn => {
171
- OpaqueTypeCollector :: collect ( tcx, item, tcx. fn_sig ( item) . subst_identity ( ) )
195
+ let mut collector = OpaqueTypeCollector :: new ( tcx, item) ;
196
+ match kind {
197
+ // Walk over the signature of the function-like to find the opaques.
198
+ DefKind :: AssocFn | DefKind :: Fn => {
199
+ let ty_sig = tcx. fn_sig ( item) . subst_identity ( ) ;
200
+ let hir_sig = tcx. hir ( ) . get_by_def_id ( item) . fn_sig ( ) . unwrap ( ) ;
201
+ // Walk over the inputs and outputs manually in order to get good spans for them.
202
+ collector. visit_spanned ( hir_sig. decl . output . span ( ) , ty_sig. output ( ) ) ;
203
+ for ( hir, ty) in hir_sig. decl . inputs . iter ( ) . zip ( ty_sig. inputs ( ) . iter ( ) ) {
204
+ collector. visit_spanned ( hir. span , ty. map_bound ( |x| * x) ) ;
205
+ }
172
206
}
173
- DefKind :: AssocFn => {
174
- OpaqueTypeCollector :: collect ( tcx, item, tcx. fn_sig ( item) . subst_identity ( ) )
207
+ // Walk over the type of the item to find opaques.
208
+ DefKind :: AssocTy | DefKind :: AssocConst => {
209
+ let span = match tcx. hir ( ) . get_by_def_id ( item) . ty ( ) {
210
+ Some ( ty) => ty. span ,
211
+ _ => tcx. def_span ( item) ,
212
+ } ;
213
+ collector. visit_spanned ( span, tcx. type_of ( item) . subst_identity ( ) ) ;
175
214
}
176
- DefKind :: AssocTy | DefKind :: AssocConst => OpaqueTypeCollector :: collect (
177
- tcx,
178
- item,
179
- ty:: Binder :: dummy ( tcx. type_of ( item) . subst_identity ( ) ) ,
180
- ) ,
181
215
_ => unreachable ! ( ) ,
182
- } ;
183
- tcx. arena . alloc_from_iter ( defined_opaques )
216
+ }
217
+ tcx. arena . alloc_from_iter ( collector . opaques )
184
218
}
185
219
DefKind :: Mod
186
220
| DefKind :: Struct
@@ -209,7 +243,9 @@ fn opaque_types_defined_by<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx [
209
243
| DefKind :: GlobalAsm
210
244
| DefKind :: Impl { .. }
211
245
| DefKind :: Closure
212
- | DefKind :: Generator => & [ ] ,
246
+ | DefKind :: Generator => {
247
+ span_bug ! ( tcx. def_span( item) , "{kind:?} is type checked as part of its parent" )
248
+ }
213
249
}
214
250
}
215
251
0 commit comments