]>
Commit | Line | Data |
---|---|---|
2b03887a FG |
1 | #![feature(if_let_guard)] |
2 | #![feature(let_chains)] | |
3 | #![feature(try_blocks)] | |
4 | #![feature(never_type)] | |
5 | #![feature(min_specialization)] | |
6 | #![feature(control_flow_enum)] | |
7 | #![feature(drain_filter)] | |
8 | #![allow(rustc::potential_query_instability)] | |
9 | #![recursion_limit = "256"] | |
10 | ||
11 | #[macro_use] | |
12 | extern crate tracing; | |
13 | ||
14 | #[macro_use] | |
15 | extern crate rustc_middle; | |
16 | ||
17 | mod _match; | |
18 | mod autoderef; | |
19 | mod callee; | |
20 | // Used by clippy; | |
21 | pub mod cast; | |
22 | mod check; | |
23 | mod closure; | |
24 | mod coercion; | |
25 | mod demand; | |
26 | mod diverges; | |
27 | mod errors; | |
28 | mod expectation; | |
29 | mod expr; | |
30 | // Used by clippy; | |
31 | pub mod expr_use_visitor; | |
32 | mod fallback; | |
33 | mod fn_ctxt; | |
34 | mod gather_locals; | |
35 | mod generator_interior; | |
36 | mod inherited; | |
37 | mod intrinsicck; | |
38 | mod mem_categorization; | |
39 | mod method; | |
40 | mod op; | |
41 | mod pat; | |
42 | mod place_op; | |
43 | mod rvalue_scopes; | |
44 | mod upvar; | |
45 | mod writeback; | |
46 | ||
47 | pub use diverges::Diverges; | |
48 | pub use expectation::Expectation; | |
49 | pub use fn_ctxt::*; | |
50 | pub use inherited::{Inherited, InheritedBuilder}; | |
51 | ||
52 | use crate::check::check_fn; | |
53 | use crate::coercion::DynamicCoerceMany; | |
54 | use crate::gather_locals::GatherLocalsVisitor; | |
55 | use rustc_data_structures::unord::UnordSet; | |
487cf647 | 56 | use rustc_errors::{struct_span_err, DiagnosticId, ErrorGuaranteed, MultiSpan}; |
2b03887a | 57 | use rustc_hir as hir; |
487cf647 | 58 | use rustc_hir::def::{DefKind, Res}; |
2b03887a FG |
59 | use rustc_hir::intravisit::Visitor; |
60 | use rustc_hir::{HirIdMap, Node}; | |
61 | use rustc_hir_analysis::astconv::AstConv; | |
62 | use rustc_hir_analysis::check::check_abi; | |
63 | use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; | |
64 | use rustc_middle::traits; | |
65 | use rustc_middle::ty::query::Providers; | |
66 | use rustc_middle::ty::{self, Ty, TyCtxt}; | |
67 | use rustc_session::config; | |
68 | use rustc_session::Session; | |
69 | use rustc_span::def_id::{DefId, LocalDefId}; | |
70 | use rustc_span::Span; | |
71 | ||
72 | #[macro_export] | |
73 | macro_rules! type_error_struct { | |
74 | ($session:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({ | |
75 | let mut err = rustc_errors::struct_span_err!($session, $span, $code, $($message)*); | |
76 | ||
77 | if $typ.references_error() { | |
78 | err.downgrade_to_delayed_bug(); | |
79 | } | |
80 | ||
81 | err | |
82 | }) | |
83 | } | |
84 | ||
85 | /// The type of a local binding, including the revealed type for anon types. | |
86 | #[derive(Copy, Clone, Debug)] | |
87 | pub struct LocalTy<'tcx> { | |
88 | decl_ty: Ty<'tcx>, | |
89 | revealed_ty: Ty<'tcx>, | |
90 | } | |
91 | ||
2b03887a FG |
92 | /// If this `DefId` is a "primary tables entry", returns |
93 | /// `Some((body_id, body_ty, fn_sig))`. Otherwise, returns `None`. | |
94 | /// | |
95 | /// If this function returns `Some`, then `typeck_results(def_id)` will | |
96 | /// succeed; if it returns `None`, then `typeck_results(def_id)` may or | |
97 | /// may not succeed. In some cases where this function returns `None` | |
98 | /// (notably closures), `typeck_results(def_id)` would wind up | |
99 | /// redirecting to the owning function. | |
100 | fn primary_body_of( | |
101 | tcx: TyCtxt<'_>, | |
102 | id: hir::HirId, | |
103 | ) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> { | |
104 | match tcx.hir().get(id) { | |
105 | Node::Item(item) => match item.kind { | |
106 | hir::ItemKind::Const(ty, body) | hir::ItemKind::Static(ty, _, body) => { | |
107 | Some((body, Some(ty), None)) | |
108 | } | |
109 | hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(sig))), | |
110 | _ => None, | |
111 | }, | |
112 | Node::TraitItem(item) => match item.kind { | |
113 | hir::TraitItemKind::Const(ty, Some(body)) => Some((body, Some(ty), None)), | |
114 | hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { | |
115 | Some((body, None, Some(sig))) | |
116 | } | |
117 | _ => None, | |
118 | }, | |
119 | Node::ImplItem(item) => match item.kind { | |
120 | hir::ImplItemKind::Const(ty, body) => Some((body, Some(ty), None)), | |
121 | hir::ImplItemKind::Fn(ref sig, body) => Some((body, None, Some(sig))), | |
122 | _ => None, | |
123 | }, | |
124 | Node::AnonConst(constant) => Some((constant.body, None, None)), | |
125 | _ => None, | |
126 | } | |
127 | } | |
128 | ||
129 | fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool { | |
130 | // Closures' typeck results come from their outermost function, | |
131 | // as they are part of the same "inference environment". | |
132 | let typeck_root_def_id = tcx.typeck_root_def_id(def_id); | |
133 | if typeck_root_def_id != def_id { | |
134 | return tcx.has_typeck_results(typeck_root_def_id); | |
135 | } | |
136 | ||
137 | if let Some(def_id) = def_id.as_local() { | |
138 | let id = tcx.hir().local_def_id_to_hir_id(def_id); | |
139 | primary_body_of(tcx, id).is_some() | |
140 | } else { | |
141 | false | |
142 | } | |
143 | } | |
144 | ||
145 | fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &UnordSet<LocalDefId> { | |
146 | &*tcx.typeck(def_id).used_trait_imports | |
147 | } | |
148 | ||
149 | fn typeck_item_bodies(tcx: TyCtxt<'_>, (): ()) { | |
150 | tcx.hir().par_body_owners(|body_owner_def_id| tcx.ensure().typeck(body_owner_def_id)); | |
151 | } | |
152 | ||
153 | fn typeck_const_arg<'tcx>( | |
154 | tcx: TyCtxt<'tcx>, | |
155 | (did, param_did): (LocalDefId, DefId), | |
156 | ) -> &ty::TypeckResults<'tcx> { | |
157 | let fallback = move || tcx.type_of(param_did); | |
158 | typeck_with_fallback(tcx, did, fallback) | |
159 | } | |
160 | ||
161 | fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> { | |
162 | if let Some(param_did) = tcx.opt_const_param_of(def_id) { | |
163 | tcx.typeck_const_arg((def_id, param_did)) | |
164 | } else { | |
165 | let fallback = move || tcx.type_of(def_id.to_def_id()); | |
166 | typeck_with_fallback(tcx, def_id, fallback) | |
167 | } | |
168 | } | |
169 | ||
170 | /// Used only to get `TypeckResults` for type inference during error recovery. | |
171 | /// Currently only used for type inference of `static`s and `const`s to avoid type cycle errors. | |
172 | fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> { | |
173 | let fallback = move || { | |
174 | let span = tcx.hir().span(tcx.hir().local_def_id_to_hir_id(def_id)); | |
175 | tcx.ty_error_with_message(span, "diagnostic only typeck table used") | |
176 | }; | |
177 | typeck_with_fallback(tcx, def_id, fallback) | |
178 | } | |
179 | ||
487cf647 | 180 | #[instrument(level = "debug", skip(tcx, fallback), ret)] |
2b03887a FG |
181 | fn typeck_with_fallback<'tcx>( |
182 | tcx: TyCtxt<'tcx>, | |
183 | def_id: LocalDefId, | |
184 | fallback: impl Fn() -> Ty<'tcx> + 'tcx, | |
185 | ) -> &'tcx ty::TypeckResults<'tcx> { | |
186 | // Closures' typeck results come from their outermost function, | |
187 | // as they are part of the same "inference environment". | |
188 | let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local(); | |
189 | if typeck_root_def_id != def_id { | |
190 | return tcx.typeck(typeck_root_def_id); | |
191 | } | |
192 | ||
193 | let id = tcx.hir().local_def_id_to_hir_id(def_id); | |
194 | let span = tcx.hir().span(id); | |
195 | ||
196 | // Figure out what primary body this item has. | |
197 | let (body_id, body_ty, fn_sig) = primary_body_of(tcx, id).unwrap_or_else(|| { | |
198 | span_bug!(span, "can't type-check body of {:?}", def_id); | |
199 | }); | |
200 | let body = tcx.hir().body(body_id); | |
201 | ||
202 | let typeck_results = Inherited::build(tcx, def_id).enter(|inh| { | |
203 | let param_env = tcx.param_env(def_id); | |
487cf647 FG |
204 | let mut fcx = FnCtxt::new(&inh, param_env, body.value.hir_id); |
205 | ||
206 | if let Some(hir::FnSig { header, decl, .. }) = fn_sig { | |
2b03887a | 207 | let fn_sig = if rustc_hir_analysis::collect::get_infer_ret_ty(&decl.output).is_some() { |
2b03887a FG |
208 | <dyn AstConv<'_>>::ty_of_fn(&fcx, id, header.unsafety, header.abi, decl, None, None) |
209 | } else { | |
210 | tcx.fn_sig(def_id) | |
211 | }; | |
212 | ||
213 | check_abi(tcx, id, span, fn_sig.abi()); | |
214 | ||
215 | // Compute the function signature from point of view of inside the fn. | |
216 | let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig); | |
487cf647 FG |
217 | let fn_sig = fcx.normalize(body.value.span, fn_sig); |
218 | ||
219 | check_fn(&mut fcx, fn_sig, decl, def_id, body, None); | |
2b03887a | 220 | } else { |
2b03887a FG |
221 | let expected_type = body_ty |
222 | .and_then(|ty| match ty.kind { | |
223 | hir::TyKind::Infer => Some(<dyn AstConv<'_>>::ast_ty_to_ty(&fcx, ty)), | |
224 | _ => None, | |
225 | }) | |
226 | .unwrap_or_else(|| match tcx.hir().get(id) { | |
227 | Node::AnonConst(_) => match tcx.hir().get(tcx.hir().get_parent_node(id)) { | |
228 | Node::Expr(&hir::Expr { | |
229 | kind: hir::ExprKind::ConstBlock(ref anon_const), | |
230 | .. | |
231 | }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin { | |
232 | kind: TypeVariableOriginKind::TypeInference, | |
233 | span, | |
234 | }), | |
235 | Node::Ty(&hir::Ty { | |
236 | kind: hir::TyKind::Typeof(ref anon_const), .. | |
237 | }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin { | |
238 | kind: TypeVariableOriginKind::TypeInference, | |
239 | span, | |
240 | }), | |
241 | Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), .. }) | |
242 | | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. }) => { | |
243 | let operand_ty = asm | |
244 | .operands | |
245 | .iter() | |
246 | .filter_map(|(op, _op_sp)| match op { | |
247 | hir::InlineAsmOperand::Const { anon_const } | |
248 | if anon_const.hir_id == id => | |
249 | { | |
250 | // Inline assembly constants must be integers. | |
251 | Some(fcx.next_int_var()) | |
252 | } | |
253 | hir::InlineAsmOperand::SymFn { anon_const } | |
254 | if anon_const.hir_id == id => | |
255 | { | |
256 | Some(fcx.next_ty_var(TypeVariableOrigin { | |
257 | kind: TypeVariableOriginKind::MiscVariable, | |
258 | span, | |
259 | })) | |
260 | } | |
261 | _ => None, | |
262 | }) | |
263 | .next(); | |
264 | operand_ty.unwrap_or_else(fallback) | |
265 | } | |
266 | _ => fallback(), | |
267 | }, | |
268 | _ => fallback(), | |
269 | }); | |
270 | ||
487cf647 | 271 | let expected_type = fcx.normalize(body.value.span, expected_type); |
2b03887a FG |
272 | fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized); |
273 | ||
274 | // Gather locals in statics (because of block expressions). | |
275 | GatherLocalsVisitor::new(&fcx).visit_body(body); | |
276 | ||
277 | fcx.check_expr_coercable_to_type(&body.value, expected_type, None); | |
278 | ||
279 | fcx.write_ty(id, expected_type); | |
2b03887a FG |
280 | }; |
281 | ||
487cf647 | 282 | fcx.type_inference_fallback(); |
2b03887a FG |
283 | |
284 | // Even though coercion casts provide type hints, we check casts after fallback for | |
285 | // backwards compatibility. This makes fallback a stronger type hint than a cast coercion. | |
286 | fcx.check_casts(); | |
487cf647 | 287 | fcx.select_obligations_where_possible(|_| {}); |
2b03887a FG |
288 | |
289 | // Closure and generator analysis may run after fallback | |
290 | // because they don't constrain other type variables. | |
291 | // Closure analysis only runs on closures. Therefore they only need to fulfill non-const predicates (as of now) | |
292 | let prev_constness = fcx.param_env.constness(); | |
293 | fcx.param_env = fcx.param_env.without_const(); | |
294 | fcx.closure_analyze(body); | |
295 | fcx.param_env = fcx.param_env.with_constness(prev_constness); | |
296 | assert!(fcx.deferred_call_resolutions.borrow().is_empty()); | |
297 | // Before the generator analysis, temporary scopes shall be marked to provide more | |
298 | // precise information on types to be captured. | |
299 | fcx.resolve_rvalue_scopes(def_id.to_def_id()); | |
300 | fcx.resolve_generator_interiors(def_id.to_def_id()); | |
301 | ||
302 | for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) { | |
303 | let ty = fcx.normalize_ty(span, ty); | |
304 | fcx.require_type_is_sized(ty, span, code); | |
305 | } | |
306 | ||
307 | fcx.select_all_obligations_or_error(); | |
308 | ||
487cf647 | 309 | if let None = fcx.infcx.tainted_by_errors() { |
2b03887a FG |
310 | fcx.check_transmutes(); |
311 | } | |
312 | ||
313 | fcx.check_asms(); | |
314 | ||
315 | fcx.infcx.skip_region_resolution(); | |
316 | ||
317 | fcx.resolve_type_vars_in_body(body) | |
318 | }); | |
319 | ||
320 | // Consistency check our TypeckResults instance can hold all ItemLocalIds | |
321 | // it will need to hold. | |
322 | assert_eq!(typeck_results.hir_owner, id.owner); | |
323 | ||
324 | typeck_results | |
325 | } | |
326 | ||
327 | /// When `check_fn` is invoked on a generator (i.e., a body that | |
328 | /// includes yield), it returns back some information about the yield | |
329 | /// points. | |
330 | struct GeneratorTypes<'tcx> { | |
331 | /// Type of generator argument / values returned by `yield`. | |
332 | resume_ty: Ty<'tcx>, | |
333 | ||
334 | /// Type of value that is yielded. | |
335 | yield_ty: Ty<'tcx>, | |
336 | ||
337 | /// Types that are captured (see `GeneratorInterior` for more). | |
338 | interior: Ty<'tcx>, | |
339 | ||
340 | /// Indicates if the generator is movable or static (immovable). | |
341 | movability: hir::Movability, | |
342 | } | |
343 | ||
344 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] | |
345 | pub enum Needs { | |
346 | MutPlace, | |
347 | None, | |
348 | } | |
349 | ||
350 | impl Needs { | |
351 | fn maybe_mut_place(m: hir::Mutability) -> Self { | |
352 | match m { | |
353 | hir::Mutability::Mut => Needs::MutPlace, | |
354 | hir::Mutability::Not => Needs::None, | |
355 | } | |
356 | } | |
357 | } | |
358 | ||
359 | #[derive(Debug, Copy, Clone)] | |
360 | pub enum PlaceOp { | |
361 | Deref, | |
362 | Index, | |
363 | } | |
364 | ||
365 | pub struct BreakableCtxt<'tcx> { | |
366 | may_break: bool, | |
367 | ||
368 | // this is `null` for loops where break with a value is illegal, | |
369 | // such as `while`, `for`, and `while let` | |
370 | coerce: Option<DynamicCoerceMany<'tcx>>, | |
371 | } | |
372 | ||
373 | pub struct EnclosingBreakables<'tcx> { | |
374 | stack: Vec<BreakableCtxt<'tcx>>, | |
375 | by_id: HirIdMap<usize>, | |
376 | } | |
377 | ||
378 | impl<'tcx> EnclosingBreakables<'tcx> { | |
379 | fn find_breakable(&mut self, target_id: hir::HirId) -> &mut BreakableCtxt<'tcx> { | |
380 | self.opt_find_breakable(target_id).unwrap_or_else(|| { | |
381 | bug!("could not find enclosing breakable with id {}", target_id); | |
382 | }) | |
383 | } | |
384 | ||
385 | fn opt_find_breakable(&mut self, target_id: hir::HirId) -> Option<&mut BreakableCtxt<'tcx>> { | |
386 | match self.by_id.get(&target_id) { | |
387 | Some(ix) => Some(&mut self.stack[*ix]), | |
388 | None => None, | |
389 | } | |
390 | } | |
391 | } | |
392 | ||
487cf647 FG |
393 | fn report_unexpected_variant_res( |
394 | tcx: TyCtxt<'_>, | |
395 | res: Res, | |
396 | qpath: &hir::QPath<'_>, | |
397 | span: Span, | |
398 | err_code: &str, | |
399 | expected: &str, | |
400 | ) -> ErrorGuaranteed { | |
401 | let res_descr = match res { | |
402 | Res::Def(DefKind::Variant, _) => "struct variant", | |
403 | _ => res.descr(), | |
404 | }; | |
405 | let path_str = rustc_hir_pretty::qpath_to_string(qpath); | |
406 | let mut err = tcx.sess.struct_span_err_with_code( | |
2b03887a | 407 | span, |
487cf647 FG |
408 | format!("expected {expected}, found {res_descr} `{path_str}`"), |
409 | DiagnosticId::Error(err_code.into()), | |
410 | ); | |
411 | match res { | |
412 | Res::Def(DefKind::Fn | DefKind::AssocFn, _) if err_code == "E0164" => { | |
413 | let patterns_url = "https://doc.rust-lang.org/book/ch18-00-patterns.html"; | |
414 | err.span_label(span, "`fn` calls are not allowed in patterns"); | |
415 | err.help(format!("for more information, visit {patterns_url}")) | |
416 | } | |
417 | _ => err.span_label(span, format!("not a {expected}")), | |
418 | } | |
419 | .emit() | |
2b03887a FG |
420 | } |
421 | ||
422 | /// Controls whether the arguments are tupled. This is used for the call | |
423 | /// operator. | |
424 | /// | |
425 | /// Tupling means that all call-side arguments are packed into a tuple and | |
426 | /// passed as a single parameter. For example, if tupling is enabled, this | |
427 | /// function: | |
428 | /// ``` | |
429 | /// fn f(x: (isize, isize)) {} | |
430 | /// ``` | |
431 | /// Can be called as: | |
432 | /// ```ignore UNSOLVED (can this be done in user code?) | |
433 | /// # fn f(x: (isize, isize)) {} | |
434 | /// f(1, 2); | |
435 | /// ``` | |
436 | /// Instead of: | |
437 | /// ``` | |
438 | /// # fn f(x: (isize, isize)) {} | |
439 | /// f((1, 2)); | |
440 | /// ``` | |
487cf647 | 441 | #[derive(Copy, Clone, Eq, PartialEq)] |
2b03887a FG |
442 | enum TupleArgumentsFlag { |
443 | DontTupleArguments, | |
444 | TupleArguments, | |
445 | } | |
446 | ||
447 | fn fatally_break_rust(sess: &Session) { | |
448 | let handler = sess.diagnostic(); | |
449 | handler.span_bug_no_panic( | |
450 | MultiSpan::new(), | |
451 | "It looks like you're trying to break rust; would you like some ICE?", | |
452 | ); | |
453 | handler.note_without_error("the compiler expectedly panicked. this is a feature."); | |
454 | handler.note_without_error( | |
455 | "we would appreciate a joke overview: \ | |
456 | https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675", | |
457 | ); | |
458 | handler.note_without_error(&format!( | |
459 | "rustc {} running on {}", | |
460 | option_env!("CFG_VERSION").unwrap_or("unknown_version"), | |
461 | config::host_triple(), | |
462 | )); | |
463 | } | |
464 | ||
465 | fn has_expected_num_generic_args<'tcx>( | |
466 | tcx: TyCtxt<'tcx>, | |
467 | trait_did: Option<DefId>, | |
468 | expected: usize, | |
469 | ) -> bool { | |
470 | trait_did.map_or(true, |trait_did| { | |
471 | let generics = tcx.generics_of(trait_did); | |
472 | generics.count() == expected + if generics.has_self { 1 } else { 0 } | |
473 | }) | |
474 | } | |
475 | ||
476 | pub fn provide(providers: &mut Providers) { | |
477 | method::provide(providers); | |
478 | *providers = Providers { | |
479 | typeck_item_bodies, | |
480 | typeck_const_arg, | |
481 | typeck, | |
482 | diagnostic_only_typeck, | |
483 | has_typeck_results, | |
484 | used_trait_imports, | |
485 | ..*providers | |
486 | }; | |
487 | } |