]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_typeck/src/lib.rs
New upstream version 1.63.0+dfsg1
[rustc.git] / compiler / rustc_typeck / src / lib.rs
1 /*!
2
3 # typeck
4
5 The type checker is responsible for:
6
7 1. Determining the type of each expression.
8 2. Resolving methods and traits.
9 3. Guaranteeing that most type rules are met. ("Most?", you say, "why most?"
10 Well, dear reader, read on.)
11
12 The main entry point is [`check_crate()`]. Type checking operates in
13 several major phases:
14
15 1. The collect phase first passes over all items and determines their
16 type, without examining their "innards".
17
18 2. Variance inference then runs to compute the variance of each parameter.
19
20 3. Coherence checks for overlapping or orphaned impls.
21
22 4. Finally, the check phase then checks function bodies and so forth.
23 Within the check phase, we check each function body one at a time
24 (bodies of function expressions are checked as part of the
25 containing function). Inference is used to supply types wherever
26 they are unknown. The actual checking of a function itself has
27 several phases (check, regionck, writeback), as discussed in the
28 documentation for the [`check`] module.
29
30 The type checker is defined into various submodules which are documented
31 independently:
32
33 - astconv: converts the AST representation of types
34 into the `ty` representation.
35
36 - collect: computes the types of each top-level item and enters them into
37 the `tcx.types` table for later use.
38
39 - coherence: enforces coherence rules, builds some tables.
40
41 - variance: variance inference
42
43 - outlives: outlives inference
44
45 - check: walks over function bodies and type checks them, inferring types for
46 local variables, type parameters, etc as necessary.
47
48 - infer: finds the types to use for each type variable such that
49 all subtyping and assignment constraints are met. In essence, the check
50 module specifies the constraints, and the infer module solves them.
51
52 ## Note
53
54 This API is completely unstable and subject to change.
55
56 */
57
58 #![allow(rustc::potential_query_instability)]
59 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
60 #![feature(box_patterns)]
61 #![feature(control_flow_enum)]
62 #![feature(drain_filter)]
63 #![feature(hash_drain_filter)]
64 #![feature(if_let_guard)]
65 #![feature(is_sorted)]
66 #![feature(iter_intersperse)]
67 #![feature(label_break_value)]
68 #![feature(let_chains)]
69 #![feature(let_else)]
70 #![feature(min_specialization)]
71 #![feature(never_type)]
72 #![feature(once_cell)]
73 #![feature(slice_partition_dedup)]
74 #![feature(try_blocks)]
75 #![recursion_limit = "256"]
76
77 #[macro_use]
78 extern crate tracing;
79
80 #[macro_use]
81 extern crate rustc_middle;
82
83 // These are used by Clippy.
84 pub mod check;
85 pub mod expr_use_visitor;
86
87 mod astconv;
88 mod bounds;
89 mod check_unused;
90 mod coherence;
91 mod collect;
92 mod constrained_generic_params;
93 mod errors;
94 pub mod hir_wf_check;
95 mod impl_wf_check;
96 mod mem_categorization;
97 mod outlives;
98 mod structured_errors;
99 mod variance;
100
101 use rustc_errors::{struct_span_err, ErrorGuaranteed};
102 use rustc_hir as hir;
103 use rustc_hir::def_id::DefId;
104 use rustc_hir::{Node, CRATE_HIR_ID};
105 use rustc_infer::infer::{InferOk, TyCtxtInferExt};
106 use rustc_infer::traits::TraitEngineExt as _;
107 use rustc_middle::middle;
108 use rustc_middle::ty::query::Providers;
109 use rustc_middle::ty::{self, Ty, TyCtxt};
110 use rustc_middle::util;
111 use rustc_session::config::EntryFnType;
112 use rustc_span::{symbol::sym, Span, DUMMY_SP};
113 use rustc_target::spec::abi::Abi;
114 use rustc_trait_selection::infer::InferCtxtExt;
115 use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
116 use rustc_trait_selection::traits::{
117 self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt as _,
118 };
119
120 use std::iter;
121
122 use astconv::AstConv;
123 use bounds::Bounds;
124
125 fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi, span: Span) {
126 match (decl.c_variadic, abi) {
127 // The function has the correct calling convention, or isn't a "C-variadic" function.
128 (false, _) | (true, Abi::C { .. }) | (true, Abi::Cdecl { .. }) => {}
129 // The function is a "C-variadic" function with an incorrect calling convention.
130 (true, _) => {
131 let mut err = struct_span_err!(
132 tcx.sess,
133 span,
134 E0045,
135 "C-variadic function must have C or cdecl calling convention"
136 );
137 err.span_label(span, "C-variadics require C or cdecl calling convention").emit();
138 }
139 }
140 }
141
142 fn require_same_types<'tcx>(
143 tcx: TyCtxt<'tcx>,
144 cause: &ObligationCause<'tcx>,
145 expected: Ty<'tcx>,
146 actual: Ty<'tcx>,
147 ) -> bool {
148 tcx.infer_ctxt().enter(|ref infcx| {
149 let param_env = ty::ParamEnv::empty();
150 let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
151 match infcx.at(cause, param_env).eq(expected, actual) {
152 Ok(InferOk { obligations, .. }) => {
153 fulfill_cx.register_predicate_obligations(infcx, obligations);
154 }
155 Err(err) => {
156 infcx.report_mismatched_types(cause, expected, actual, err).emit();
157 return false;
158 }
159 }
160
161 match fulfill_cx.select_all_or_error(infcx).as_slice() {
162 [] => true,
163 errors => {
164 infcx.report_fulfillment_errors(errors, None, false);
165 false
166 }
167 }
168 })
169 }
170
171 fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
172 let main_fnsig = tcx.fn_sig(main_def_id);
173 let main_span = tcx.def_span(main_def_id);
174
175 fn main_fn_diagnostics_hir_id(tcx: TyCtxt<'_>, def_id: DefId, sp: Span) -> hir::HirId {
176 if let Some(local_def_id) = def_id.as_local() {
177 let hir_id = tcx.hir().local_def_id_to_hir_id(local_def_id);
178 let hir_type = tcx.type_of(local_def_id);
179 if !matches!(hir_type.kind(), ty::FnDef(..)) {
180 span_bug!(sp, "main has a non-function type: found `{}`", hir_type);
181 }
182 hir_id
183 } else {
184 CRATE_HIR_ID
185 }
186 }
187
188 fn main_fn_generics_params_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
189 if !def_id.is_local() {
190 return None;
191 }
192 let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
193 match tcx.hir().find(hir_id) {
194 Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, ref generics, _), .. })) => {
195 if !generics.params.is_empty() {
196 Some(generics.span)
197 } else {
198 None
199 }
200 }
201 _ => {
202 span_bug!(tcx.def_span(def_id), "main has a non-function type");
203 }
204 }
205 }
206
207 fn main_fn_where_clauses_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
208 if !def_id.is_local() {
209 return None;
210 }
211 let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
212 match tcx.hir().find(hir_id) {
213 Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, ref generics, _), .. })) => {
214 Some(generics.where_clause_span)
215 }
216 _ => {
217 span_bug!(tcx.def_span(def_id), "main has a non-function type");
218 }
219 }
220 }
221
222 fn main_fn_asyncness_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
223 if !def_id.is_local() {
224 return None;
225 }
226 let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
227 match tcx.hir().find(hir_id) {
228 Some(Node::Item(hir::Item { span: item_span, .. })) => {
229 Some(tcx.sess.source_map().guess_head_span(*item_span))
230 }
231 _ => {
232 span_bug!(tcx.def_span(def_id), "main has a non-function type");
233 }
234 }
235 }
236
237 fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
238 if !def_id.is_local() {
239 return None;
240 }
241 let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
242 match tcx.hir().find(hir_id) {
243 Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(ref fn_sig, _, _), .. })) => {
244 Some(fn_sig.decl.output.span())
245 }
246 _ => {
247 span_bug!(tcx.def_span(def_id), "main has a non-function type");
248 }
249 }
250 }
251
252 let mut error = false;
253 let main_diagnostics_hir_id = main_fn_diagnostics_hir_id(tcx, main_def_id, main_span);
254 let main_fn_generics = tcx.generics_of(main_def_id);
255 let main_fn_predicates = tcx.predicates_of(main_def_id);
256 if main_fn_generics.count() != 0 || !main_fnsig.bound_vars().is_empty() {
257 let generics_param_span = main_fn_generics_params_span(tcx, main_def_id);
258 let msg = "`main` function is not allowed to have generic \
259 parameters";
260 let mut diag =
261 struct_span_err!(tcx.sess, generics_param_span.unwrap_or(main_span), E0131, "{}", msg);
262 if let Some(generics_param_span) = generics_param_span {
263 let label = "`main` cannot have generic parameters".to_string();
264 diag.span_label(generics_param_span, label);
265 }
266 diag.emit();
267 error = true;
268 } else if !main_fn_predicates.predicates.is_empty() {
269 // generics may bring in implicit predicates, so we skip this check if generics is present.
270 let generics_where_clauses_span = main_fn_where_clauses_span(tcx, main_def_id);
271 let mut diag = struct_span_err!(
272 tcx.sess,
273 generics_where_clauses_span.unwrap_or(main_span),
274 E0646,
275 "`main` function is not allowed to have a `where` clause"
276 );
277 if let Some(generics_where_clauses_span) = generics_where_clauses_span {
278 diag.span_label(generics_where_clauses_span, "`main` cannot have a `where` clause");
279 }
280 diag.emit();
281 error = true;
282 }
283
284 let main_asyncness = tcx.asyncness(main_def_id);
285 if let hir::IsAsync::Async = main_asyncness {
286 let mut diag = struct_span_err!(
287 tcx.sess,
288 main_span,
289 E0752,
290 "`main` function is not allowed to be `async`"
291 );
292 let asyncness_span = main_fn_asyncness_span(tcx, main_def_id);
293 if let Some(asyncness_span) = asyncness_span {
294 diag.span_label(asyncness_span, "`main` function is not allowed to be `async`");
295 }
296 diag.emit();
297 error = true;
298 }
299
300 for attr in tcx.get_attrs(main_def_id, sym::track_caller) {
301 tcx.sess
302 .struct_span_err(attr.span, "`main` function is not allowed to be `#[track_caller]`")
303 .span_label(main_span, "`main` function is not allowed to be `#[track_caller]`")
304 .emit();
305 error = true;
306 }
307
308 if error {
309 return;
310 }
311
312 let expected_return_type;
313 if let Some(term_id) = tcx.lang_items().termination() {
314 let return_ty = main_fnsig.output();
315 let return_ty_span = main_fn_return_type_span(tcx, main_def_id).unwrap_or(main_span);
316 if !return_ty.bound_vars().is_empty() {
317 let msg = "`main` function return type is not allowed to have generic \
318 parameters"
319 .to_owned();
320 struct_span_err!(tcx.sess, return_ty_span, E0131, "{}", msg).emit();
321 error = true;
322 }
323 let return_ty = return_ty.skip_binder();
324 tcx.infer_ctxt().enter(|infcx| {
325 let cause = traits::ObligationCause::new(
326 return_ty_span,
327 main_diagnostics_hir_id,
328 ObligationCauseCode::MainFunctionType,
329 );
330 let mut fulfillment_cx = traits::FulfillmentContext::new();
331 // normalize any potential projections in the return type, then add
332 // any possible obligations to the fulfillment context.
333 // HACK(ThePuzzlemaker) this feels symptomatic of a problem within
334 // checking trait fulfillment, not this here. I'm not sure why it
335 // works in the example in `fn test()` given in #88609? This also
336 // probably isn't the best way to do this.
337 let InferOk { value: norm_return_ty, obligations } = infcx
338 .partially_normalize_associated_types_in(
339 cause.clone(),
340 ty::ParamEnv::empty(),
341 return_ty,
342 );
343 fulfillment_cx.register_predicate_obligations(&infcx, obligations);
344 fulfillment_cx.register_bound(
345 &infcx,
346 ty::ParamEnv::empty(),
347 norm_return_ty,
348 term_id,
349 cause,
350 );
351 let errors = fulfillment_cx.select_all_or_error(&infcx);
352 if !errors.is_empty() {
353 infcx.report_fulfillment_errors(&errors, None, false);
354 error = true;
355 }
356 });
357 // now we can take the return type of the given main function
358 expected_return_type = main_fnsig.output();
359 } else {
360 // standard () main return type
361 expected_return_type = ty::Binder::dummy(tcx.mk_unit());
362 }
363
364 if error {
365 return;
366 }
367
368 let se_ty = tcx.mk_fn_ptr(expected_return_type.map_bound(|expected_return_type| {
369 tcx.mk_fn_sig(iter::empty(), expected_return_type, false, hir::Unsafety::Normal, Abi::Rust)
370 }));
371
372 require_same_types(
373 tcx,
374 &ObligationCause::new(
375 main_span,
376 main_diagnostics_hir_id,
377 ObligationCauseCode::MainFunctionType,
378 ),
379 se_ty,
380 tcx.mk_fn_ptr(main_fnsig),
381 );
382 }
383 fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
384 let start_def_id = start_def_id.expect_local();
385 let start_id = tcx.hir().local_def_id_to_hir_id(start_def_id);
386 let start_span = tcx.def_span(start_def_id);
387 let start_t = tcx.type_of(start_def_id);
388 match start_t.kind() {
389 ty::FnDef(..) => {
390 if let Some(Node::Item(it)) = tcx.hir().find(start_id) {
391 if let hir::ItemKind::Fn(ref sig, ref generics, _) = it.kind {
392 let mut error = false;
393 if !generics.params.is_empty() {
394 struct_span_err!(
395 tcx.sess,
396 generics.span,
397 E0132,
398 "start function is not allowed to have type parameters"
399 )
400 .span_label(generics.span, "start function cannot have type parameters")
401 .emit();
402 error = true;
403 }
404 if generics.has_where_clause_predicates {
405 struct_span_err!(
406 tcx.sess,
407 generics.where_clause_span,
408 E0647,
409 "start function is not allowed to have a `where` clause"
410 )
411 .span_label(
412 generics.where_clause_span,
413 "start function cannot have a `where` clause",
414 )
415 .emit();
416 error = true;
417 }
418 if let hir::IsAsync::Async = sig.header.asyncness {
419 let span = tcx.sess.source_map().guess_head_span(it.span);
420 struct_span_err!(
421 tcx.sess,
422 span,
423 E0752,
424 "`start` is not allowed to be `async`"
425 )
426 .span_label(span, "`start` is not allowed to be `async`")
427 .emit();
428 error = true;
429 }
430
431 let attrs = tcx.hir().attrs(start_id);
432 for attr in attrs {
433 if attr.has_name(sym::track_caller) {
434 tcx.sess
435 .struct_span_err(
436 attr.span,
437 "`start` is not allowed to be `#[track_caller]`",
438 )
439 .span_label(
440 start_span,
441 "`start` is not allowed to be `#[track_caller]`",
442 )
443 .emit();
444 error = true;
445 }
446 }
447
448 if error {
449 return;
450 }
451 }
452 }
453
454 let se_ty = tcx.mk_fn_ptr(ty::Binder::dummy(tcx.mk_fn_sig(
455 [tcx.types.isize, tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8))].iter().cloned(),
456 tcx.types.isize,
457 false,
458 hir::Unsafety::Normal,
459 Abi::Rust,
460 )));
461
462 require_same_types(
463 tcx,
464 &ObligationCause::new(start_span, start_id, ObligationCauseCode::StartFunctionType),
465 se_ty,
466 tcx.mk_fn_ptr(tcx.fn_sig(start_def_id)),
467 );
468 }
469 _ => {
470 span_bug!(start_span, "start has a non-function type: found `{}`", start_t);
471 }
472 }
473 }
474
475 fn check_for_entry_fn(tcx: TyCtxt<'_>) {
476 match tcx.entry_fn(()) {
477 Some((def_id, EntryFnType::Main)) => check_main_fn_ty(tcx, def_id),
478 Some((def_id, EntryFnType::Start)) => check_start_fn_ty(tcx, def_id),
479 _ => {}
480 }
481 }
482
483 pub fn provide(providers: &mut Providers) {
484 collect::provide(providers);
485 coherence::provide(providers);
486 check::provide(providers);
487 variance::provide(providers);
488 outlives::provide(providers);
489 impl_wf_check::provide(providers);
490 hir_wf_check::provide(providers);
491 }
492
493 pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
494 let _prof_timer = tcx.sess.timer("type_check_crate");
495
496 // this ensures that later parts of type checking can assume that items
497 // have valid types and not error
498 // FIXME(matthewjasper) We shouldn't need to use `track_errors`.
499 tcx.sess.track_errors(|| {
500 tcx.sess.time("type_collecting", || {
501 tcx.hir().for_each_module(|module| tcx.ensure().collect_mod_item_types(module))
502 });
503 })?;
504
505 if tcx.features().rustc_attrs {
506 tcx.sess.track_errors(|| {
507 tcx.sess.time("outlives_testing", || outlives::test::test_inferred_outlives(tcx));
508 })?;
509 }
510
511 tcx.sess.track_errors(|| {
512 tcx.sess.time("impl_wf_inference", || impl_wf_check::impl_wf_check(tcx));
513 })?;
514
515 tcx.sess.track_errors(|| {
516 tcx.sess.time("coherence_checking", || coherence::check_coherence(tcx));
517 })?;
518
519 if tcx.features().rustc_attrs {
520 tcx.sess.track_errors(|| {
521 tcx.sess.time("variance_testing", || variance::test::test_variance(tcx));
522 })?;
523 }
524
525 tcx.sess.track_errors(|| {
526 tcx.sess.time("wf_checking", || check::check_wf_new(tcx));
527 })?;
528
529 // NOTE: This is copy/pasted in librustdoc/core.rs and should be kept in sync.
530 tcx.sess.time("item_types_checking", || {
531 tcx.hir().for_each_module(|module| tcx.ensure().check_mod_item_types(module))
532 });
533
534 tcx.sess.time("item_bodies_checking", || tcx.typeck_item_bodies(()));
535
536 check_unused::check_crate(tcx);
537 check_for_entry_fn(tcx);
538
539 if let Some(reported) = tcx.sess.has_errors() { Err(reported) } else { Ok(()) }
540 }
541
542 /// A quasi-deprecated helper used in rustdoc and clippy to get
543 /// the type from a HIR node.
544 pub fn hir_ty_to_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'_>) -> Ty<'tcx> {
545 // In case there are any projections, etc., find the "environment"
546 // def-ID that will be used to determine the traits/predicates in
547 // scope. This is derived from the enclosing item-like thing.
548 let env_def_id = tcx.hir().get_parent_item(hir_ty.hir_id);
549 let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.to_def_id());
550 <dyn AstConv<'_>>::ast_ty_to_ty(&item_cx, hir_ty)
551 }
552
553 pub fn hir_trait_to_predicates<'tcx>(
554 tcx: TyCtxt<'tcx>,
555 hir_trait: &hir::TraitRef<'_>,
556 self_ty: Ty<'tcx>,
557 ) -> Bounds<'tcx> {
558 // In case there are any projections, etc., find the "environment"
559 // def-ID that will be used to determine the traits/predicates in
560 // scope. This is derived from the enclosing item-like thing.
561 let env_def_id = tcx.hir().get_parent_item(hir_trait.hir_ref_id);
562 let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.to_def_id());
563 let mut bounds = Bounds::default();
564 let _ = <dyn AstConv<'_>>::instantiate_poly_trait_ref(
565 &item_cx,
566 hir_trait,
567 DUMMY_SP,
568 ty::BoundConstness::NotConst,
569 self_ty,
570 &mut bounds,
571 true,
572 );
573
574 bounds
575 }