]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_hir_analysis/src/check/mod.rs
Auto merge of #107141 - notriddle:notriddle/max-lev-distance-2023, r=GuillaumeGomez
[rust.git] / compiler / rustc_hir_analysis / src / check / mod.rs
1 /*!
2
3 # typeck: check phase
4
5 Within the check phase of type check, we check each item one at a time
6 (bodies of function expressions are checked as part of the containing
7 function). Inference is used to supply types wherever they are unknown.
8
9 By far the most complex case is checking the body of a function. This
10 can be broken down into several distinct phases:
11
12 - gather: creates type variables to represent the type of each local
13   variable and pattern binding.
14
15 - main: the main pass does the lion's share of the work: it
16   determines the types of all expressions, resolves
17   methods, checks for most invalid conditions, and so forth. In
18   some cases, where a type is unknown, it may create a type or region
19   variable and use that as the type of an expression.
20
21   In the process of checking, various constraints will be placed on
22   these type variables through the subtyping relationships requested
23   through the `demand` module. The `infer` module is in charge
24   of resolving those constraints.
25
26 - regionck: after main is complete, the regionck pass goes over all
27   types looking for regions and making sure that they did not escape
28   into places where they are not in scope. This may also influence the
29   final assignments of the various region variables if there is some
30   flexibility.
31
32 - writeback: writes the final types within a function body, replacing
33   type variables with their final inferred types. These final types
34   are written into the `tcx.node_types` table, which should *never* contain
35   any reference to a type variable.
36
37 ## Intermediate types
38
39 While type checking a function, the intermediate types for the
40 expressions, blocks, and so forth contained within the function are
41 stored in `fcx.node_types` and `fcx.node_substs`. These types
42 may contain unresolved type variables. After type checking is
43 complete, the functions in the writeback module are used to take the
44 types from this table, resolve them, and then write them into their
45 permanent home in the type context `tcx`.
46
47 This means that during inferencing you should use `fcx.write_ty()`
48 and `fcx.expr_ty()` / `fcx.node_ty()` to write/obtain the types of
49 nodes within the function.
50
51 The types of top-level items, which never contain unbound type
52 variables, are stored directly into the `tcx` typeck_results.
53
54 N.B., a type variable is not the same thing as a type parameter. A
55 type variable is an instance of a type parameter. That is,
56 given a generic function `fn foo<T>(t: T)`, while checking the
57 function `foo`, the type `ty_param(0)` refers to the type `T`, which
58 is treated in abstract. However, when `foo()` is called, `T` will be
59 substituted for a fresh type variable `N`. This variable will
60 eventually be resolved to some concrete type (which might itself be
61 a type parameter).
62
63 */
64
65 mod check;
66 mod compare_impl_item;
67 pub mod dropck;
68 pub mod intrinsic;
69 pub mod intrinsicck;
70 mod region;
71 pub mod wfcheck;
72
73 pub use check::check_abi;
74
75 use check::check_mod_item_types;
76 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
77 use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder};
78 use rustc_hir as hir;
79 use rustc_hir::def_id::{DefId, LocalDefId};
80 use rustc_hir::intravisit::Visitor;
81 use rustc_index::bit_set::BitSet;
82 use rustc_middle::ty::query::Providers;
83 use rustc_middle::ty::{self, Ty, TyCtxt};
84 use rustc_middle::ty::{InternalSubsts, SubstsRef};
85 use rustc_session::parse::feature_err;
86 use rustc_span::source_map::DUMMY_SP;
87 use rustc_span::symbol::{kw, Ident};
88 use rustc_span::{self, BytePos, Span, Symbol};
89 use rustc_target::abi::VariantIdx;
90 use rustc_target::spec::abi::Abi;
91 use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
92 use std::num::NonZeroU32;
93
94 use crate::require_c_abi_if_c_variadic;
95 use crate::util::common::indenter;
96
97 use self::compare_impl_item::collect_return_position_impl_trait_in_trait_tys;
98 use self::region::region_scope_tree;
99
100 pub fn provide(providers: &mut Providers) {
101     wfcheck::provide(providers);
102     *providers = Providers {
103         adt_destructor,
104         check_mod_item_types,
105         region_scope_tree,
106         collect_return_position_impl_trait_in_trait_tys,
107         compare_impl_const: compare_impl_item::compare_impl_const_raw,
108         check_generator_obligations: check::check_generator_obligations,
109         ..*providers
110     };
111 }
112
113 fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::Destructor> {
114     tcx.calculate_dtor(def_id, dropck::check_drop_impl)
115 }
116
117 /// Given a `DefId` for an opaque type in return position, find its parent item's return
118 /// expressions.
119 fn get_owner_return_paths(
120     tcx: TyCtxt<'_>,
121     def_id: LocalDefId,
122 ) -> Option<(LocalDefId, ReturnsVisitor<'_>)> {
123     let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
124     let parent_id = tcx.hir().get_parent_item(hir_id).def_id;
125     tcx.hir().find_by_def_id(parent_id).and_then(|node| node.body_id()).map(|body_id| {
126         let body = tcx.hir().body(body_id);
127         let mut visitor = ReturnsVisitor::default();
128         visitor.visit_body(body);
129         (parent_id, visitor)
130     })
131 }
132
133 /// Forbid defining intrinsics in Rust code,
134 /// as they must always be defined by the compiler.
135 // FIXME: Move this to a more appropriate place.
136 pub fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) {
137     if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
138         tcx.sess.span_err(sp, "intrinsic must be in `extern \"rust-intrinsic\" { ... }` block");
139     }
140 }
141
142 fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) {
143     // Only restricted on wasm target for now
144     if !tcx.sess.target.is_like_wasm {
145         return;
146     }
147
148     // If `#[link_section]` is missing, then nothing to verify
149     let attrs = tcx.codegen_fn_attrs(id);
150     if attrs.link_section.is_none() {
151         return;
152     }
153
154     // For the wasm32 target statics with `#[link_section]` are placed into custom
155     // sections of the final output file, but this isn't link custom sections of
156     // other executable formats. Namely we can only embed a list of bytes,
157     // nothing with provenance (pointers to anything else). If any provenance
158     // show up, reject it here.
159     // `#[link_section]` may contain arbitrary, or even undefined bytes, but it is
160     // the consumer's responsibility to ensure all bytes that have been read
161     // have defined values.
162     if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id())
163         && alloc.inner().provenance().ptrs().len() != 0
164     {
165         let msg = "statics with a custom `#[link_section]` must be a \
166                         simple list of bytes on the wasm target with no \
167                         extra levels of indirection such as references";
168         tcx.sess.span_err(tcx.def_span(id), msg);
169     }
170 }
171
172 fn report_forbidden_specialization(
173     tcx: TyCtxt<'_>,
174     impl_item: &hir::ImplItemRef,
175     parent_impl: DefId,
176 ) {
177     let mut err = struct_span_err!(
178         tcx.sess,
179         impl_item.span,
180         E0520,
181         "`{}` specializes an item from a parent `impl`, but \
182          that item is not marked `default`",
183         impl_item.ident
184     );
185     err.span_label(impl_item.span, format!("cannot specialize default item `{}`", impl_item.ident));
186
187     match tcx.span_of_impl(parent_impl) {
188         Ok(span) => {
189             err.span_label(span, "parent `impl` is here");
190             err.note(&format!(
191                 "to specialize, `{}` in the parent `impl` must be marked `default`",
192                 impl_item.ident
193             ));
194         }
195         Err(cname) => {
196             err.note(&format!("parent implementation is in crate `{cname}`"));
197         }
198     }
199
200     err.emit();
201 }
202
203 fn missing_items_err(
204     tcx: TyCtxt<'_>,
205     impl_span: Span,
206     missing_items: &[&ty::AssocItem],
207     full_impl_span: Span,
208 ) {
209     let missing_items_msg = missing_items
210         .iter()
211         .map(|trait_item| trait_item.name.to_string())
212         .collect::<Vec<_>>()
213         .join("`, `");
214
215     let mut err = struct_span_err!(
216         tcx.sess,
217         impl_span,
218         E0046,
219         "not all trait items implemented, missing: `{missing_items_msg}`",
220     );
221     err.span_label(impl_span, format!("missing `{missing_items_msg}` in implementation"));
222
223     // `Span` before impl block closing brace.
224     let hi = full_impl_span.hi() - BytePos(1);
225     // Point at the place right before the closing brace of the relevant `impl` to suggest
226     // adding the associated item at the end of its body.
227     let sugg_sp = full_impl_span.with_lo(hi).with_hi(hi);
228     // Obtain the level of indentation ending in `sugg_sp`.
229     let padding =
230         tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(|| String::new());
231
232     for trait_item in missing_items {
233         let snippet = suggestion_signature(trait_item, tcx);
234         let code = format!("{}{}\n{}", padding, snippet, padding);
235         let msg = format!("implement the missing item: `{snippet}`");
236         let appl = Applicability::HasPlaceholders;
237         if let Some(span) = tcx.hir().span_if_local(trait_item.def_id) {
238             err.span_label(span, format!("`{}` from trait", trait_item.name));
239             err.tool_only_span_suggestion(sugg_sp, &msg, code, appl);
240         } else {
241             err.span_suggestion_hidden(sugg_sp, &msg, code, appl);
242         }
243     }
244     err.emit();
245 }
246
247 fn missing_items_must_implement_one_of_err(
248     tcx: TyCtxt<'_>,
249     impl_span: Span,
250     missing_items: &[Ident],
251     annotation_span: Option<Span>,
252 ) {
253     let missing_items_msg =
254         missing_items.iter().map(Ident::to_string).collect::<Vec<_>>().join("`, `");
255
256     let mut err = struct_span_err!(
257         tcx.sess,
258         impl_span,
259         E0046,
260         "not all trait items implemented, missing one of: `{missing_items_msg}`",
261     );
262     err.span_label(impl_span, format!("missing one of `{missing_items_msg}` in implementation"));
263
264     if let Some(annotation_span) = annotation_span {
265         err.span_note(annotation_span, "required because of this annotation");
266     }
267
268     err.emit();
269 }
270
271 fn default_body_is_unstable(
272     tcx: TyCtxt<'_>,
273     impl_span: Span,
274     item_did: DefId,
275     feature: Symbol,
276     reason: Option<Symbol>,
277     issue: Option<NonZeroU32>,
278 ) {
279     let missing_item_name = &tcx.associated_item(item_did).name;
280     let use_of_unstable_library_feature_note = match reason {
281         Some(r) => format!("use of unstable library feature '{feature}': {r}"),
282         None => format!("use of unstable library feature '{feature}'"),
283     };
284
285     let mut err = struct_span_err!(
286         tcx.sess,
287         impl_span,
288         E0046,
289         "not all trait items implemented, missing: `{missing_item_name}`",
290     );
291     err.note(format!("default implementation of `{missing_item_name}` is unstable"));
292     err.note(use_of_unstable_library_feature_note);
293     rustc_session::parse::add_feature_diagnostics_for_issue(
294         &mut err,
295         &tcx.sess.parse_sess,
296         feature,
297         rustc_feature::GateIssue::Library(issue),
298     );
299     err.emit();
300 }
301
302 /// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions.
303 fn bounds_from_generic_predicates<'tcx>(
304     tcx: TyCtxt<'tcx>,
305     predicates: ty::GenericPredicates<'tcx>,
306 ) -> (String, String) {
307     let mut types: FxHashMap<Ty<'tcx>, Vec<DefId>> = FxHashMap::default();
308     let mut projections = vec![];
309     for (predicate, _) in predicates.predicates {
310         debug!("predicate {:?}", predicate);
311         let bound_predicate = predicate.kind();
312         match bound_predicate.skip_binder() {
313             ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => {
314                 let entry = types.entry(trait_predicate.self_ty()).or_default();
315                 let def_id = trait_predicate.def_id();
316                 if Some(def_id) != tcx.lang_items().sized_trait() {
317                     // Type params are `Sized` by default, do not add that restriction to the list
318                     // if it is a positive requirement.
319                     entry.push(trait_predicate.def_id());
320                 }
321             }
322             ty::PredicateKind::Clause(ty::Clause::Projection(projection_pred)) => {
323                 projections.push(bound_predicate.rebind(projection_pred));
324             }
325             _ => {}
326         }
327     }
328     let generics = if types.is_empty() {
329         "".to_string()
330     } else {
331         format!(
332             "<{}>",
333             types
334                 .keys()
335                 .filter_map(|t| match t.kind() {
336                     ty::Param(_) => Some(t.to_string()),
337                     // Avoid suggesting the following:
338                     // fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {}
339                     _ => None,
340                 })
341                 .collect::<Vec<_>>()
342                 .join(", ")
343         )
344     };
345     let mut where_clauses = vec![];
346     for (ty, bounds) in types {
347         where_clauses
348             .extend(bounds.into_iter().map(|bound| format!("{}: {}", ty, tcx.def_path_str(bound))));
349     }
350     for projection in &projections {
351         let p = projection.skip_binder();
352         // FIXME: this is not currently supported syntax, we should be looking at the `types` and
353         // insert the associated types where they correspond, but for now let's be "lazy" and
354         // propose this instead of the following valid resugaring:
355         // `T: Trait, Trait::Assoc = K` → `T: Trait<Assoc = K>`
356         where_clauses.push(format!("{} = {}", tcx.def_path_str(p.projection_ty.def_id), p.term));
357     }
358     let where_clauses = if where_clauses.is_empty() {
359         String::new()
360     } else {
361         format!(" where {}", where_clauses.join(", "))
362     };
363     (generics, where_clauses)
364 }
365
366 /// Return placeholder code for the given function.
367 fn fn_sig_suggestion<'tcx>(
368     tcx: TyCtxt<'tcx>,
369     sig: ty::FnSig<'tcx>,
370     ident: Ident,
371     predicates: ty::GenericPredicates<'tcx>,
372     assoc: &ty::AssocItem,
373 ) -> String {
374     let args = sig
375         .inputs()
376         .iter()
377         .enumerate()
378         .map(|(i, ty)| {
379             Some(match ty.kind() {
380                 ty::Param(_) if assoc.fn_has_self_parameter && i == 0 => "self".to_string(),
381                 ty::Ref(reg, ref_ty, mutability) if i == 0 => {
382                     let reg = format!("{reg} ");
383                     let reg = match &reg[..] {
384                         "'_ " | " " => "",
385                         reg => reg,
386                     };
387                     if assoc.fn_has_self_parameter {
388                         match ref_ty.kind() {
389                             ty::Param(param) if param.name == kw::SelfUpper => {
390                                 format!("&{}{}self", reg, mutability.prefix_str())
391                             }
392
393                             _ => format!("self: {ty}"),
394                         }
395                     } else {
396                         format!("_: {ty}")
397                     }
398                 }
399                 _ => {
400                     if assoc.fn_has_self_parameter && i == 0 {
401                         format!("self: {ty}")
402                     } else {
403                         format!("_: {ty}")
404                     }
405                 }
406             })
407         })
408         .chain(std::iter::once(if sig.c_variadic { Some("...".to_string()) } else { None }))
409         .flatten()
410         .collect::<Vec<String>>()
411         .join(", ");
412     let output = sig.output();
413     let output = if !output.is_unit() { format!(" -> {output}") } else { String::new() };
414
415     let unsafety = sig.unsafety.prefix_str();
416     let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates);
417
418     // FIXME: this is not entirely correct, as the lifetimes from borrowed params will
419     // not be present in the `fn` definition, not will we account for renamed
420     // lifetimes between the `impl` and the `trait`, but this should be good enough to
421     // fill in a significant portion of the missing code, and other subsequent
422     // suggestions can help the user fix the code.
423     format!("{unsafety}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}")
424 }
425
426 pub fn ty_kind_suggestion(ty: Ty<'_>) -> Option<&'static str> {
427     Some(match ty.kind() {
428         ty::Bool => "true",
429         ty::Char => "'a'",
430         ty::Int(_) | ty::Uint(_) => "42",
431         ty::Float(_) => "3.14159",
432         ty::Error(_) | ty::Never => return None,
433         _ => "value",
434     })
435 }
436
437 /// Return placeholder code for the given associated item.
438 /// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a
439 /// structured suggestion.
440 fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String {
441     match assoc.kind {
442         ty::AssocKind::Fn => {
443             // We skip the binder here because the binder would deanonymize all
444             // late-bound regions, and we don't want method signatures to show up
445             // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
446             // regions just fine, showing `fn(&MyType)`.
447             fn_sig_suggestion(
448                 tcx,
449                 tcx.fn_sig(assoc.def_id).subst_identity().skip_binder(),
450                 assoc.ident(tcx),
451                 tcx.predicates_of(assoc.def_id),
452                 assoc,
453             )
454         }
455         ty::AssocKind::Type => format!("type {} = Type;", assoc.name),
456         ty::AssocKind::Const => {
457             let ty = tcx.type_of(assoc.def_id);
458             let val = ty_kind_suggestion(ty).unwrap_or("value");
459             format!("const {}: {} = {};", assoc.name, ty, val)
460         }
461     }
462 }
463
464 /// Emit an error when encountering two or more variants in a transparent enum.
465 fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>, sp: Span, did: DefId) {
466     let variant_spans: Vec<_> = adt
467         .variants()
468         .iter()
469         .map(|variant| tcx.hir().span_if_local(variant.def_id).unwrap())
470         .collect();
471     let msg = format!("needs exactly one variant, but has {}", adt.variants().len(),);
472     let mut err = struct_span_err!(tcx.sess, sp, E0731, "transparent enum {msg}");
473     err.span_label(sp, &msg);
474     if let [start @ .., end] = &*variant_spans {
475         for variant_span in start {
476             err.span_label(*variant_span, "");
477         }
478         err.span_label(*end, &format!("too many variants in `{}`", tcx.def_path_str(did)));
479     }
480     err.emit();
481 }
482
483 /// Emit an error when encountering two or more non-zero-sized fields in a transparent
484 /// enum.
485 fn bad_non_zero_sized_fields<'tcx>(
486     tcx: TyCtxt<'tcx>,
487     adt: ty::AdtDef<'tcx>,
488     field_count: usize,
489     field_spans: impl Iterator<Item = Span>,
490     sp: Span,
491 ) {
492     let msg = format!("needs at most one non-zero-sized field, but has {field_count}");
493     let mut err = struct_span_err!(
494         tcx.sess,
495         sp,
496         E0690,
497         "{}transparent {} {}",
498         if adt.is_enum() { "the variant of a " } else { "" },
499         adt.descr(),
500         msg,
501     );
502     err.span_label(sp, &msg);
503     for sp in field_spans {
504         err.span_label(sp, "this field is non-zero-sized");
505     }
506     err.emit();
507 }
508
509 // FIXME: Consider moving this method to a more fitting place.
510 pub fn potentially_plural_count(count: usize, word: &str) -> String {
511     format!("{} {}{}", count, word, pluralize!(count))
512 }