]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_typeck/src/collect/type_of.rs
New upstream version 1.56.0~beta.4+dfsg1
[rustc.git] / compiler / rustc_typeck / src / collect / type_of.rs
CommitLineData
ba9703b0 1use rustc_data_structures::fx::FxHashSet;
1b1a35ee 2use rustc_errors::{Applicability, ErrorReported, StashKey};
74b04a01
XL
3use rustc_hir as hir;
4use rustc_hir::def::{DefKind, Res};
f9f354fc 5use rustc_hir::def_id::{DefId, LocalDefId};
74b04a01
XL
6use rustc_hir::intravisit;
7use rustc_hir::intravisit::Visitor;
5869c6ff 8use rustc_hir::{HirId, Node};
ba9703b0 9use rustc_middle::hir::map::Map;
94222f64 10use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, SubstsRef};
ba9703b0 11use rustc_middle::ty::util::IntTypeExt;
136023e0 12use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable, TypeFolder};
f035d41b 13use rustc_span::symbol::Ident;
74b04a01
XL
14use rustc_span::{Span, DUMMY_SP};
15
16use super::ItemCtxt;
17use super::{bad_placeholder_type, is_suggestable_infer_ty};
18
3dfed10e
XL
19/// Computes the relevant generic parameter for a potential generic const argument.
20///
21/// This should be called using the query `tcx.opt_const_param_of`.
22pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<DefId> {
94222f64
XL
23 // FIXME(generic_arg_infer): allow for returning DefIds of inference of
24 // GenericArg::Infer below. This may require a change where GenericArg::Infer has some flag
25 // for const or type.
3dfed10e 26 use hir::*;
3dfed10e
XL
27 let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
28
29 if let Node::AnonConst(_) = tcx.hir().get(hir_id) {
30 let parent_node_id = tcx.hir().get_parent_node(hir_id);
31 let parent_node = tcx.hir().get(parent_node_id);
32
33 match parent_node {
6a06907d
XL
34 // This match arm is for when the def_id appears in a GAT whose
35 // path can't be resolved without typechecking e.g.
36 //
37 // trait Foo {
38 // type Assoc<const N: usize>;
39 // fn foo() -> Self::Assoc<3>;
40 // }
41 //
42 // In the above code we would call this query with the def_id of 3 and
43 // the parent_node we match on would be the hir node for Self::Assoc<3>
44 //
45 // `Self::Assoc<3>` cant be resolved without typchecking here as we
46 // didnt write <Self as Foo>::Assoc<3>. If we did then another match
47 // arm would handle this.
48 //
49 // I believe this match arm is only needed for GAT but I am not 100% sure - BoxyUwU
50 Node::Ty(hir_ty @ Ty { kind: TyKind::Path(QPath::TypeRelative(_, segment)), .. }) => {
51 // Find the Item containing the associated type so we can create an ItemCtxt.
52 // Using the ItemCtxt convert the HIR for the unresolved assoc type into a
53 // ty which is a fully resolved projection.
54 // For the code example above, this would mean converting Self::Assoc<3>
55 // into a ty::Projection(<Self as Foo>::Assoc<3>)
56 let item_hir_id = tcx
57 .hir()
58 .parent_iter(hir_id)
59 .filter(|(_, node)| matches!(node, Node::Item(_)))
60 .map(|(id, _)| id)
61 .next()
62 .unwrap();
63 let item_did = tcx.hir().local_def_id(item_hir_id).to_def_id();
64 let item_ctxt = &ItemCtxt::new(tcx, item_did) as &dyn crate::astconv::AstConv<'_>;
65 let ty = item_ctxt.ast_ty_to_ty(hir_ty);
66
67 // Iterate through the generics of the projection to find the one that corresponds to
68 // the def_id that this query was called with. We filter to only const args here as a
69 // precaution for if it's ever allowed to elide lifetimes in GAT's. It currently isn't
70 // but it can't hurt to be safe ^^
71 if let ty::Projection(projection) = ty.kind() {
72 let generics = tcx.generics_of(projection.item_def_id);
73
74 let arg_index = segment
75 .args
76 .and_then(|args| {
77 args.args
78 .iter()
79 .filter(|arg| arg.is_const())
80 .position(|arg| arg.id() == hir_id)
81 })
82 .unwrap_or_else(|| {
83 bug!("no arg matching AnonConst in segment");
84 });
85
86 return generics
87 .params
88 .iter()
cdc7bbd5 89 .filter(|param| matches!(param.kind, ty::GenericParamDefKind::Const { .. }))
6a06907d
XL
90 .nth(arg_index)
91 .map(|param| param.def_id);
92 }
93
94 // I dont think it's possible to reach this but I'm not 100% sure - BoxyUwU
95 tcx.sess.delay_span_bug(
96 tcx.def_span(def_id),
97 "unexpected non-GAT usage of an anon const",
98 );
99 return None;
100 }
3dfed10e
XL
101 Node::Expr(&Expr {
102 kind:
103 ExprKind::MethodCall(segment, ..) | ExprKind::Path(QPath::TypeRelative(_, segment)),
104 ..
105 }) => {
106 let body_owner = tcx.hir().local_def_id(tcx.hir().enclosing_body_owner(hir_id));
107 let tables = tcx.typeck(body_owner);
108 // This may fail in case the method/path does not actually exist.
109 // As there is no relevant param for `def_id`, we simply return
110 // `None` here.
111 let type_dependent_def = tables.type_dependent_def_id(parent_node_id)?;
112 let idx = segment
113 .args
114 .and_then(|args| {
115 args.args
116 .iter()
117 .filter(|arg| arg.is_const())
118 .position(|arg| arg.id() == hir_id)
119 })
120 .unwrap_or_else(|| {
121 bug!("no arg matching AnonConst in segment");
122 });
123
124 tcx.generics_of(type_dependent_def)
125 .params
126 .iter()
cdc7bbd5 127 .filter(|param| matches!(param.kind, ty::GenericParamDefKind::Const { .. }))
3dfed10e
XL
128 .nth(idx)
129 .map(|param| param.def_id)
130 }
131
132 Node::Ty(&Ty { kind: TyKind::Path(_), .. })
5869c6ff
XL
133 | Node::Expr(&Expr { kind: ExprKind::Path(_) | ExprKind::Struct(..), .. })
134 | Node::TraitRef(..)
135 | Node::Pat(_) => {
3dfed10e
XL
136 let path = match parent_node {
137 Node::Ty(&Ty { kind: TyKind::Path(QPath::Resolved(_, path)), .. })
138 | Node::TraitRef(&TraitRef { path, .. }) => &*path,
139 Node::Expr(&Expr {
140 kind:
141 ExprKind::Path(QPath::Resolved(_, path))
142 | ExprKind::Struct(&QPath::Resolved(_, path), ..),
143 ..
144 }) => {
145 let body_owner =
146 tcx.hir().local_def_id(tcx.hir().enclosing_body_owner(hir_id));
147 let _tables = tcx.typeck(body_owner);
148 &*path
149 }
5869c6ff
XL
150 Node::Pat(pat) => {
151 if let Some(path) = get_path_containing_arg_in_pat(pat, hir_id) {
152 path
153 } else {
154 tcx.sess.delay_span_bug(
155 tcx.def_span(def_id),
156 &format!(
157 "unable to find const parent for {} in pat {:?}",
158 hir_id, pat
159 ),
160 );
161 return None;
162 }
163 }
1b1a35ee
XL
164 _ => {
165 tcx.sess.delay_span_bug(
166 tcx.def_span(def_id),
167 &format!("unexpected const parent path {:?}", parent_node),
168 );
169 return None;
170 }
3dfed10e
XL
171 };
172
173 // We've encountered an `AnonConst` in some path, so we need to
174 // figure out which generic parameter it corresponds to and return
175 // the relevant type.
3dfed10e
XL
176 let (arg_index, segment) = path
177 .segments
178 .iter()
179 .filter_map(|seg| seg.args.map(|args| (args.args, seg)))
180 .find_map(|(args, seg)| {
181 args.iter()
182 .filter(|arg| arg.is_const())
183 .position(|arg| arg.id() == hir_id)
184 .map(|index| (index, seg))
185 })
186 .unwrap_or_else(|| {
187 bug!("no arg matching AnonConst in path");
188 });
189
190 // Try to use the segment resolution if it is valid, otherwise we
191 // default to the path resolution.
192 let res = segment.res.filter(|&r| r != Res::Err).unwrap_or(path.res);
94222f64 193 use def::CtorOf;
3dfed10e 194 let generics = match res {
94222f64
XL
195 Res::Def(DefKind::Ctor(CtorOf::Variant, _), def_id) => tcx.generics_of(
196 tcx.parent(def_id).and_then(|def_id| tcx.parent(def_id)).unwrap(),
197 ),
198 Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Struct, _), def_id) => {
3dfed10e
XL
199 tcx.generics_of(tcx.parent(def_id).unwrap())
200 }
cdc7bbd5
XL
201 // Other `DefKind`s don't have generics and would ICE when calling
202 // `generics_of`.
203 Res::Def(
204 DefKind::Struct
205 | DefKind::Union
206 | DefKind::Enum
cdc7bbd5
XL
207 | DefKind::Trait
208 | DefKind::OpaqueTy
209 | DefKind::TyAlias
210 | DefKind::ForeignTy
211 | DefKind::TraitAlias
212 | DefKind::AssocTy
213 | DefKind::Fn
214 | DefKind::AssocFn
215 | DefKind::AssocConst
216 | DefKind::Impl,
217 def_id,
218 ) => tcx.generics_of(def_id),
3dfed10e
XL
219 Res::Err => {
220 tcx.sess.delay_span_bug(tcx.def_span(def_id), "anon const with Res::Err");
221 return None;
222 }
29967ef6
XL
223 _ => {
224 // If the user tries to specify generics on a type that does not take them,
225 // e.g. `usize<T>`, we may hit this branch, in which case we treat it as if
226 // no arguments have been passed. An error should already have been emitted.
227 tcx.sess.delay_span_bug(
228 tcx.def_span(def_id),
229 &format!("unexpected anon const res {:?} in path: {:?}", res, path),
230 );
231 return None;
232 }
3dfed10e
XL
233 };
234
235 generics
236 .params
237 .iter()
cdc7bbd5 238 .filter(|param| matches!(param.kind, ty::GenericParamDefKind::Const { .. }))
3dfed10e
XL
239 .nth(arg_index)
240 .map(|param| param.def_id)
241 }
242 _ => None,
243 }
244 } else {
245 None
246 }
247}
248
5869c6ff
XL
249fn get_path_containing_arg_in_pat<'hir>(
250 pat: &'hir hir::Pat<'hir>,
251 arg_id: HirId,
252) -> Option<&'hir hir::Path<'hir>> {
253 use hir::*;
254
255 let is_arg_in_path = |p: &hir::Path<'_>| {
256 p.segments
257 .iter()
258 .filter_map(|seg| seg.args)
259 .flat_map(|args| args.args)
260 .any(|arg| arg.id() == arg_id)
261 };
262 let mut arg_path = None;
263 pat.walk(|pat| match pat.kind {
264 PatKind::Struct(QPath::Resolved(_, path), _, _)
265 | PatKind::TupleStruct(QPath::Resolved(_, path), _, _)
266 | PatKind::Path(QPath::Resolved(_, path))
267 if is_arg_in_path(path) =>
268 {
269 arg_path = Some(path);
270 false
271 }
272 _ => true,
273 });
274 arg_path
275}
276
94222f64
XL
277pub(super) fn default_anon_const_substs(tcx: TyCtxt<'_>, def_id: DefId) -> SubstsRef<'_> {
278 let generics = tcx.generics_of(def_id);
279 if let Some(parent) = generics.parent {
280 // This is the reason we bother with having optional anon const substs.
281 //
282 // In the future the substs of an anon const will depend on its parents predicates
283 // at which point eagerly looking at them will cause a query cycle.
284 //
285 // So for now this is only an assurance that this approach won't cause cycle errors in
286 // the future.
287 let _cycle_check = tcx.predicates_of(parent);
288 }
289
290 let substs = InternalSubsts::identity_for_item(tcx, def_id);
291 // We only expect substs with the following type flags as default substs.
292 //
293 // Getting this wrong can lead to ICE and unsoundness, so we assert it here.
294 for arg in substs.iter() {
295 let allowed_flags = ty::TypeFlags::MAY_NEED_DEFAULT_CONST_SUBSTS
296 | ty::TypeFlags::STILL_FURTHER_SPECIALIZABLE;
297 assert!(!arg.has_type_flags(!allowed_flags));
298 }
299 substs
300}
301
74b04a01 302pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
3dfed10e 303 let def_id = def_id.expect_local();
74b04a01
XL
304 use rustc_hir::*;
305
3dfed10e 306 let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
74b04a01 307
3dfed10e 308 let icx = ItemCtxt::new(tcx, def_id.to_def_id());
74b04a01
XL
309
310 match tcx.hir().get(hir_id) {
311 Node::TraitItem(item) => match item.kind {
ba9703b0 312 TraitItemKind::Fn(..) => {
3dfed10e
XL
313 let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
314 tcx.mk_fn_def(def_id.to_def_id(), substs)
74b04a01
XL
315 }
316 TraitItemKind::Const(ref ty, body_id) => body_id
317 .and_then(|body_id| {
318 if is_suggestable_infer_ty(ty) {
136023e0
XL
319 Some(infer_placeholder_type(
320 tcx, def_id, body_id, ty.span, item.ident, "constant",
321 ))
74b04a01
XL
322 } else {
323 None
324 }
325 })
326 .unwrap_or_else(|| icx.to_ty(ty)),
327 TraitItemKind::Type(_, Some(ref ty)) => icx.to_ty(ty),
328 TraitItemKind::Type(_, None) => {
329 span_bug!(item.span, "associated type missing default");
330 }
331 },
332
333 Node::ImplItem(item) => match item.kind {
ba9703b0 334 ImplItemKind::Fn(..) => {
3dfed10e
XL
335 let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
336 tcx.mk_fn_def(def_id.to_def_id(), substs)
74b04a01
XL
337 }
338 ImplItemKind::Const(ref ty, body_id) => {
339 if is_suggestable_infer_ty(ty) {
136023e0 340 infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident, "constant")
74b04a01
XL
341 } else {
342 icx.to_ty(ty)
343 }
344 }
74b04a01 345 ImplItemKind::TyAlias(ref ty) => {
ba9703b0 346 if tcx.impl_trait_ref(tcx.hir().get_parent_did(hir_id).to_def_id()).is_none() {
6a06907d 347 check_feature_inherent_assoc_ty(tcx, item.span);
74b04a01
XL
348 }
349
350 icx.to_ty(ty)
351 }
352 },
353
354 Node::Item(item) => {
355 match item.kind {
136023e0 356 ItemKind::Static(ref ty, .., body_id) => {
74b04a01 357 if is_suggestable_infer_ty(ty) {
136023e0
XL
358 infer_placeholder_type(
359 tcx,
360 def_id,
361 body_id,
362 ty.span,
363 item.ident,
364 "static variable",
365 )
366 } else {
367 icx.to_ty(ty)
368 }
369 }
370 ItemKind::Const(ref ty, body_id) => {
371 if is_suggestable_infer_ty(ty) {
372 infer_placeholder_type(
373 tcx, def_id, body_id, ty.span, item.ident, "constant",
374 )
74b04a01
XL
375 } else {
376 icx.to_ty(ty)
377 }
378 }
5869c6ff
XL
379 ItemKind::TyAlias(ref self_ty, _)
380 | ItemKind::Impl(hir::Impl { ref self_ty, .. }) => icx.to_ty(self_ty),
74b04a01 381 ItemKind::Fn(..) => {
3dfed10e
XL
382 let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
383 tcx.mk_fn_def(def_id.to_def_id(), substs)
74b04a01
XL
384 }
385 ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => {
386 let def = tcx.adt_def(def_id);
3dfed10e 387 let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
74b04a01
XL
388 tcx.mk_adt(def, substs)
389 }
390 ItemKind::OpaqueTy(OpaqueTy { impl_trait_fn: None, .. }) => {
3dfed10e 391 find_opaque_ty_constraints(tcx, def_id)
74b04a01
XL
392 }
393 // Opaque types desugared from `impl Trait`.
f035d41b
XL
394 ItemKind::OpaqueTy(OpaqueTy { impl_trait_fn: Some(owner), .. }) => {
395 let concrete_ty = tcx
396 .mir_borrowck(owner.expect_local())
397 .concrete_opaque_types
136023e0 398 .get_value_matching(|(key, _)| key.def_id == def_id.to_def_id())
17df50a5 399 .map(|concrete_ty| *concrete_ty)
74b04a01
XL
400 .unwrap_or_else(|| {
401 tcx.sess.delay_span_bug(
402 DUMMY_SP,
403 &format!(
3dfed10e 404 "owner {:?} has no opaque type for {:?} in its typeck results",
74b04a01
XL
405 owner, def_id,
406 ),
407 );
ba9703b0 408 if let Some(ErrorReported) =
3dfed10e 409 tcx.typeck(owner.expect_local()).tainted_by_errors
ba9703b0 410 {
74b04a01
XL
411 // Some error in the
412 // owner fn prevented us from populating
413 // the `concrete_opaque_types` table.
f035d41b 414 tcx.ty_error()
74b04a01
XL
415 } else {
416 // We failed to resolve the opaque type or it
417 // resolves to itself. Return the non-revealed
418 // type, which should result in E0720.
419 tcx.mk_opaque(
3dfed10e
XL
420 def_id.to_def_id(),
421 InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
74b04a01
XL
422 )
423 }
424 });
425 debug!("concrete_ty = {:?}", concrete_ty);
74b04a01
XL
426 concrete_ty
427 }
428 ItemKind::Trait(..)
429 | ItemKind::TraitAlias(..)
94222f64 430 | ItemKind::Macro(..)
74b04a01 431 | ItemKind::Mod(..)
fc512014 432 | ItemKind::ForeignMod { .. }
74b04a01
XL
433 | ItemKind::GlobalAsm(..)
434 | ItemKind::ExternCrate(..)
435 | ItemKind::Use(..) => {
436 span_bug!(
437 item.span,
438 "compute_type_of_item: unexpected item type: {:?}",
439 item.kind
440 );
441 }
442 }
443 }
444
445 Node::ForeignItem(foreign_item) => match foreign_item.kind {
446 ForeignItemKind::Fn(..) => {
3dfed10e
XL
447 let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
448 tcx.mk_fn_def(def_id.to_def_id(), substs)
74b04a01
XL
449 }
450 ForeignItemKind::Static(ref t, _) => icx.to_ty(t),
3dfed10e 451 ForeignItemKind::Type => tcx.mk_foreign(def_id.to_def_id()),
74b04a01
XL
452 },
453
454 Node::Ctor(&ref def) | Node::Variant(Variant { data: ref def, .. }) => match *def {
455 VariantData::Unit(..) | VariantData::Struct(..) => {
ba9703b0 456 tcx.type_of(tcx.hir().get_parent_did(hir_id).to_def_id())
74b04a01
XL
457 }
458 VariantData::Tuple(..) => {
3dfed10e
XL
459 let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
460 tcx.mk_fn_def(def_id.to_def_id(), substs)
74b04a01
XL
461 }
462 },
463
464 Node::Field(field) => icx.to_ty(&field.ty),
465
466 Node::Expr(&Expr { kind: ExprKind::Closure(.., gen), .. }) => {
3dfed10e 467 let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
ba9703b0 468 if let Some(movability) = gen {
3dfed10e 469 tcx.mk_generator(def_id.to_def_id(), substs, movability)
ba9703b0 470 } else {
3dfed10e 471 tcx.mk_closure(def_id.to_def_id(), substs)
ba9703b0 472 }
74b04a01
XL
473 }
474
94222f64
XL
475 Node::AnonConst(_) if let Some(param) = tcx.opt_const_param_of(def_id) => {
476 // We defer to `type_of` of the corresponding parameter
477 // for generic arguments.
478 tcx.type_of(param)
479 }
3dfed10e 480
94222f64 481 Node::AnonConst(_) => {
74b04a01
XL
482 let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
483 match parent_node {
484 Node::Ty(&Ty { kind: TyKind::Array(_, ref constant), .. })
74b04a01
XL
485 | Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
486 if constant.hir_id == hir_id =>
487 {
488 tcx.types.usize
489 }
cdc7bbd5
XL
490 Node::Ty(&Ty { kind: TyKind::Typeof(ref e), .. }) if e.hir_id == hir_id => {
491 tcx.typeck(def_id).node_type(e.hir_id)
492 }
74b04a01 493
29967ef6
XL
494 Node::Expr(&Expr { kind: ExprKind::ConstBlock(ref anon_const), .. })
495 if anon_const.hir_id == hir_id =>
496 {
497 tcx.typeck(def_id).node_type(anon_const.hir_id)
498 }
499
17df50a5
XL
500 Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
501 | Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. })
502 if asm.operands.iter().any(|(op, _op_sp)| match op {
cdc7bbd5
XL
503 hir::InlineAsmOperand::Const { anon_const } => anon_const.hir_id == hir_id,
504 _ => false,
505 }) =>
506 {
507 tcx.typeck(def_id).node_type(hir_id)
508 }
509
ba9703b0
XL
510 Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => tcx
511 .adt_def(tcx.hir().get_parent_did(hir_id).to_def_id())
512 .repr
513 .discr_type()
514 .to_ty(tcx),
74b04a01 515
cdc7bbd5
XL
516 Node::GenericParam(&GenericParam {
517 hir_id: param_hir_id,
518 kind: GenericParamKind::Const { default: Some(ct), .. },
519 ..
520 }) if ct.hir_id == hir_id => tcx.type_of(tcx.hir().local_def_id(param_hir_id)),
521
f035d41b
XL
522 x => tcx.ty_error_with_message(
523 DUMMY_SP,
136023e0 524 &format!("unexpected const parent in type_of(): {:?}", x),
f035d41b 525 ),
74b04a01
XL
526 }
527 }
528
529 Node::GenericParam(param) => match &param.kind {
3dfed10e
XL
530 GenericParamKind::Type { default: Some(ty), .. }
531 | GenericParamKind::Const { ty, .. } => icx.to_ty(ty),
74b04a01
XL
532 x => bug!("unexpected non-type Node::GenericParam: {:?}", x),
533 },
534
535 x => {
136023e0 536 bug!("unexpected sort of node in type_of(): {:?}", x);
74b04a01
XL
537 }
538 }
539}
540
136023e0 541#[instrument(skip(tcx), level = "debug")]
f9f354fc 542fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
74b04a01
XL
543 use rustc_hir::{Expr, ImplItem, Item, TraitItem};
544
74b04a01
XL
545 struct ConstraintLocator<'tcx> {
546 tcx: TyCtxt<'tcx>,
136023e0
XL
547
548 /// def_id of the opaque type whose defining uses are being checked
74b04a01 549 def_id: DefId,
136023e0
XL
550
551 /// as we walk the defining uses, we are checking that all of them
552 /// define the same hidden type. This variable is set to `Some`
553 /// with the first type that we find, and then later types are
554 /// checked against it (we also carry the span of that first
555 /// type).
ba9703b0 556 found: Option<(Span, Ty<'tcx>)>,
74b04a01
XL
557 }
558
559 impl ConstraintLocator<'_> {
136023e0 560 #[instrument(skip(self), level = "debug")]
f9f354fc 561 fn check(&mut self, def_id: LocalDefId) {
74b04a01 562 // Don't try to check items that cannot possibly constrain the type.
3dfed10e 563 if !self.tcx.has_typeck_results(def_id) {
136023e0 564 debug!("no constraint: no typeck results");
74b04a01
XL
565 return;
566 }
567 // Calling `mir_borrowck` can lead to cycle errors through
568 // const-checking, avoid calling it if we don't have to.
94222f64 569 if !self.tcx.typeck(def_id).concrete_opaque_types.contains(&self.def_id) {
136023e0 570 debug!("no constraints in typeck results");
74b04a01
XL
571 return;
572 }
573 // Use borrowck to get the type with unerased regions.
17df50a5 574 let concrete_opaque_types = &self.tcx.mir_borrowck(def_id).concrete_opaque_types;
136023e0
XL
575 debug!(?concrete_opaque_types);
576 for (opaque_type_key, concrete_type) in concrete_opaque_types {
577 if opaque_type_key.def_id != self.def_id {
578 // Ignore constraints for other opaque types.
579 continue;
580 }
581
582 debug!(?concrete_type, ?opaque_type_key.substs, "found constraint");
74b04a01
XL
583
584 // FIXME(oli-obk): trace the actual span from inference to improve errors.
585 let span = self.tcx.def_span(def_id);
ba9703b0
XL
586
587 // HACK(eddyb) this check shouldn't be needed, as `wfcheck`
588 // performs the same checks, in theory, but I've kept it here
589 // using `delay_span_bug`, just in case `wfcheck` slips up.
590 let opaque_generics = self.tcx.generics_of(self.def_id);
591 let mut used_params: FxHashSet<_> = FxHashSet::default();
17df50a5 592 for (i, arg) in opaque_type_key.substs.iter().enumerate() {
ba9703b0 593 let arg_is_param = match arg.unpack() {
1b1a35ee 594 GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
ba9703b0
XL
595 GenericArgKind::Lifetime(lt) => {
596 matches!(lt, ty::ReEarlyBound(_) | ty::ReFree(_))
597 }
598 GenericArgKind::Const(ct) => matches!(ct.val, ty::ConstKind::Param(_)),
599 };
600
601 if arg_is_param {
602 if !used_params.insert(arg) {
603 // There was already an entry for `arg`, meaning a generic parameter
604 // was used twice.
74b04a01
XL
605 self.tcx.sess.delay_span_bug(
606 span,
607 &format!(
ba9703b0
XL
608 "defining opaque type use restricts opaque \
609 type by using the generic parameter `{}` twice",
610 arg,
74b04a01
XL
611 ),
612 );
613 }
ba9703b0
XL
614 } else {
615 let param = opaque_generics.param_at(i, self.tcx);
616 self.tcx.sess.delay_span_bug(
74b04a01
XL
617 span,
618 &format!(
619 "defining opaque type use does not fully define opaque type: \
ba9703b0
XL
620 generic parameter `{}` is specified as concrete {} `{}`",
621 param.name,
622 param.kind.descr(),
623 arg,
74b04a01
XL
624 ),
625 );
626 }
ba9703b0
XL
627 }
628
629 if let Some((prev_span, prev_ty)) = self.found {
630 if *concrete_type != prev_ty {
136023e0 631 debug!(?span);
74b04a01
XL
632 // Found different concrete types for the opaque type.
633 let mut err = self.tcx.sess.struct_span_err(
634 span,
635 "concrete type differs from previous defining opaque type use",
636 );
637 err.span_label(
638 span,
639 format!("expected `{}`, got `{}`", prev_ty, concrete_type),
640 );
641 err.span_note(prev_span, "previous use here");
642 err.emit();
74b04a01
XL
643 }
644 } else {
ba9703b0 645 self.found = Some((span, concrete_type));
74b04a01 646 }
74b04a01
XL
647 }
648 }
649 }
650
651 impl<'tcx> intravisit::Visitor<'tcx> for ConstraintLocator<'tcx> {
652 type Map = Map<'tcx>;
653
ba9703b0
XL
654 fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
655 intravisit::NestedVisitorMap::All(self.tcx.hir())
74b04a01
XL
656 }
657 fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
658 if let hir::ExprKind::Closure(..) = ex.kind {
659 let def_id = self.tcx.hir().local_def_id(ex.hir_id);
660 self.check(def_id);
661 }
662 intravisit::walk_expr(self, ex);
663 }
664 fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
665 debug!("find_existential_constraints: visiting {:?}", it);
74b04a01 666 // The opaque type itself or its children are not within its reveal scope.
6a06907d
XL
667 if it.def_id.to_def_id() != self.def_id {
668 self.check(it.def_id);
74b04a01
XL
669 intravisit::walk_item(self, it);
670 }
671 }
672 fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
673 debug!("find_existential_constraints: visiting {:?}", it);
74b04a01 674 // The opaque type itself or its children are not within its reveal scope.
6a06907d
XL
675 if it.def_id.to_def_id() != self.def_id {
676 self.check(it.def_id);
74b04a01
XL
677 intravisit::walk_impl_item(self, it);
678 }
679 }
680 fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
681 debug!("find_existential_constraints: visiting {:?}", it);
6a06907d 682 self.check(it.def_id);
74b04a01
XL
683 intravisit::walk_trait_item(self, it);
684 }
685 }
686
3dfed10e 687 let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
74b04a01 688 let scope = tcx.hir().get_defining_scope(hir_id);
f9f354fc 689 let mut locator = ConstraintLocator { def_id: def_id.to_def_id(), tcx, found: None };
74b04a01
XL
690
691 debug!("find_opaque_ty_constraints: scope={:?}", scope);
692
693 if scope == hir::CRATE_HIR_ID {
694 intravisit::walk_crate(&mut locator, tcx.hir().krate());
695 } else {
696 debug!("find_opaque_ty_constraints: scope={:?}", tcx.hir().get(scope));
697 match tcx.hir().get(scope) {
698 // We explicitly call `visit_*` methods, instead of using `intravisit::walk_*` methods
699 // This allows our visitor to process the defining item itself, causing
700 // it to pick up any 'sibling' defining uses.
701 //
702 // For example, this code:
703 // ```
704 // fn foo() {
705 // type Blah = impl Debug;
706 // let my_closure = || -> Blah { true };
707 // }
708 // ```
709 //
710 // requires us to explicitly process `foo()` in order
711 // to notice the defining usage of `Blah`.
712 Node::Item(ref it) => locator.visit_item(it),
713 Node::ImplItem(ref it) => locator.visit_impl_item(it),
714 Node::TraitItem(ref it) => locator.visit_trait_item(it),
715 other => bug!("{:?} is not a valid scope for an opaque type item", other),
716 }
717 }
718
719 match locator.found {
ba9703b0 720 Some((_, ty)) => ty,
74b04a01
XL
721 None => {
722 let span = tcx.def_span(def_id);
723 tcx.sess.span_err(span, "could not find defining uses");
f035d41b 724 tcx.ty_error()
74b04a01
XL
725 }
726 }
727}
728
136023e0
XL
729fn infer_placeholder_type<'a>(
730 tcx: TyCtxt<'a>,
f9f354fc 731 def_id: LocalDefId,
74b04a01
XL
732 body_id: hir::BodyId,
733 span: Span,
734 item_ident: Ident,
136023e0
XL
735 kind: &'static str,
736) -> Ty<'a> {
737 // Attempts to make the type nameable by turning FnDefs into FnPtrs.
738 struct MakeNameable<'tcx> {
739 success: bool,
740 tcx: TyCtxt<'tcx>,
741 }
742
743 impl<'tcx> MakeNameable<'tcx> {
744 fn new(tcx: TyCtxt<'tcx>) -> Self {
745 MakeNameable { success: true, tcx }
746 }
747 }
748
749 impl TypeFolder<'tcx> for MakeNameable<'tcx> {
750 fn tcx(&self) -> TyCtxt<'tcx> {
751 self.tcx
752 }
753
754 fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
755 if !self.success {
756 return ty;
757 }
758
759 match ty.kind() {
760 ty::FnDef(def_id, _) => self.tcx.mk_fn_ptr(self.tcx.fn_sig(*def_id)),
761 // FIXME: non-capturing closures should also suggest a function pointer
762 ty::Closure(..) | ty::Generator(..) => {
763 self.success = false;
764 ty
765 }
766 _ => ty.super_fold_with(self),
767 }
768 }
769 }
770
3dfed10e 771 let ty = tcx.diagnostic_only_typeck(def_id).node_type(body_id.hir_id);
74b04a01
XL
772
773 // If this came from a free `const` or `static mut?` item,
774 // then the user may have written e.g. `const A = 42;`.
775 // In this case, the parser has stashed a diagnostic for
776 // us to improve in typeck so we do that now.
777 match tcx.sess.diagnostic().steal_diagnostic(span, StashKey::ItemNoType) {
778 Some(mut err) => {
779 // The parser provided a sub-optimal `HasPlaceholders` suggestion for the type.
780 // We are typeck and have the real type, so remove that and suggest the actual type.
781 err.suggestions.clear();
136023e0
XL
782
783 // Suggesting unnameable types won't help.
784 let mut mk_nameable = MakeNameable::new(tcx);
785 let ty = mk_nameable.fold_ty(ty);
786 let sugg_ty = if mk_nameable.success { Some(ty) } else { None };
787 if let Some(sugg_ty) = sugg_ty {
788 err.span_suggestion(
789 span,
790 &format!("provide a type for the {item}", item = kind),
791 format!("{}: {}", item_ident, sugg_ty),
792 Applicability::MachineApplicable,
793 );
794 } else {
795 err.span_note(
796 tcx.hir().body(body_id).value.span,
797 &format!("however, the inferred type `{}` cannot be named", ty.to_string()),
798 );
799 }
800
801 err.emit_unless(ty.references_error());
74b04a01
XL
802 }
803 None => {
136023e0 804 let mut diag = bad_placeholder_type(tcx, vec![span], kind);
6a06907d
XL
805
806 if !ty.references_error() {
136023e0
XL
807 let mut mk_nameable = MakeNameable::new(tcx);
808 let ty = mk_nameable.fold_ty(ty);
809 let sugg_ty = if mk_nameable.success { Some(ty) } else { None };
810 if let Some(sugg_ty) = sugg_ty {
811 diag.span_suggestion(
812 span,
813 "replace with the correct type",
814 sugg_ty.to_string(),
815 Applicability::MaybeIncorrect,
816 );
817 } else {
818 diag.span_note(
819 tcx.hir().body(body_id).value.span,
820 &format!("however, the inferred type `{}` cannot be named", ty.to_string()),
821 );
822 }
74b04a01 823 }
6a06907d 824
74b04a01
XL
825 diag.emit();
826 }
827 }
828
ba9703b0 829 // Typeck doesn't expect erased regions to be returned from `type_of`.
fc512014 830 tcx.fold_regions(ty, &mut false, |r, _| match r {
ba9703b0
XL
831 ty::ReErased => tcx.lifetimes.re_static,
832 _ => r,
833 })
74b04a01
XL
834}
835
6a06907d
XL
836fn check_feature_inherent_assoc_ty(tcx: TyCtxt<'_>, span: Span) {
837 if !tcx.features().inherent_associated_types {
838 use rustc_session::parse::feature_err;
839 use rustc_span::symbol::sym;
840 feature_err(
841 &tcx.sess.parse_sess,
842 sym::inherent_associated_types,
843 span,
844 "inherent associated types are unstable",
845 )
846 .emit();
847 }
74b04a01 848}