]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_hir_typeck/src/check.rs
New upstream version 1.68.2+dfsg1
[rustc.git] / compiler / rustc_hir_typeck / src / check.rs
CommitLineData
2b03887a 1use crate::coercion::CoerceMany;
9c376795
FG
2use crate::errors::{
3 LangStartIncorrectNumberArgs, LangStartIncorrectParam, LangStartIncorrectRetTy,
4};
2b03887a 5use crate::gather_locals::GatherLocalsVisitor;
487cf647
FG
6use crate::FnCtxt;
7use crate::GeneratorTypes;
2b03887a
FG
8use rustc_hir as hir;
9use rustc_hir::def::DefKind;
10use rustc_hir::intravisit::Visitor;
11use rustc_hir::lang_items::LangItem;
2b03887a
FG
12use rustc_hir_analysis::check::fn_maybe_err;
13use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
14use rustc_infer::infer::RegionVariableOrigin;
9c376795 15use rustc_middle::ty::{self, Binder, Ty, TyCtxt};
2b03887a 16use rustc_span::def_id::LocalDefId;
9c376795 17use rustc_target::spec::abi::Abi;
2b03887a
FG
18use rustc_trait_selection::traits;
19use std::cell::RefCell;
20
21/// Helper used for fns and closures. Does the grungy work of checking a function
22/// body and returns the function context used for that purpose, since in the case of a fn item
23/// there is still a bit more to do.
24///
25/// * ...
26/// * inherited: other fields inherited from the enclosing fn (if any)
487cf647 27#[instrument(skip(fcx, body), level = "debug")]
2b03887a 28pub(super) fn check_fn<'a, 'tcx>(
487cf647 29 fcx: &mut FnCtxt<'a, 'tcx>,
2b03887a
FG
30 fn_sig: ty::FnSig<'tcx>,
31 decl: &'tcx hir::FnDecl<'tcx>,
487cf647 32 fn_def_id: LocalDefId,
2b03887a
FG
33 body: &'tcx hir::Body<'tcx>,
34 can_be_generator: Option<hir::Movability>,
487cf647
FG
35) -> Option<GeneratorTypes<'tcx>> {
36 let fn_id = fcx.tcx.hir().local_def_id_to_hir_id(fn_def_id);
2b03887a
FG
37
38 let tcx = fcx.tcx;
39 let hir = tcx.hir();
40
41 let declared_ret_ty = fn_sig.output();
42
43 let ret_ty =
44 fcx.register_infer_ok_obligations(fcx.infcx.replace_opaque_types_with_inference_vars(
45 declared_ret_ty,
46 body.value.hir_id,
47 decl.output.span(),
487cf647 48 fcx.param_env,
2b03887a 49 ));
2b03887a
FG
50
51 fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
52
53 let span = body.value.span;
54
55 fn_maybe_err(tcx, span, fn_sig.abi);
56
487cf647
FG
57 if let Some(kind) = body.generator_kind && can_be_generator.is_some() {
58 let yield_ty = if kind == hir::GeneratorKind::Gen {
59 let yield_ty = fcx
60 .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span });
61 fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
62 yield_ty
2b03887a 63 } else {
487cf647
FG
64 tcx.mk_unit()
65 };
2b03887a
FG
66
67 // Resume type defaults to `()` if the generator has no argument.
68 let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| tcx.mk_unit());
69
70 fcx.resume_yield_tys = Some((resume_ty, yield_ty));
71 }
72
73 GatherLocalsVisitor::new(&fcx).visit_body(body);
74
75 // C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
76 // (as it's created inside the body itself, not passed in from outside).
77 let maybe_va_list = if fn_sig.c_variadic {
78 let span = body.params.last().unwrap().span;
79 let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(span));
80 let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span));
81
82 Some(tcx.bound_type_of(va_list_did).subst(tcx, &[region.into()]))
83 } else {
84 None
85 };
86
87 // Add formal parameters.
88 let inputs_hir = hir.fn_decl_by_hir_id(fn_id).map(|decl| &decl.inputs);
89 let inputs_fn = fn_sig.inputs().iter().copied();
90 for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
91 // Check the pattern.
92 let ty_span = try { inputs_hir?.get(idx)?.span };
93 fcx.check_pat_top(&param.pat, param_ty, ty_span, false);
94
95 // Check that argument is Sized.
96 // The check for a non-trivial pattern is a hack to avoid duplicate warnings
97 // for simple cases like `fn foo(x: Trait)`,
98 // where we would error once on the parameter as a whole, and once on the binding `x`.
99 if param.pat.simple_ident().is_none() && !tcx.features().unsized_fn_params {
100 fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span));
101 }
102
103 fcx.write_ty(param.hir_id, param_ty);
104 }
105
487cf647 106 fcx.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig);
2b03887a 107
487cf647 108 if let ty::Dynamic(_, _, ty::Dyn) = declared_ret_ty.kind() {
2b03887a
FG
109 // FIXME: We need to verify that the return type is `Sized` after the return expression has
110 // been evaluated so that we have types available for all the nodes being returned, but that
111 // requires the coerced evaluated type to be stored. Moving `check_return_expr` before this
112 // causes unsized errors caused by the `declared_ret_ty` to point at the return expression,
113 // while keeping the current ordering we will ignore the tail expression's type because we
114 // don't know it yet. We can't do `check_expr_kind` while keeping `check_return_expr`
115 // because we will trigger "unreachable expression" lints unconditionally.
116 // Because of all of this, we perform a crude check to know whether the simplest `!Sized`
117 // case that a newcomer might make, returning a bare trait, and in that case we populate
118 // the tail expression's type so that the suggestion will be correct, but ignore all other
119 // possible cases.
120 fcx.check_expr(&body.value);
121 fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
122 } else {
123 fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
124 fcx.check_return_expr(&body.value, false);
125 }
2b03887a
FG
126
127 // We insert the deferred_generator_interiors entry after visiting the body.
128 // This ensures that all nested generators appear before the entry of this generator.
129 // resolve_generator_interiors relies on this property.
130 let gen_ty = if let (Some(_), Some(gen_kind)) = (can_be_generator, body.generator_kind) {
131 let interior = fcx
132 .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span });
133 fcx.deferred_generator_interiors.borrow_mut().push((body.id(), interior, gen_kind));
134
135 let (resume_ty, yield_ty) = fcx.resume_yield_tys.unwrap();
136 Some(GeneratorTypes {
137 resume_ty,
138 yield_ty,
139 interior,
140 movability: can_be_generator.unwrap(),
141 })
142 } else {
143 None
144 };
145
146 // Finalize the return check by taking the LUB of the return types
147 // we saw and assigning it to the expected return type. This isn't
148 // really expected to fail, since the coercions would have failed
149 // earlier when trying to find a LUB.
150 let coercion = fcx.ret_coercion.take().unwrap().into_inner();
151 let mut actual_return_ty = coercion.complete(&fcx);
152 debug!("actual_return_ty = {:?}", actual_return_ty);
153 if let ty::Dynamic(..) = declared_ret_ty.kind() {
154 // We have special-cased the case where the function is declared
155 // `-> dyn Foo` and we don't actually relate it to the
156 // `fcx.ret_coercion`, so just substitute a type variable.
157 actual_return_ty =
158 fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::DynReturnFn, span });
159 debug!("actual_return_ty replaced with {:?}", actual_return_ty);
160 }
161
162 // HACK(oli-obk, compiler-errors): We should be comparing this against
163 // `declared_ret_ty`, but then anything uninferred would be inferred to
164 // the opaque type itself. That again would cause writeback to assume
165 // we have a recursive call site and do the sadly stabilized fallback to `()`.
166 fcx.demand_suptype(span, ret_ty, actual_return_ty);
167
168 // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !`
169 if let Some(panic_impl_did) = tcx.lang_items().panic_impl()
170 && panic_impl_did == hir.local_def_id(fn_id).to_def_id()
171 {
172 check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty);
173 }
174
9c376795
FG
175 if let Some(lang_start_defid) = tcx.lang_items().start_fn() && lang_start_defid == hir.local_def_id(fn_id).to_def_id() {
176 check_lang_start_fn(tcx, fn_sig, decl, fn_def_id);
177 }
178
487cf647 179 gen_ty
2b03887a
FG
180}
181
182fn check_panic_info_fn(
183 tcx: TyCtxt<'_>,
184 fn_id: LocalDefId,
185 fn_sig: ty::FnSig<'_>,
186 decl: &hir::FnDecl<'_>,
187 declared_ret_ty: Ty<'_>,
188) {
189 let Some(panic_info_did) = tcx.lang_items().panic_info() else {
190 tcx.sess.err("language item required, but not found: `panic_info`");
191 return;
192 };
193
194 if *declared_ret_ty.kind() != ty::Never {
195 tcx.sess.span_err(decl.output.span(), "return type should be `!`");
196 }
197
198 let inputs = fn_sig.inputs();
199 if inputs.len() != 1 {
200 tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument");
201 return;
202 }
203
204 let arg_is_panic_info = match *inputs[0].kind() {
205 ty::Ref(region, ty, mutbl) => match *ty.kind() {
206 ty::Adt(ref adt, _) => {
487cf647 207 adt.did() == panic_info_did && mutbl.is_not() && !region.is_static()
2b03887a
FG
208 }
209 _ => false,
210 },
211 _ => false,
212 };
213
214 if !arg_is_panic_info {
215 tcx.sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`");
216 }
217
218 let DefKind::Fn = tcx.def_kind(fn_id) else {
219 let span = tcx.def_span(fn_id);
220 tcx.sess.span_err(span, "should be a function");
221 return;
222 };
223
224 let generic_counts = tcx.generics_of(fn_id).own_counts();
225 if generic_counts.types != 0 {
226 let span = tcx.def_span(fn_id);
227 tcx.sess.span_err(span, "should have no type parameters");
228 }
229 if generic_counts.consts != 0 {
230 let span = tcx.def_span(fn_id);
231 tcx.sess.span_err(span, "should have no const parameters");
232 }
233}
9c376795
FG
234
235fn check_lang_start_fn<'tcx>(
236 tcx: TyCtxt<'tcx>,
237 fn_sig: ty::FnSig<'tcx>,
238 decl: &'tcx hir::FnDecl<'tcx>,
239 def_id: LocalDefId,
240) {
241 let inputs = fn_sig.inputs();
242
243 let arg_count = inputs.len();
244 if arg_count != 4 {
245 tcx.sess.emit_err(LangStartIncorrectNumberArgs {
246 params_span: tcx.def_span(def_id),
247 found_param_count: arg_count,
248 });
249 }
250
251 // only check args if they should exist by checking the count
252 // note: this does not handle args being shifted or their order swapped very nicely
253 // but it's a lang item, users shouldn't frequently encounter this
254
255 // first arg is `main: fn() -> T`
256 if let Some(&main_arg) = inputs.get(0) {
257 // make a Ty for the generic on the fn for diagnostics
258 // FIXME: make the lang item generic checks check for the right generic *kind*
259 // for example `start`'s generic should be a type parameter
260 let generics = tcx.generics_of(def_id);
261 let fn_generic = generics.param_at(0, tcx);
262 let generic_tykind =
263 ty::Param(ty::ParamTy { index: fn_generic.index, name: fn_generic.name });
264 let generic_ty = tcx.mk_ty(generic_tykind);
265 let expected_fn_sig =
266 tcx.mk_fn_sig([].iter(), &generic_ty, false, hir::Unsafety::Normal, Abi::Rust);
267 let expected_ty = tcx.mk_fn_ptr(Binder::dummy(expected_fn_sig));
268
269 // we emit the same error to suggest changing the arg no matter what's wrong with the arg
270 let emit_main_fn_arg_err = || {
271 tcx.sess.emit_err(LangStartIncorrectParam {
272 param_span: decl.inputs[0].span,
273 param_num: 1,
274 expected_ty: expected_ty,
275 found_ty: main_arg,
276 });
277 };
278
279 if let ty::FnPtr(main_fn_sig) = main_arg.kind() {
280 let main_fn_inputs = main_fn_sig.inputs();
281 if main_fn_inputs.iter().count() != 0 {
282 emit_main_fn_arg_err();
283 }
284
285 let output = main_fn_sig.output();
286 output.map_bound(|ret_ty| {
287 // if the output ty is a generic, it's probably the right one
288 if !matches!(ret_ty.kind(), ty::Param(_)) {
289 emit_main_fn_arg_err();
290 }
291 });
292 } else {
293 emit_main_fn_arg_err();
294 }
295 }
296
297 // second arg is isize
298 if let Some(&argc_arg) = inputs.get(1) {
299 if argc_arg != tcx.types.isize {
300 tcx.sess.emit_err(LangStartIncorrectParam {
301 param_span: decl.inputs[1].span,
302 param_num: 2,
303 expected_ty: tcx.types.isize,
304 found_ty: argc_arg,
305 });
306 }
307 }
308
309 // third arg is `*const *const u8`
310 if let Some(&argv_arg) = inputs.get(2) {
311 let mut argv_is_okay = false;
312 if let ty::RawPtr(outer_ptr) = argv_arg.kind() {
313 if outer_ptr.mutbl.is_not() {
314 if let ty::RawPtr(inner_ptr) = outer_ptr.ty.kind() {
315 if inner_ptr.mutbl.is_not() && inner_ptr.ty == tcx.types.u8 {
316 argv_is_okay = true;
317 }
318 }
319 }
320 }
321
322 if !argv_is_okay {
323 let inner_ptr_ty =
324 tcx.mk_ptr(ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: tcx.types.u8 });
325 let expected_ty =
326 tcx.mk_ptr(ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: inner_ptr_ty });
327 tcx.sess.emit_err(LangStartIncorrectParam {
328 param_span: decl.inputs[2].span,
329 param_num: 3,
330 expected_ty,
331 found_ty: argv_arg,
332 });
333 }
334 }
335
336 // fourth arg is `sigpipe: u8`
337 if let Some(&sigpipe_arg) = inputs.get(3) {
338 if sigpipe_arg != tcx.types.u8 {
339 tcx.sess.emit_err(LangStartIncorrectParam {
340 param_span: decl.inputs[3].span,
341 param_num: 4,
342 expected_ty: tcx.types.u8,
343 found_ty: sigpipe_arg,
344 });
345 }
346 }
347
348 // output type is isize
349 if fn_sig.output() != tcx.types.isize {
350 tcx.sess.emit_err(LangStartIncorrectRetTy {
351 ret_span: decl.output.span(),
352 expected_ty: tcx.types.isize,
353 found_ty: fn_sig.output(),
354 });
355 }
356}