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