]>
Commit | Line | Data |
---|---|---|
dfeec247 XL |
1 | use rustc_data_structures::svh::Svh; |
2 | use rustc_hir as hir; | |
f9f354fc | 3 | use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; |
ba9703b0 XL |
4 | use rustc_middle::hir::map as hir_map; |
5 | use rustc_middle::ty::subst::Subst; | |
6 | use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness}; | |
7 | use rustc_session::CrateDisambiguator; | |
dfeec247 XL |
8 | use rustc_span::symbol::Symbol; |
9 | use rustc_span::Span; | |
ba9703b0 | 10 | use rustc_trait_selection::traits; |
dfeec247 | 11 | |
74b04a01 XL |
12 | fn sized_constraint_for_ty<'tcx>( |
13 | tcx: TyCtxt<'tcx>, | |
14 | adtdef: &ty::AdtDef, | |
15 | ty: Ty<'tcx>, | |
16 | ) -> Vec<Ty<'tcx>> { | |
dfeec247 XL |
17 | use ty::TyKind::*; |
18 | ||
19 | let result = match ty.kind { | |
20 | Bool | Char | Int(..) | Uint(..) | Float(..) | RawPtr(..) | Ref(..) | FnDef(..) | |
21 | | FnPtr(_) | Array(..) | Closure(..) | Generator(..) | Never => vec![], | |
22 | ||
23 | Str | Dynamic(..) | Slice(_) | Foreign(..) | Error | GeneratorWitness(..) => { | |
24 | // these are never sized - return the target type | |
25 | vec![ty] | |
26 | } | |
27 | ||
28 | Tuple(ref tys) => match tys.last() { | |
29 | None => vec![], | |
30 | Some(ty) => sized_constraint_for_ty(tcx, adtdef, ty.expect_ty()), | |
31 | }, | |
32 | ||
33 | Adt(adt, substs) => { | |
34 | // recursive case | |
35 | let adt_tys = adt.sized_constraint(tcx); | |
36 | debug!("sized_constraint_for_ty({:?}) intermediate = {:?}", ty, adt_tys); | |
37 | adt_tys | |
38 | .iter() | |
39 | .map(|ty| ty.subst(tcx, substs)) | |
40 | .flat_map(|ty| sized_constraint_for_ty(tcx, adtdef, ty)) | |
41 | .collect() | |
42 | } | |
43 | ||
44 | Projection(..) | Opaque(..) => { | |
45 | // must calculate explicitly. | |
46 | // FIXME: consider special-casing always-Sized projections | |
47 | vec![ty] | |
48 | } | |
49 | ||
dfeec247 XL |
50 | Param(..) => { |
51 | // perf hack: if there is a `T: Sized` bound, then | |
52 | // we know that `T` is Sized and do not need to check | |
53 | // it on the impl. | |
54 | ||
55 | let sized_trait = match tcx.lang_items().sized_trait() { | |
56 | Some(x) => x, | |
57 | _ => return vec![ty], | |
58 | }; | |
59 | let sized_predicate = ty::Binder::dummy(ty::TraitRef { | |
60 | def_id: sized_trait, | |
61 | substs: tcx.mk_substs_trait(ty, &[]), | |
62 | }) | |
63 | .without_const() | |
f9f354fc | 64 | .to_predicate(tcx); |
dfeec247 XL |
65 | let predicates = tcx.predicates_of(adtdef.did).predicates; |
66 | if predicates.iter().any(|(p, _)| *p == sized_predicate) { vec![] } else { vec![ty] } | |
67 | } | |
68 | ||
69 | Placeholder(..) | Bound(..) | Infer(..) => { | |
70 | bug!("unexpected type `{:?}` in sized_constraint_for_ty", ty) | |
71 | } | |
72 | }; | |
73 | debug!("sized_constraint_for_ty({:?}) = {:?}", ty, result); | |
74 | result | |
75 | } | |
76 | ||
77 | fn associated_item_from_trait_item_ref( | |
78 | tcx: TyCtxt<'_>, | |
f9f354fc | 79 | parent_def_id: LocalDefId, |
dfeec247 XL |
80 | parent_vis: &hir::Visibility<'_>, |
81 | trait_item_ref: &hir::TraitItemRef, | |
82 | ) -> ty::AssocItem { | |
83 | let def_id = tcx.hir().local_def_id(trait_item_ref.id.hir_id); | |
84 | let (kind, has_self) = match trait_item_ref.kind { | |
85 | hir::AssocItemKind::Const => (ty::AssocKind::Const, false), | |
ba9703b0 | 86 | hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self), |
dfeec247 XL |
87 | hir::AssocItemKind::Type => (ty::AssocKind::Type, false), |
88 | hir::AssocItemKind::OpaqueTy => bug!("only impls can have opaque types"), | |
89 | }; | |
90 | ||
91 | ty::AssocItem { | |
92 | ident: trait_item_ref.ident, | |
93 | kind, | |
94 | // Visibility of trait items is inherited from their traits. | |
95 | vis: ty::Visibility::from_hir(parent_vis, trait_item_ref.id.hir_id, tcx), | |
96 | defaultness: trait_item_ref.defaultness, | |
f9f354fc XL |
97 | def_id: def_id.to_def_id(), |
98 | container: ty::TraitContainer(parent_def_id.to_def_id()), | |
ba9703b0 | 99 | fn_has_self_parameter: has_self, |
dfeec247 XL |
100 | } |
101 | } | |
102 | ||
103 | fn associated_item_from_impl_item_ref( | |
104 | tcx: TyCtxt<'_>, | |
f9f354fc | 105 | parent_def_id: LocalDefId, |
dfeec247 XL |
106 | impl_item_ref: &hir::ImplItemRef<'_>, |
107 | ) -> ty::AssocItem { | |
108 | let def_id = tcx.hir().local_def_id(impl_item_ref.id.hir_id); | |
109 | let (kind, has_self) = match impl_item_ref.kind { | |
110 | hir::AssocItemKind::Const => (ty::AssocKind::Const, false), | |
ba9703b0 | 111 | hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self), |
dfeec247 XL |
112 | hir::AssocItemKind::Type => (ty::AssocKind::Type, false), |
113 | hir::AssocItemKind::OpaqueTy => (ty::AssocKind::OpaqueTy, false), | |
114 | }; | |
115 | ||
116 | ty::AssocItem { | |
117 | ident: impl_item_ref.ident, | |
118 | kind, | |
119 | // Visibility of trait impl items doesn't matter. | |
120 | vis: ty::Visibility::from_hir(&impl_item_ref.vis, impl_item_ref.id.hir_id, tcx), | |
121 | defaultness: impl_item_ref.defaultness, | |
f9f354fc XL |
122 | def_id: def_id.to_def_id(), |
123 | container: ty::ImplContainer(parent_def_id.to_def_id()), | |
ba9703b0 | 124 | fn_has_self_parameter: has_self, |
dfeec247 XL |
125 | } |
126 | } | |
127 | ||
128 | fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem { | |
f9f354fc | 129 | let id = tcx.hir().as_local_hir_id(def_id.expect_local()); |
dfeec247 XL |
130 | let parent_id = tcx.hir().get_parent_item(id); |
131 | let parent_def_id = tcx.hir().local_def_id(parent_id); | |
132 | let parent_item = tcx.hir().expect_item(parent_id); | |
133 | match parent_item.kind { | |
134 | hir::ItemKind::Impl { ref items, .. } => { | |
135 | if let Some(impl_item_ref) = items.iter().find(|i| i.id.hir_id == id) { | |
136 | let assoc_item = | |
137 | associated_item_from_impl_item_ref(tcx, parent_def_id, impl_item_ref); | |
138 | debug_assert_eq!(assoc_item.def_id, def_id); | |
139 | return assoc_item; | |
140 | } | |
141 | } | |
142 | ||
143 | hir::ItemKind::Trait(.., ref trait_item_refs) => { | |
144 | if let Some(trait_item_ref) = trait_item_refs.iter().find(|i| i.id.hir_id == id) { | |
145 | let assoc_item = associated_item_from_trait_item_ref( | |
146 | tcx, | |
147 | parent_def_id, | |
148 | &parent_item.vis, | |
149 | trait_item_ref, | |
150 | ); | |
151 | debug_assert_eq!(assoc_item.def_id, def_id); | |
152 | return assoc_item; | |
153 | } | |
154 | } | |
155 | ||
156 | _ => {} | |
157 | } | |
158 | ||
159 | span_bug!( | |
160 | parent_item.span, | |
161 | "unexpected parent of trait or impl item or item not found: {:?}", | |
162 | parent_item.kind | |
163 | ) | |
164 | } | |
165 | ||
ba9703b0 | 166 | fn impl_defaultness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Defaultness { |
f9f354fc | 167 | let hir_id = tcx.hir().as_local_hir_id(def_id.expect_local()); |
ba9703b0 XL |
168 | let item = tcx.hir().expect_item(hir_id); |
169 | if let hir::ItemKind::Impl { defaultness, .. } = item.kind { | |
170 | defaultness | |
171 | } else { | |
172 | bug!("`impl_defaultness` called on {:?}", item); | |
173 | } | |
174 | } | |
175 | ||
dfeec247 XL |
176 | /// Calculates the `Sized` constraint. |
177 | /// | |
178 | /// In fact, there are only a few options for the types in the constraint: | |
179 | /// - an obviously-unsized type | |
180 | /// - a type parameter or projection whose Sizedness can't be known | |
181 | /// - a tuple of type parameters or projections, if there are multiple | |
182 | /// such. | |
183 | /// - a Error, if a type contained itself. The representability | |
184 | /// check should catch this case. | |
185 | fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtSizedConstraint<'_> { | |
186 | let def = tcx.adt_def(def_id); | |
187 | ||
188 | let result = tcx.mk_type_list( | |
189 | def.variants | |
190 | .iter() | |
191 | .flat_map(|v| v.fields.last()) | |
192 | .flat_map(|f| sized_constraint_for_ty(tcx, def, tcx.type_of(f.did))), | |
193 | ); | |
194 | ||
195 | debug!("adt_sized_constraint: {:?} => {:?}", def, result); | |
196 | ||
197 | ty::AdtSizedConstraint(result) | |
198 | } | |
199 | ||
200 | fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] { | |
f9f354fc | 201 | let id = tcx.hir().as_local_hir_id(def_id.expect_local()); |
dfeec247 XL |
202 | let item = tcx.hir().expect_item(id); |
203 | match item.kind { | |
204 | hir::ItemKind::Trait(.., ref trait_item_refs) => tcx.arena.alloc_from_iter( | |
205 | trait_item_refs | |
206 | .iter() | |
207 | .map(|trait_item_ref| trait_item_ref.id) | |
f9f354fc | 208 | .map(|id| tcx.hir().local_def_id(id.hir_id).to_def_id()), |
dfeec247 XL |
209 | ), |
210 | hir::ItemKind::Impl { ref items, .. } => tcx.arena.alloc_from_iter( | |
211 | items | |
212 | .iter() | |
213 | .map(|impl_item_ref| impl_item_ref.id) | |
f9f354fc | 214 | .map(|id| tcx.hir().local_def_id(id.hir_id).to_def_id()), |
dfeec247 XL |
215 | ), |
216 | hir::ItemKind::TraitAlias(..) => &[], | |
217 | _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"), | |
218 | } | |
219 | } | |
220 | ||
f9f354fc | 221 | fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssociatedItems<'_> { |
74b04a01 | 222 | let items = tcx.associated_item_def_ids(def_id).iter().map(|did| tcx.associated_item(*did)); |
f9f354fc | 223 | ty::AssociatedItems::new(items) |
74b04a01 XL |
224 | } |
225 | ||
dfeec247 XL |
226 | fn def_span(tcx: TyCtxt<'_>, def_id: DefId) -> Span { |
227 | tcx.hir().span_if_local(def_id).unwrap() | |
228 | } | |
229 | ||
230 | /// If the given `DefId` describes an item belonging to a trait, | |
231 | /// returns the `DefId` of the trait that the trait item belongs to; | |
232 | /// otherwise, returns `None`. | |
233 | fn trait_of_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> { | |
234 | tcx.opt_associated_item(def_id).and_then(|associated_item| match associated_item.container { | |
235 | ty::TraitContainer(def_id) => Some(def_id), | |
236 | ty::ImplContainer(_) => None, | |
237 | }) | |
238 | } | |
239 | ||
240 | /// See `ParamEnv` struct definition for details. | |
241 | fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { | |
242 | // The param_env of an impl Trait type is its defining function's param_env | |
243 | if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) { | |
244 | return param_env(tcx, parent); | |
245 | } | |
246 | // Compute the bounds on Self and the type parameters. | |
247 | ||
74b04a01 | 248 | let ty::InstantiatedPredicates { predicates, .. } = |
dfeec247 XL |
249 | tcx.predicates_of(def_id).instantiate_identity(tcx); |
250 | ||
251 | // Finally, we have to normalize the bounds in the environment, in | |
252 | // case they contain any associated type projections. This process | |
253 | // can yield errors if the put in illegal associated types, like | |
254 | // `<i32 as Foo>::Bar` where `i32` does not implement `Foo`. We | |
255 | // report these errors right here; this doesn't actually feel | |
256 | // right to me, because constructing the environment feels like a | |
257 | // kind of a "idempotent" action, but I'm not sure where would be | |
258 | // a better place. In practice, we construct environments for | |
259 | // every fn once during type checking, and we'll abort if there | |
260 | // are any errors at that point, so after type checking you can be | |
261 | // sure that this will succeed without errors anyway. | |
262 | ||
f9f354fc XL |
263 | let unnormalized_env = ty::ParamEnv::new( |
264 | tcx.intern_predicates(&predicates), | |
265 | traits::Reveal::UserFacing, | |
266 | tcx.sess.opts.debugging_opts.chalk.then_some(def_id), | |
267 | ); | |
dfeec247 | 268 | |
f9f354fc XL |
269 | let body_id = def_id |
270 | .as_local() | |
271 | .map(|def_id| tcx.hir().as_local_hir_id(def_id)) | |
272 | .map_or(hir::CRATE_HIR_ID, |id| { | |
273 | tcx.hir().maybe_body_owned_by(id).map_or(id, |body| body.hir_id) | |
274 | }); | |
dfeec247 XL |
275 | let cause = traits::ObligationCause::misc(tcx.def_span(def_id), body_id); |
276 | traits::normalize_param_env_or_error(tcx, def_id, unnormalized_env, cause) | |
277 | } | |
278 | ||
279 | fn crate_disambiguator(tcx: TyCtxt<'_>, crate_num: CrateNum) -> CrateDisambiguator { | |
280 | assert_eq!(crate_num, LOCAL_CRATE); | |
281 | tcx.sess.local_crate_disambiguator() | |
282 | } | |
283 | ||
284 | fn original_crate_name(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Symbol { | |
285 | assert_eq!(crate_num, LOCAL_CRATE); | |
286 | tcx.crate_name | |
287 | } | |
288 | ||
289 | fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh { | |
ba9703b0 | 290 | tcx.index_hir(crate_num).crate_hash |
dfeec247 XL |
291 | } |
292 | ||
293 | fn instance_def_size_estimate<'tcx>( | |
294 | tcx: TyCtxt<'tcx>, | |
295 | instance_def: ty::InstanceDef<'tcx>, | |
296 | ) -> usize { | |
297 | use ty::InstanceDef; | |
298 | ||
299 | match instance_def { | |
300 | InstanceDef::Item(..) | InstanceDef::DropGlue(..) => { | |
301 | let mir = tcx.instance_mir(instance_def); | |
302 | mir.basic_blocks().iter().map(|bb| bb.statements.len()).sum() | |
303 | } | |
304 | // Estimate the size of other compiler-generated shims to be 1. | |
305 | _ => 1, | |
306 | } | |
307 | } | |
308 | ||
309 | /// If `def_id` is an issue 33140 hack impl, returns its self type; otherwise, returns `None`. | |
310 | /// | |
f9f354fc | 311 | /// See [`ty::ImplOverlapKind::Issue33140`] for more details. |
dfeec247 XL |
312 | fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Ty<'_>> { |
313 | debug!("issue33140_self_ty({:?})", def_id); | |
314 | ||
315 | let trait_ref = tcx | |
316 | .impl_trait_ref(def_id) | |
317 | .unwrap_or_else(|| bug!("issue33140_self_ty called on inherent impl {:?}", def_id)); | |
318 | ||
319 | debug!("issue33140_self_ty({:?}), trait-ref={:?}", def_id, trait_ref); | |
320 | ||
321 | let is_marker_like = tcx.impl_polarity(def_id) == ty::ImplPolarity::Positive | |
322 | && tcx.associated_item_def_ids(trait_ref.def_id).is_empty(); | |
323 | ||
324 | // Check whether these impls would be ok for a marker trait. | |
325 | if !is_marker_like { | |
326 | debug!("issue33140_self_ty - not marker-like!"); | |
327 | return None; | |
328 | } | |
329 | ||
330 | // impl must be `impl Trait for dyn Marker1 + Marker2 + ...` | |
331 | if trait_ref.substs.len() != 1 { | |
332 | debug!("issue33140_self_ty - impl has substs!"); | |
333 | return None; | |
334 | } | |
335 | ||
336 | let predicates = tcx.predicates_of(def_id); | |
337 | if predicates.parent.is_some() || !predicates.predicates.is_empty() { | |
338 | debug!("issue33140_self_ty - impl has predicates {:?}!", predicates); | |
339 | return None; | |
340 | } | |
341 | ||
342 | let self_ty = trait_ref.self_ty(); | |
343 | let self_ty_matches = match self_ty.kind { | |
344 | ty::Dynamic(ref data, ty::ReStatic) => data.principal().is_none(), | |
345 | _ => false, | |
346 | }; | |
347 | ||
348 | if self_ty_matches { | |
349 | debug!("issue33140_self_ty - MATCHES!"); | |
350 | Some(self_ty) | |
351 | } else { | |
352 | debug!("issue33140_self_ty - non-matching self type"); | |
353 | None | |
354 | } | |
355 | } | |
356 | ||
357 | /// Check if a function is async. | |
358 | fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync { | |
f9f354fc | 359 | let hir_id = tcx.hir().as_local_hir_id(def_id.expect_local()); |
dfeec247 XL |
360 | |
361 | let node = tcx.hir().get(hir_id); | |
362 | ||
363 | let fn_like = hir_map::blocks::FnLikeNode::from_node(node).unwrap_or_else(|| { | |
364 | bug!("asyncness: expected fn-like node but got `{:?}`", def_id); | |
365 | }); | |
366 | ||
367 | fn_like.asyncness() | |
368 | } | |
369 | ||
370 | pub fn provide(providers: &mut ty::query::Providers<'_>) { | |
371 | *providers = ty::query::Providers { | |
372 | asyncness, | |
373 | associated_item, | |
374 | associated_item_def_ids, | |
74b04a01 | 375 | associated_items, |
dfeec247 XL |
376 | adt_sized_constraint, |
377 | def_span, | |
378 | param_env, | |
379 | trait_of_item, | |
380 | crate_disambiguator, | |
381 | original_crate_name, | |
382 | crate_hash, | |
383 | instance_def_size_estimate, | |
384 | issue33140_self_ty, | |
ba9703b0 | 385 | impl_defaultness, |
dfeec247 XL |
386 | ..*providers |
387 | }; | |
388 | } |