]>
Commit | Line | Data |
---|---|---|
1b1a35ee | 1 | use rustc_data_structures::fx::FxIndexSet; |
dfeec247 | 2 | use rustc_hir as hir; |
5099ac24 | 3 | use rustc_hir::def_id::DefId; |
29967ef6 | 4 | use rustc_middle::ty::subst::Subst; |
064997fb | 5 | use rustc_middle::ty::{self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt}; |
ba9703b0 | 6 | use rustc_trait_selection::traits; |
dfeec247 | 7 | |
74b04a01 XL |
8 | fn sized_constraint_for_ty<'tcx>( |
9 | tcx: TyCtxt<'tcx>, | |
5e7ed085 | 10 | adtdef: ty::AdtDef<'tcx>, |
74b04a01 XL |
11 | ty: Ty<'tcx>, |
12 | ) -> Vec<Ty<'tcx>> { | |
923072b8 | 13 | use rustc_type_ir::sty::TyKind::*; |
dfeec247 | 14 | |
1b1a35ee | 15 | let result = match ty.kind() { |
dfeec247 XL |
16 | Bool | Char | Int(..) | Uint(..) | Float(..) | RawPtr(..) | Ref(..) | FnDef(..) |
17 | | FnPtr(_) | Array(..) | Closure(..) | Generator(..) | Never => vec![], | |
18 | ||
f035d41b | 19 | Str | Dynamic(..) | Slice(_) | Foreign(..) | Error(_) | GeneratorWitness(..) => { |
dfeec247 XL |
20 | // these are never sized - return the target type |
21 | vec![ty] | |
22 | } | |
23 | ||
24 | Tuple(ref tys) => match tys.last() { | |
25 | None => vec![], | |
5e7ed085 | 26 | Some(&ty) => sized_constraint_for_ty(tcx, adtdef, ty), |
dfeec247 XL |
27 | }, |
28 | ||
29 | Adt(adt, substs) => { | |
30 | // recursive case | |
31 | let adt_tys = adt.sized_constraint(tcx); | |
32 | debug!("sized_constraint_for_ty({:?}) intermediate = {:?}", ty, adt_tys); | |
33 | adt_tys | |
064997fb | 34 | .0 |
dfeec247 | 35 | .iter() |
064997fb | 36 | .map(|ty| adt_tys.rebind(*ty).subst(tcx, substs)) |
dfeec247 XL |
37 | .flat_map(|ty| sized_constraint_for_ty(tcx, adtdef, ty)) |
38 | .collect() | |
39 | } | |
40 | ||
41 | Projection(..) | Opaque(..) => { | |
42 | // must calculate explicitly. | |
43 | // FIXME: consider special-casing always-Sized projections | |
44 | vec![ty] | |
45 | } | |
46 | ||
dfeec247 XL |
47 | Param(..) => { |
48 | // perf hack: if there is a `T: Sized` bound, then | |
49 | // we know that `T` is Sized and do not need to check | |
50 | // it on the impl. | |
51 | ||
5e7ed085 | 52 | let Some(sized_trait) = tcx.lang_items().sized_trait() else { return vec![ty] }; |
dfeec247 XL |
53 | let sized_predicate = ty::Binder::dummy(ty::TraitRef { |
54 | def_id: sized_trait, | |
55 | substs: tcx.mk_substs_trait(ty, &[]), | |
56 | }) | |
57 | .without_const() | |
f9f354fc | 58 | .to_predicate(tcx); |
5e7ed085 | 59 | let predicates = tcx.predicates_of(adtdef.did()).predicates; |
dfeec247 XL |
60 | if predicates.iter().any(|(p, _)| *p == sized_predicate) { vec![] } else { vec![ty] } |
61 | } | |
62 | ||
63 | Placeholder(..) | Bound(..) | Infer(..) => { | |
64 | bug!("unexpected type `{:?}` in sized_constraint_for_ty", ty) | |
65 | } | |
66 | }; | |
67 | debug!("sized_constraint_for_ty({:?}) = {:?}", ty, result); | |
68 | result | |
69 | } | |
70 | ||
ba9703b0 | 71 | fn impl_defaultness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Defaultness { |
064997fb FG |
72 | match tcx.hir().get_by_def_id(def_id.expect_local()) { |
73 | hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) => impl_.defaultness, | |
74 | hir::Node::ImplItem(hir::ImplItem { defaultness, .. }) | |
75 | | hir::Node::TraitItem(hir::TraitItem { defaultness, .. }) => *defaultness, | |
76 | node => { | |
77 | bug!("`impl_defaultness` called on {:?}", node); | |
78 | } | |
ba9703b0 XL |
79 | } |
80 | } | |
81 | ||
dfeec247 XL |
82 | /// Calculates the `Sized` constraint. |
83 | /// | |
84 | /// In fact, there are only a few options for the types in the constraint: | |
85 | /// - an obviously-unsized type | |
86 | /// - a type parameter or projection whose Sizedness can't be known | |
87 | /// - a tuple of type parameters or projections, if there are multiple | |
88 | /// such. | |
94222f64 | 89 | /// - an Error, if a type contained itself. The representability |
dfeec247 XL |
90 | /// check should catch this case. |
91 | fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtSizedConstraint<'_> { | |
92 | let def = tcx.adt_def(def_id); | |
93 | ||
94 | let result = tcx.mk_type_list( | |
5e7ed085 | 95 | def.variants() |
dfeec247 XL |
96 | .iter() |
97 | .flat_map(|v| v.fields.last()) | |
98 | .flat_map(|f| sized_constraint_for_ty(tcx, def, tcx.type_of(f.did))), | |
99 | ); | |
100 | ||
101 | debug!("adt_sized_constraint: {:?} => {:?}", def, result); | |
102 | ||
103 | ty::AdtSizedConstraint(result) | |
104 | } | |
105 | ||
dfeec247 | 106 | /// See `ParamEnv` struct definition for details. |
c295e0f8 | 107 | #[instrument(level = "debug", skip(tcx))] |
dfeec247 XL |
108 | fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { |
109 | // The param_env of an impl Trait type is its defining function's param_env | |
110 | if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) { | |
a2a8927a | 111 | return param_env(tcx, parent.to_def_id()); |
dfeec247 XL |
112 | } |
113 | // Compute the bounds on Self and the type parameters. | |
114 | ||
1b1a35ee | 115 | let ty::InstantiatedPredicates { mut predicates, .. } = |
dfeec247 XL |
116 | tcx.predicates_of(def_id).instantiate_identity(tcx); |
117 | ||
118 | // Finally, we have to normalize the bounds in the environment, in | |
119 | // case they contain any associated type projections. This process | |
120 | // can yield errors if the put in illegal associated types, like | |
121 | // `<i32 as Foo>::Bar` where `i32` does not implement `Foo`. We | |
122 | // report these errors right here; this doesn't actually feel | |
123 | // right to me, because constructing the environment feels like a | |
94222f64 | 124 | // kind of an "idempotent" action, but I'm not sure where would be |
dfeec247 XL |
125 | // a better place. In practice, we construct environments for |
126 | // every fn once during type checking, and we'll abort if there | |
5099ac24 | 127 | // are any errors at that point, so outside of type inference you can be |
dfeec247 XL |
128 | // sure that this will succeed without errors anyway. |
129 | ||
064997fb | 130 | if tcx.sess.opts.unstable_opts.chalk { |
1b1a35ee XL |
131 | let environment = well_formed_types_in_env(tcx, def_id); |
132 | predicates.extend(environment); | |
133 | } | |
134 | ||
a2a8927a XL |
135 | let local_did = def_id.as_local(); |
136 | let hir_id = local_did.map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id)); | |
137 | ||
138 | let constness = match hir_id { | |
139 | Some(hir_id) => match tcx.hir().get(hir_id) { | |
140 | hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. }) | |
923072b8 | 141 | if tcx.is_const_default_method(def_id) => |
a2a8927a XL |
142 | { |
143 | hir::Constness::Const | |
144 | } | |
145 | ||
146 | hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(..), .. }) | |
147 | | hir::Node::Item(hir::Item { kind: hir::ItemKind::Static(..), .. }) | |
148 | | hir::Node::TraitItem(hir::TraitItem { | |
149 | kind: hir::TraitItemKind::Const(..), .. | |
150 | }) | |
151 | | hir::Node::AnonConst(_) | |
152 | | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) | |
153 | | hir::Node::ImplItem(hir::ImplItem { | |
154 | kind: | |
155 | hir::ImplItemKind::Fn( | |
156 | hir::FnSig { | |
157 | header: hir::FnHeader { constness: hir::Constness::Const, .. }, | |
158 | .. | |
159 | }, | |
160 | .., | |
161 | ), | |
162 | .. | |
163 | }) => hir::Constness::Const, | |
164 | ||
165 | hir::Node::ImplItem(hir::ImplItem { | |
166 | kind: hir::ImplItemKind::TyAlias(..) | hir::ImplItemKind::Fn(..), | |
167 | .. | |
168 | }) => { | |
169 | let parent_hir_id = tcx.hir().get_parent_node(hir_id); | |
170 | match tcx.hir().get(parent_hir_id) { | |
171 | hir::Node::Item(hir::Item { | |
172 | kind: hir::ItemKind::Impl(hir::Impl { constness, .. }), | |
173 | .. | |
174 | }) => *constness, | |
175 | _ => span_bug!( | |
176 | tcx.def_span(parent_hir_id.owner), | |
177 | "impl item's parent node is not an impl", | |
178 | ), | |
179 | } | |
180 | } | |
181 | ||
182 | hir::Node::Item(hir::Item { | |
183 | kind: | |
184 | hir::ItemKind::Fn(hir::FnSig { header: hir::FnHeader { constness, .. }, .. }, ..), | |
185 | .. | |
186 | }) | |
187 | | hir::Node::TraitItem(hir::TraitItem { | |
188 | kind: | |
189 | hir::TraitItemKind::Fn( | |
190 | hir::FnSig { header: hir::FnHeader { constness, .. }, .. }, | |
191 | .., | |
192 | ), | |
193 | .. | |
194 | }) | |
195 | | hir::Node::Item(hir::Item { | |
196 | kind: hir::ItemKind::Impl(hir::Impl { constness, .. }), | |
197 | .. | |
198 | }) => *constness, | |
199 | ||
200 | _ => hir::Constness::NotConst, | |
201 | }, | |
202 | None => hir::Constness::NotConst, | |
203 | }; | |
204 | ||
205 | let unnormalized_env = ty::ParamEnv::new( | |
206 | tcx.intern_predicates(&predicates), | |
207 | traits::Reveal::UserFacing, | |
208 | constness, | |
209 | ); | |
dfeec247 | 210 | |
064997fb FG |
211 | let body_id = |
212 | local_did.and_then(|id| tcx.hir().maybe_body_owned_by(id).map(|body| body.hir_id)); | |
213 | let body_id = match body_id { | |
214 | Some(id) => id, | |
215 | None if hir_id.is_some() => hir_id.unwrap(), | |
216 | _ => hir::CRATE_HIR_ID, | |
217 | }; | |
218 | ||
dfeec247 | 219 | let cause = traits::ObligationCause::misc(tcx.def_span(def_id), body_id); |
064997fb | 220 | traits::normalize_param_env_or_error(tcx, unnormalized_env, cause) |
dfeec247 XL |
221 | } |
222 | ||
1b1a35ee XL |
223 | /// Elaborate the environment. |
224 | /// | |
225 | /// Collect a list of `Predicate`'s used for building the `ParamEnv`. Adds `TypeWellFormedFromEnv`'s | |
226 | /// that are assumed to be well-formed (because they come from the environment). | |
227 | /// | |
228 | /// Used only in chalk mode. | |
229 | fn well_formed_types_in_env<'tcx>( | |
230 | tcx: TyCtxt<'tcx>, | |
231 | def_id: DefId, | |
232 | ) -> &'tcx ty::List<Predicate<'tcx>> { | |
233 | use rustc_hir::{ForeignItemKind, ImplItemKind, ItemKind, Node, TraitItemKind}; | |
234 | use rustc_middle::ty::subst::GenericArgKind; | |
235 | ||
236 | debug!("environment(def_id = {:?})", def_id); | |
237 | ||
238 | // The environment of an impl Trait type is its defining function's environment. | |
239 | if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) { | |
a2a8927a | 240 | return well_formed_types_in_env(tcx, parent.to_def_id()); |
1b1a35ee XL |
241 | } |
242 | ||
243 | // Compute the bounds on `Self` and the type parameters. | |
244 | let ty::InstantiatedPredicates { predicates, .. } = | |
245 | tcx.predicates_of(def_id).instantiate_identity(tcx); | |
246 | ||
247 | let clauses = predicates.into_iter(); | |
248 | ||
249 | if !def_id.is_local() { | |
250 | return ty::List::empty(); | |
251 | } | |
5099ac24 | 252 | let node = tcx.hir().get_by_def_id(def_id.expect_local()); |
1b1a35ee XL |
253 | |
254 | enum NodeKind { | |
255 | TraitImpl, | |
256 | InherentImpl, | |
257 | Fn, | |
258 | Other, | |
fc512014 | 259 | } |
1b1a35ee XL |
260 | |
261 | let node_kind = match node { | |
262 | Node::TraitItem(item) => match item.kind { | |
263 | TraitItemKind::Fn(..) => NodeKind::Fn, | |
264 | _ => NodeKind::Other, | |
265 | }, | |
266 | ||
267 | Node::ImplItem(item) => match item.kind { | |
268 | ImplItemKind::Fn(..) => NodeKind::Fn, | |
269 | _ => NodeKind::Other, | |
270 | }, | |
271 | ||
272 | Node::Item(item) => match item.kind { | |
5869c6ff XL |
273 | ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => NodeKind::TraitImpl, |
274 | ItemKind::Impl(hir::Impl { of_trait: None, .. }) => NodeKind::InherentImpl, | |
1b1a35ee XL |
275 | ItemKind::Fn(..) => NodeKind::Fn, |
276 | _ => NodeKind::Other, | |
277 | }, | |
278 | ||
279 | Node::ForeignItem(item) => match item.kind { | |
280 | ForeignItemKind::Fn(..) => NodeKind::Fn, | |
281 | _ => NodeKind::Other, | |
282 | }, | |
283 | ||
284 | // FIXME: closures? | |
285 | _ => NodeKind::Other, | |
286 | }; | |
287 | ||
288 | // FIXME(eddyb) isn't the unordered nature of this a hazard? | |
289 | let mut inputs = FxIndexSet::default(); | |
290 | ||
291 | match node_kind { | |
292 | // In a trait impl, we assume that the header trait ref and all its | |
293 | // constituents are well-formed. | |
294 | NodeKind::TraitImpl => { | |
295 | let trait_ref = tcx.impl_trait_ref(def_id).expect("not an impl"); | |
296 | ||
297 | // FIXME(chalk): this has problems because of late-bound regions | |
298 | //inputs.extend(trait_ref.substs.iter().flat_map(|arg| arg.walk())); | |
299 | inputs.extend(trait_ref.substs.iter()); | |
300 | } | |
301 | ||
302 | // In an inherent impl, we assume that the receiver type and all its | |
303 | // constituents are well-formed. | |
304 | NodeKind::InherentImpl => { | |
305 | let self_ty = tcx.type_of(def_id); | |
5099ac24 | 306 | inputs.extend(self_ty.walk()); |
1b1a35ee XL |
307 | } |
308 | ||
309 | // In an fn, we assume that the arguments and all their constituents are | |
310 | // well-formed. | |
311 | NodeKind::Fn => { | |
312 | let fn_sig = tcx.fn_sig(def_id); | |
fc512014 | 313 | let fn_sig = tcx.liberate_late_bound_regions(def_id, fn_sig); |
1b1a35ee | 314 | |
5099ac24 | 315 | inputs.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk())); |
1b1a35ee XL |
316 | } |
317 | ||
318 | NodeKind::Other => (), | |
319 | } | |
320 | let input_clauses = inputs.into_iter().filter_map(|arg| { | |
321 | match arg.unpack() { | |
322 | GenericArgKind::Type(ty) => { | |
5869c6ff XL |
323 | let binder = Binder::dummy(PredicateKind::TypeWellFormedFromEnv(ty)); |
324 | Some(tcx.mk_predicate(binder)) | |
1b1a35ee XL |
325 | } |
326 | ||
327 | // FIXME(eddyb) no WF conditions from lifetimes? | |
328 | GenericArgKind::Lifetime(_) => None, | |
329 | ||
330 | // FIXME(eddyb) support const generics in Chalk | |
331 | GenericArgKind::Const(_) => None, | |
332 | } | |
333 | }); | |
334 | ||
335 | tcx.mk_predicates(clauses.chain(input_clauses)) | |
336 | } | |
337 | ||
3dfed10e XL |
338 | fn param_env_reveal_all_normalized(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { |
339 | tcx.param_env(def_id).with_reveal_all_normalized(tcx) | |
340 | } | |
341 | ||
dfeec247 XL |
342 | fn instance_def_size_estimate<'tcx>( |
343 | tcx: TyCtxt<'tcx>, | |
344 | instance_def: ty::InstanceDef<'tcx>, | |
345 | ) -> usize { | |
346 | use ty::InstanceDef; | |
347 | ||
348 | match instance_def { | |
349 | InstanceDef::Item(..) | InstanceDef::DropGlue(..) => { | |
350 | let mir = tcx.instance_mir(instance_def); | |
136023e0 | 351 | mir.basic_blocks().iter().map(|bb| bb.statements.len() + 1).sum() |
dfeec247 XL |
352 | } |
353 | // Estimate the size of other compiler-generated shims to be 1. | |
354 | _ => 1, | |
355 | } | |
356 | } | |
357 | ||
358 | /// If `def_id` is an issue 33140 hack impl, returns its self type; otherwise, returns `None`. | |
359 | /// | |
f9f354fc | 360 | /// See [`ty::ImplOverlapKind::Issue33140`] for more details. |
dfeec247 XL |
361 | fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Ty<'_>> { |
362 | debug!("issue33140_self_ty({:?})", def_id); | |
363 | ||
364 | let trait_ref = tcx | |
365 | .impl_trait_ref(def_id) | |
366 | .unwrap_or_else(|| bug!("issue33140_self_ty called on inherent impl {:?}", def_id)); | |
367 | ||
368 | debug!("issue33140_self_ty({:?}), trait-ref={:?}", def_id, trait_ref); | |
369 | ||
370 | let is_marker_like = tcx.impl_polarity(def_id) == ty::ImplPolarity::Positive | |
371 | && tcx.associated_item_def_ids(trait_ref.def_id).is_empty(); | |
372 | ||
373 | // Check whether these impls would be ok for a marker trait. | |
374 | if !is_marker_like { | |
375 | debug!("issue33140_self_ty - not marker-like!"); | |
376 | return None; | |
377 | } | |
378 | ||
379 | // impl must be `impl Trait for dyn Marker1 + Marker2 + ...` | |
380 | if trait_ref.substs.len() != 1 { | |
381 | debug!("issue33140_self_ty - impl has substs!"); | |
382 | return None; | |
383 | } | |
384 | ||
385 | let predicates = tcx.predicates_of(def_id); | |
386 | if predicates.parent.is_some() || !predicates.predicates.is_empty() { | |
387 | debug!("issue33140_self_ty - impl has predicates {:?}!", predicates); | |
388 | return None; | |
389 | } | |
390 | ||
391 | let self_ty = trait_ref.self_ty(); | |
1b1a35ee | 392 | let self_ty_matches = match self_ty.kind() { |
5099ac24 | 393 | ty::Dynamic(ref data, re) if re.is_static() => data.principal().is_none(), |
dfeec247 XL |
394 | _ => false, |
395 | }; | |
396 | ||
397 | if self_ty_matches { | |
398 | debug!("issue33140_self_ty - MATCHES!"); | |
399 | Some(self_ty) | |
400 | } else { | |
401 | debug!("issue33140_self_ty - non-matching self type"); | |
402 | None | |
403 | } | |
404 | } | |
405 | ||
406 | /// Check if a function is async. | |
407 | fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync { | |
5099ac24 | 408 | let node = tcx.hir().get_by_def_id(def_id.expect_local()); |
04454e1e | 409 | if let Some(fn_kind) = node.fn_kind() { fn_kind.asyncness() } else { hir::IsAsync::NotAsync } |
dfeec247 XL |
410 | } |
411 | ||
6a06907d XL |
412 | /// Don't call this directly: use ``tcx.conservative_is_privately_uninhabited`` instead. |
413 | #[instrument(level = "debug", skip(tcx))] | |
414 | pub fn conservative_is_privately_uninhabited_raw<'tcx>( | |
415 | tcx: TyCtxt<'tcx>, | |
416 | param_env_and: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, | |
417 | ) -> bool { | |
418 | let (param_env, ty) = param_env_and.into_parts(); | |
419 | match ty.kind() { | |
420 | ty::Never => { | |
421 | debug!("ty::Never =>"); | |
422 | true | |
423 | } | |
424 | ty::Adt(def, _) if def.is_union() => { | |
425 | debug!("ty::Adt(def, _) if def.is_union() =>"); | |
426 | // For now, `union`s are never considered uninhabited. | |
427 | false | |
428 | } | |
429 | ty::Adt(def, substs) => { | |
430 | debug!("ty::Adt(def, _) if def.is_not_union() =>"); | |
431 | // Any ADT is uninhabited if either: | |
432 | // (a) It has no variants (i.e. an empty `enum`); | |
433 | // (b) Each of its variants (a single one in the case of a `struct`) has at least | |
434 | // one uninhabited field. | |
5e7ed085 | 435 | def.variants().iter().all(|var| { |
6a06907d | 436 | var.fields.iter().any(|field| { |
04454e1e | 437 | let ty = tcx.bound_type_of(field.did).subst(tcx, substs); |
6a06907d XL |
438 | tcx.conservative_is_privately_uninhabited(param_env.and(ty)) |
439 | }) | |
440 | }) | |
441 | } | |
5e7ed085 | 442 | ty::Tuple(fields) => { |
6a06907d | 443 | debug!("ty::Tuple(..) =>"); |
5e7ed085 | 444 | fields.iter().any(|ty| tcx.conservative_is_privately_uninhabited(param_env.and(ty))) |
6a06907d XL |
445 | } |
446 | ty::Array(ty, len) => { | |
447 | debug!("ty::Array(ty, len) =>"); | |
448 | match len.try_eval_usize(tcx, param_env) { | |
449 | Some(0) | None => false, | |
450 | // If the array is definitely non-empty, it's uninhabited if | |
451 | // the type of its elements is uninhabited. | |
5099ac24 | 452 | Some(1..) => tcx.conservative_is_privately_uninhabited(param_env.and(*ty)), |
6a06907d XL |
453 | } |
454 | } | |
455 | ty::Ref(..) => { | |
456 | debug!("ty::Ref(..) =>"); | |
457 | // References to uninitialised memory is valid for any type, including | |
458 | // uninhabited types, in unsafe code, so we treat all references as | |
459 | // inhabited. | |
460 | false | |
461 | } | |
462 | _ => { | |
463 | debug!("_ =>"); | |
464 | false | |
465 | } | |
466 | } | |
467 | } | |
468 | ||
f035d41b | 469 | pub fn provide(providers: &mut ty::query::Providers) { |
dfeec247 XL |
470 | *providers = ty::query::Providers { |
471 | asyncness, | |
dfeec247 | 472 | adt_sized_constraint, |
dfeec247 | 473 | param_env, |
3dfed10e | 474 | param_env_reveal_all_normalized, |
dfeec247 XL |
475 | instance_def_size_estimate, |
476 | issue33140_self_ty, | |
ba9703b0 | 477 | impl_defaultness, |
6a06907d | 478 | conservative_is_privately_uninhabited: conservative_is_privately_uninhabited_raw, |
dfeec247 XL |
479 | ..*providers |
480 | }; | |
481 | } |