]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_hir_analysis/src/check/mod.rs
Rollup merge of #107015 - cuviper:ra-riscv64, r=Mark-Simulacrum
[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         ..*providers
109     };
110 }
111
112 fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::Destructor> {
113     tcx.calculate_dtor(def_id, dropck::check_drop_impl)
114 }
115
116 /// Given a `DefId` for an opaque type in return position, find its parent item's return
117 /// expressions.
118 fn get_owner_return_paths(
119     tcx: TyCtxt<'_>,
120     def_id: LocalDefId,
121 ) -> Option<(LocalDefId, ReturnsVisitor<'_>)> {
122     let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
123     let parent_id = tcx.hir().get_parent_item(hir_id).def_id;
124     tcx.hir().find_by_def_id(parent_id).and_then(|node| node.body_id()).map(|body_id| {
125         let body = tcx.hir().body(body_id);
126         let mut visitor = ReturnsVisitor::default();
127         visitor.visit_body(body);
128         (parent_id, visitor)
129     })
130 }
131
132 /// Forbid defining intrinsics in Rust code,
133 /// as they must always be defined by the compiler.
134 // FIXME: Move this to a more appropriate place.
135 pub fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) {
136     if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
137         tcx.sess.span_err(sp, "intrinsic must be in `extern \"rust-intrinsic\" { ... }` block");
138     }
139 }
140
141 fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) {
142     // Only restricted on wasm target for now
143     if !tcx.sess.target.is_like_wasm {
144         return;
145     }
146
147     // If `#[link_section]` is missing, then nothing to verify
148     let attrs = tcx.codegen_fn_attrs(id);
149     if attrs.link_section.is_none() {
150         return;
151     }
152
153     // For the wasm32 target statics with `#[link_section]` are placed into custom
154     // sections of the final output file, but this isn't link custom sections of
155     // other executable formats. Namely we can only embed a list of bytes,
156     // nothing with provenance (pointers to anything else). If any provenance
157     // show up, reject it here.
158     // `#[link_section]` may contain arbitrary, or even undefined bytes, but it is
159     // the consumer's responsibility to ensure all bytes that have been read
160     // have defined values.
161     if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id())
162         && alloc.inner().provenance().ptrs().len() != 0
163     {
164         let msg = "statics with a custom `#[link_section]` must be a \
165                         simple list of bytes on the wasm target with no \
166                         extra levels of indirection such as references";
167         tcx.sess.span_err(tcx.def_span(id), msg);
168     }
169 }
170
171 fn report_forbidden_specialization(
172     tcx: TyCtxt<'_>,
173     impl_item: &hir::ImplItemRef,
174     parent_impl: DefId,
175 ) {
176     let mut err = struct_span_err!(
177         tcx.sess,
178         impl_item.span,
179         E0520,
180         "`{}` specializes an item from a parent `impl`, but \
181          that item is not marked `default`",
182         impl_item.ident
183     );
184     err.span_label(impl_item.span, format!("cannot specialize default item `{}`", impl_item.ident));
185
186     match tcx.span_of_impl(parent_impl) {
187         Ok(span) => {
188             err.span_label(span, "parent `impl` is here");
189             err.note(&format!(
190                 "to specialize, `{}` in the parent `impl` must be marked `default`",
191                 impl_item.ident
192             ));
193         }
194         Err(cname) => {
195             err.note(&format!("parent implementation is in crate `{cname}`"));
196         }
197     }
198
199     err.emit();
200 }
201
202 fn missing_items_err(
203     tcx: TyCtxt<'_>,
204     impl_span: Span,
205     missing_items: &[&ty::AssocItem],
206     full_impl_span: Span,
207 ) {
208     let missing_items_msg = missing_items
209         .iter()
210         .map(|trait_item| trait_item.name.to_string())
211         .collect::<Vec<_>>()
212         .join("`, `");
213
214     let mut err = struct_span_err!(
215         tcx.sess,
216         impl_span,
217         E0046,
218         "not all trait items implemented, missing: `{missing_items_msg}`",
219     );
220     err.span_label(impl_span, format!("missing `{missing_items_msg}` in implementation"));
221
222     // `Span` before impl block closing brace.
223     let hi = full_impl_span.hi() - BytePos(1);
224     // Point at the place right before the closing brace of the relevant `impl` to suggest
225     // adding the associated item at the end of its body.
226     let sugg_sp = full_impl_span.with_lo(hi).with_hi(hi);
227     // Obtain the level of indentation ending in `sugg_sp`.
228     let padding =
229         tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(|| String::new());
230
231     for trait_item in missing_items {
232         let snippet = suggestion_signature(trait_item, tcx);
233         let code = format!("{}{}\n{}", padding, snippet, padding);
234         let msg = format!("implement the missing item: `{snippet}`");
235         let appl = Applicability::HasPlaceholders;
236         if let Some(span) = tcx.hir().span_if_local(trait_item.def_id) {
237             err.span_label(span, format!("`{}` from trait", trait_item.name));
238             err.tool_only_span_suggestion(sugg_sp, &msg, code, appl);
239         } else {
240             err.span_suggestion_hidden(sugg_sp, &msg, code, appl);
241         }
242     }
243     err.emit();
244 }
245
246 fn missing_items_must_implement_one_of_err(
247     tcx: TyCtxt<'_>,
248     impl_span: Span,
249     missing_items: &[Ident],
250     annotation_span: Option<Span>,
251 ) {
252     let missing_items_msg =
253         missing_items.iter().map(Ident::to_string).collect::<Vec<_>>().join("`, `");
254
255     let mut err = struct_span_err!(
256         tcx.sess,
257         impl_span,
258         E0046,
259         "not all trait items implemented, missing one of: `{missing_items_msg}`",
260     );
261     err.span_label(impl_span, format!("missing one of `{missing_items_msg}` in implementation"));
262
263     if let Some(annotation_span) = annotation_span {
264         err.span_note(annotation_span, "required because of this annotation");
265     }
266
267     err.emit();
268 }
269
270 fn default_body_is_unstable(
271     tcx: TyCtxt<'_>,
272     impl_span: Span,
273     item_did: DefId,
274     feature: Symbol,
275     reason: Option<Symbol>,
276     issue: Option<NonZeroU32>,
277 ) {
278     let missing_item_name = &tcx.associated_item(item_did).name;
279     let use_of_unstable_library_feature_note = match reason {
280         Some(r) => format!("use of unstable library feature '{feature}': {r}"),
281         None => format!("use of unstable library feature '{feature}'"),
282     };
283
284     let mut err = struct_span_err!(
285         tcx.sess,
286         impl_span,
287         E0046,
288         "not all trait items implemented, missing: `{missing_item_name}`",
289     );
290     err.note(format!("default implementation of `{missing_item_name}` is unstable"));
291     err.note(use_of_unstable_library_feature_note);
292     rustc_session::parse::add_feature_diagnostics_for_issue(
293         &mut err,
294         &tcx.sess.parse_sess,
295         feature,
296         rustc_feature::GateIssue::Library(issue),
297     );
298     err.emit();
299 }
300
301 /// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions.
302 fn bounds_from_generic_predicates<'tcx>(
303     tcx: TyCtxt<'tcx>,
304     predicates: ty::GenericPredicates<'tcx>,
305 ) -> (String, String) {
306     let mut types: FxHashMap<Ty<'tcx>, Vec<DefId>> = FxHashMap::default();
307     let mut projections = vec![];
308     for (predicate, _) in predicates.predicates {
309         debug!("predicate {:?}", predicate);
310         let bound_predicate = predicate.kind();
311         match bound_predicate.skip_binder() {
312             ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => {
313                 let entry = types.entry(trait_predicate.self_ty()).or_default();
314                 let def_id = trait_predicate.def_id();
315                 if Some(def_id) != tcx.lang_items().sized_trait() {
316                     // Type params are `Sized` by default, do not add that restriction to the list
317                     // if it is a positive requirement.
318                     entry.push(trait_predicate.def_id());
319                 }
320             }
321             ty::PredicateKind::Clause(ty::Clause::Projection(projection_pred)) => {
322                 projections.push(bound_predicate.rebind(projection_pred));
323             }
324             _ => {}
325         }
326     }
327     let generics = if types.is_empty() {
328         "".to_string()
329     } else {
330         format!(
331             "<{}>",
332             types
333                 .keys()
334                 .filter_map(|t| match t.kind() {
335                     ty::Param(_) => Some(t.to_string()),
336                     // Avoid suggesting the following:
337                     // fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {}
338                     _ => None,
339                 })
340                 .collect::<Vec<_>>()
341                 .join(", ")
342         )
343     };
344     let mut where_clauses = vec![];
345     for (ty, bounds) in types {
346         where_clauses
347             .extend(bounds.into_iter().map(|bound| format!("{}: {}", ty, tcx.def_path_str(bound))));
348     }
349     for projection in &projections {
350         let p = projection.skip_binder();
351         // FIXME: this is not currently supported syntax, we should be looking at the `types` and
352         // insert the associated types where they correspond, but for now let's be "lazy" and
353         // propose this instead of the following valid resugaring:
354         // `T: Trait, Trait::Assoc = K` → `T: Trait<Assoc = K>`
355         where_clauses.push(format!("{} = {}", tcx.def_path_str(p.projection_ty.def_id), p.term));
356     }
357     let where_clauses = if where_clauses.is_empty() {
358         String::new()
359     } else {
360         format!(" where {}", where_clauses.join(", "))
361     };
362     (generics, where_clauses)
363 }
364
365 /// Return placeholder code for the given function.
366 fn fn_sig_suggestion<'tcx>(
367     tcx: TyCtxt<'tcx>,
368     sig: ty::FnSig<'tcx>,
369     ident: Ident,
370     predicates: ty::GenericPredicates<'tcx>,
371     assoc: &ty::AssocItem,
372 ) -> String {
373     let args = sig
374         .inputs()
375         .iter()
376         .enumerate()
377         .map(|(i, ty)| {
378             Some(match ty.kind() {
379                 ty::Param(_) if assoc.fn_has_self_parameter && i == 0 => "self".to_string(),
380                 ty::Ref(reg, ref_ty, mutability) if i == 0 => {
381                     let reg = format!("{reg} ");
382                     let reg = match &reg[..] {
383                         "'_ " | " " => "",
384                         reg => reg,
385                     };
386                     if assoc.fn_has_self_parameter {
387                         match ref_ty.kind() {
388                             ty::Param(param) if param.name == kw::SelfUpper => {
389                                 format!("&{}{}self", reg, mutability.prefix_str())
390                             }
391
392                             _ => format!("self: {ty}"),
393                         }
394                     } else {
395                         format!("_: {ty}")
396                     }
397                 }
398                 _ => {
399                     if assoc.fn_has_self_parameter && i == 0 {
400                         format!("self: {ty}")
401                     } else {
402                         format!("_: {ty}")
403                     }
404                 }
405             })
406         })
407         .chain(std::iter::once(if sig.c_variadic { Some("...".to_string()) } else { None }))
408         .flatten()
409         .collect::<Vec<String>>()
410         .join(", ");
411     let output = sig.output();
412     let output = if !output.is_unit() { format!(" -> {output}") } else { String::new() };
413
414     let unsafety = sig.unsafety.prefix_str();
415     let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates);
416
417     // FIXME: this is not entirely correct, as the lifetimes from borrowed params will
418     // not be present in the `fn` definition, not will we account for renamed
419     // lifetimes between the `impl` and the `trait`, but this should be good enough to
420     // fill in a significant portion of the missing code, and other subsequent
421     // suggestions can help the user fix the code.
422     format!("{unsafety}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}")
423 }
424
425 pub fn ty_kind_suggestion(ty: Ty<'_>) -> Option<&'static str> {
426     Some(match ty.kind() {
427         ty::Bool => "true",
428         ty::Char => "'a'",
429         ty::Int(_) | ty::Uint(_) => "42",
430         ty::Float(_) => "3.14159",
431         ty::Error(_) | ty::Never => return None,
432         _ => "value",
433     })
434 }
435
436 /// Return placeholder code for the given associated item.
437 /// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a
438 /// structured suggestion.
439 fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String {
440     match assoc.kind {
441         ty::AssocKind::Fn => {
442             // We skip the binder here because the binder would deanonymize all
443             // late-bound regions, and we don't want method signatures to show up
444             // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
445             // regions just fine, showing `fn(&MyType)`.
446             fn_sig_suggestion(
447                 tcx,
448                 tcx.fn_sig(assoc.def_id).skip_binder(),
449                 assoc.ident(tcx),
450                 tcx.predicates_of(assoc.def_id),
451                 assoc,
452             )
453         }
454         ty::AssocKind::Type => format!("type {} = Type;", assoc.name),
455         ty::AssocKind::Const => {
456             let ty = tcx.type_of(assoc.def_id);
457             let val = ty_kind_suggestion(ty).unwrap_or("value");
458             format!("const {}: {} = {};", assoc.name, ty, val)
459         }
460     }
461 }
462
463 /// Emit an error when encountering two or more variants in a transparent enum.
464 fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>, sp: Span, did: DefId) {
465     let variant_spans: Vec<_> = adt
466         .variants()
467         .iter()
468         .map(|variant| tcx.hir().span_if_local(variant.def_id).unwrap())
469         .collect();
470     let msg = format!("needs exactly one variant, but has {}", adt.variants().len(),);
471     let mut err = struct_span_err!(tcx.sess, sp, E0731, "transparent enum {msg}");
472     err.span_label(sp, &msg);
473     if let [start @ .., end] = &*variant_spans {
474         for variant_span in start {
475             err.span_label(*variant_span, "");
476         }
477         err.span_label(*end, &format!("too many variants in `{}`", tcx.def_path_str(did)));
478     }
479     err.emit();
480 }
481
482 /// Emit an error when encountering two or more non-zero-sized fields in a transparent
483 /// enum.
484 fn bad_non_zero_sized_fields<'tcx>(
485     tcx: TyCtxt<'tcx>,
486     adt: ty::AdtDef<'tcx>,
487     field_count: usize,
488     field_spans: impl Iterator<Item = Span>,
489     sp: Span,
490 ) {
491     let msg = format!("needs at most one non-zero-sized field, but has {field_count}");
492     let mut err = struct_span_err!(
493         tcx.sess,
494         sp,
495         E0690,
496         "{}transparent {} {}",
497         if adt.is_enum() { "the variant of a " } else { "" },
498         adt.descr(),
499         msg,
500     );
501     err.span_label(sp, &msg);
502     for sp in field_spans {
503         err.span_label(sp, "this field is non-zero-sized");
504     }
505     err.emit();
506 }
507
508 // FIXME: Consider moving this method to a more fitting place.
509 pub fn potentially_plural_count(count: usize, word: &str) -> String {
510     format!("{} {}{}", count, word, pluralize!(count))
511 }