]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_hir_typeck/src/check.rs
Rollup merge of #103253 - notriddle:notriddle/test-case-masked-blanket-impl, r=Mark...
[rust.git] / compiler / rustc_hir_typeck / src / check.rs
1 use crate::coercion::CoerceMany;
2 use crate::gather_locals::GatherLocalsVisitor;
3 use crate::{FnCtxt, Inherited};
4 use crate::{GeneratorTypes, UnsafetyState};
5 use rustc_hir as hir;
6 use rustc_hir::def::DefKind;
7 use rustc_hir::intravisit::Visitor;
8 use rustc_hir::lang_items::LangItem;
9 use rustc_hir::{ImplicitSelfKind, ItemKind, Node};
10 use rustc_hir_analysis::check::fn_maybe_err;
11 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
12 use rustc_infer::infer::RegionVariableOrigin;
13 use rustc_middle::ty::{self, Ty, TyCtxt};
14 use rustc_span::def_id::LocalDefId;
15 use rustc_target::spec::abi::Abi;
16 use rustc_trait_selection::traits;
17 use std::cell::RefCell;
18
19 /// Helper used for fns and closures. Does the grungy work of checking a function
20 /// body and returns the function context used for that purpose, since in the case of a fn item
21 /// there is still a bit more to do.
22 ///
23 /// * ...
24 /// * inherited: other fields inherited from the enclosing fn (if any)
25 #[instrument(skip(inherited, body), level = "debug")]
26 pub(super) fn check_fn<'a, 'tcx>(
27     inherited: &'a Inherited<'tcx>,
28     param_env: ty::ParamEnv<'tcx>,
29     fn_sig: ty::FnSig<'tcx>,
30     decl: &'tcx hir::FnDecl<'tcx>,
31     fn_id: hir::HirId,
32     body: &'tcx hir::Body<'tcx>,
33     can_be_generator: Option<hir::Movability>,
34     return_type_pre_known: bool,
35 ) -> (FnCtxt<'a, 'tcx>, Option<GeneratorTypes<'tcx>>) {
36     // Create the function context. This is either derived from scratch or,
37     // in the case of closures, based on the outer context.
38     let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id);
39     fcx.ps.set(UnsafetyState::function(fn_sig.unsafety, fn_id));
40     fcx.return_type_pre_known = return_type_pre_known;
41
42     let tcx = fcx.tcx;
43     let hir = tcx.hir();
44
45     let declared_ret_ty = fn_sig.output();
46
47     let ret_ty =
48         fcx.register_infer_ok_obligations(fcx.infcx.replace_opaque_types_with_inference_vars(
49             declared_ret_ty,
50             body.value.hir_id,
51             decl.output.span(),
52             param_env,
53         ));
54     // If we replaced declared_ret_ty with infer vars, then we must be inferring
55     // an opaque type, so set a flag so we can improve diagnostics.
56     fcx.return_type_has_opaque = ret_ty != declared_ret_ty;
57
58     fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
59
60     let span = body.value.span;
61
62     fn_maybe_err(tcx, span, fn_sig.abi);
63
64     if fn_sig.abi == Abi::RustCall {
65         let expected_args = if let ImplicitSelfKind::None = decl.implicit_self { 1 } else { 2 };
66
67         let err = || {
68             let item = match tcx.hir().get(fn_id) {
69                 Node::Item(hir::Item { kind: ItemKind::Fn(header, ..), .. }) => Some(header),
70                 Node::ImplItem(hir::ImplItem {
71                     kind: hir::ImplItemKind::Fn(header, ..), ..
72                 }) => Some(header),
73                 Node::TraitItem(hir::TraitItem {
74                     kind: hir::TraitItemKind::Fn(header, ..),
75                     ..
76                 }) => Some(header),
77                 // Closures are RustCall, but they tuple their arguments, so shouldn't be checked
78                 Node::Expr(hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => None,
79                 node => bug!("Item being checked wasn't a function/closure: {:?}", node),
80             };
81
82             if let Some(header) = item {
83                 tcx.sess.span_err(header.span, "functions with the \"rust-call\" ABI must take a single non-self argument that is a tuple");
84             }
85         };
86
87         if fn_sig.inputs().len() != expected_args {
88             err()
89         } else {
90             // FIXME(CraftSpider) Add a check on parameter expansion, so we don't just make the ICE happen later on
91             //   This will probably require wide-scale changes to support a TupleKind obligation
92             //   We can't resolve this without knowing the type of the param
93             if !matches!(fn_sig.inputs()[expected_args - 1].kind(), ty::Tuple(_) | ty::Param(_)) {
94                 err()
95             }
96         }
97     }
98
99     if body.generator_kind.is_some() && can_be_generator.is_some() {
100         let yield_ty = fcx
101             .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span });
102         fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
103
104         // Resume type defaults to `()` if the generator has no argument.
105         let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| tcx.mk_unit());
106
107         fcx.resume_yield_tys = Some((resume_ty, yield_ty));
108     }
109
110     GatherLocalsVisitor::new(&fcx).visit_body(body);
111
112     // C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
113     // (as it's created inside the body itself, not passed in from outside).
114     let maybe_va_list = if fn_sig.c_variadic {
115         let span = body.params.last().unwrap().span;
116         let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(span));
117         let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span));
118
119         Some(tcx.bound_type_of(va_list_did).subst(tcx, &[region.into()]))
120     } else {
121         None
122     };
123
124     // Add formal parameters.
125     let inputs_hir = hir.fn_decl_by_hir_id(fn_id).map(|decl| &decl.inputs);
126     let inputs_fn = fn_sig.inputs().iter().copied();
127     for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
128         // Check the pattern.
129         let ty_span = try { inputs_hir?.get(idx)?.span };
130         fcx.check_pat_top(&param.pat, param_ty, ty_span, false);
131
132         // Check that argument is Sized.
133         // The check for a non-trivial pattern is a hack to avoid duplicate warnings
134         // for simple cases like `fn foo(x: Trait)`,
135         // where we would error once on the parameter as a whole, and once on the binding `x`.
136         if param.pat.simple_ident().is_none() && !tcx.features().unsized_fn_params {
137             fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span));
138         }
139
140         fcx.write_ty(param.hir_id, param_ty);
141     }
142
143     inherited.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig);
144
145     fcx.in_tail_expr = true;
146     if let ty::Dynamic(..) = declared_ret_ty.kind() {
147         // FIXME: We need to verify that the return type is `Sized` after the return expression has
148         // been evaluated so that we have types available for all the nodes being returned, but that
149         // requires the coerced evaluated type to be stored. Moving `check_return_expr` before this
150         // causes unsized errors caused by the `declared_ret_ty` to point at the return expression,
151         // while keeping the current ordering we will ignore the tail expression's type because we
152         // don't know it yet. We can't do `check_expr_kind` while keeping `check_return_expr`
153         // because we will trigger "unreachable expression" lints unconditionally.
154         // Because of all of this, we perform a crude check to know whether the simplest `!Sized`
155         // case that a newcomer might make, returning a bare trait, and in that case we populate
156         // the tail expression's type so that the suggestion will be correct, but ignore all other
157         // possible cases.
158         fcx.check_expr(&body.value);
159         fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
160     } else {
161         fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
162         fcx.check_return_expr(&body.value, false);
163     }
164     fcx.in_tail_expr = false;
165
166     // We insert the deferred_generator_interiors entry after visiting the body.
167     // This ensures that all nested generators appear before the entry of this generator.
168     // resolve_generator_interiors relies on this property.
169     let gen_ty = if let (Some(_), Some(gen_kind)) = (can_be_generator, body.generator_kind) {
170         let interior = fcx
171             .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span });
172         fcx.deferred_generator_interiors.borrow_mut().push((body.id(), interior, gen_kind));
173
174         let (resume_ty, yield_ty) = fcx.resume_yield_tys.unwrap();
175         Some(GeneratorTypes {
176             resume_ty,
177             yield_ty,
178             interior,
179             movability: can_be_generator.unwrap(),
180         })
181     } else {
182         None
183     };
184
185     // Finalize the return check by taking the LUB of the return types
186     // we saw and assigning it to the expected return type. This isn't
187     // really expected to fail, since the coercions would have failed
188     // earlier when trying to find a LUB.
189     let coercion = fcx.ret_coercion.take().unwrap().into_inner();
190     let mut actual_return_ty = coercion.complete(&fcx);
191     debug!("actual_return_ty = {:?}", actual_return_ty);
192     if let ty::Dynamic(..) = declared_ret_ty.kind() {
193         // We have special-cased the case where the function is declared
194         // `-> dyn Foo` and we don't actually relate it to the
195         // `fcx.ret_coercion`, so just substitute a type variable.
196         actual_return_ty =
197             fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::DynReturnFn, span });
198         debug!("actual_return_ty replaced with {:?}", actual_return_ty);
199     }
200
201     // HACK(oli-obk, compiler-errors): We should be comparing this against
202     // `declared_ret_ty`, but then anything uninferred would be inferred to
203     // the opaque type itself. That again would cause writeback to assume
204     // we have a recursive call site and do the sadly stabilized fallback to `()`.
205     fcx.demand_suptype(span, ret_ty, actual_return_ty);
206
207     // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !`
208     if let Some(panic_impl_did) = tcx.lang_items().panic_impl()
209         && panic_impl_did == hir.local_def_id(fn_id).to_def_id()
210     {
211         check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty);
212     }
213
214     // Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !`
215     if let Some(alloc_error_handler_did) = tcx.lang_items().oom()
216         && alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id()
217     {
218         check_alloc_error_fn(tcx, alloc_error_handler_did.expect_local(), fn_sig, decl, declared_ret_ty);
219     }
220
221     (fcx, gen_ty)
222 }
223
224 fn check_panic_info_fn(
225     tcx: TyCtxt<'_>,
226     fn_id: LocalDefId,
227     fn_sig: ty::FnSig<'_>,
228     decl: &hir::FnDecl<'_>,
229     declared_ret_ty: Ty<'_>,
230 ) {
231     let Some(panic_info_did) = tcx.lang_items().panic_info() else {
232         tcx.sess.err("language item required, but not found: `panic_info`");
233         return;
234     };
235
236     if *declared_ret_ty.kind() != ty::Never {
237         tcx.sess.span_err(decl.output.span(), "return type should be `!`");
238     }
239
240     let inputs = fn_sig.inputs();
241     if inputs.len() != 1 {
242         tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument");
243         return;
244     }
245
246     let arg_is_panic_info = match *inputs[0].kind() {
247         ty::Ref(region, ty, mutbl) => match *ty.kind() {
248             ty::Adt(ref adt, _) => {
249                 adt.did() == panic_info_did && mutbl == hir::Mutability::Not && !region.is_static()
250             }
251             _ => false,
252         },
253         _ => false,
254     };
255
256     if !arg_is_panic_info {
257         tcx.sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`");
258     }
259
260     let DefKind::Fn = tcx.def_kind(fn_id) else {
261         let span = tcx.def_span(fn_id);
262         tcx.sess.span_err(span, "should be a function");
263         return;
264     };
265
266     let generic_counts = tcx.generics_of(fn_id).own_counts();
267     if generic_counts.types != 0 {
268         let span = tcx.def_span(fn_id);
269         tcx.sess.span_err(span, "should have no type parameters");
270     }
271     if generic_counts.consts != 0 {
272         let span = tcx.def_span(fn_id);
273         tcx.sess.span_err(span, "should have no const parameters");
274     }
275 }
276
277 fn check_alloc_error_fn(
278     tcx: TyCtxt<'_>,
279     fn_id: LocalDefId,
280     fn_sig: ty::FnSig<'_>,
281     decl: &hir::FnDecl<'_>,
282     declared_ret_ty: Ty<'_>,
283 ) {
284     let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() else {
285         tcx.sess.err("language item required, but not found: `alloc_layout`");
286         return;
287     };
288
289     if *declared_ret_ty.kind() != ty::Never {
290         tcx.sess.span_err(decl.output.span(), "return type should be `!`");
291     }
292
293     let inputs = fn_sig.inputs();
294     if inputs.len() != 1 {
295         tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument");
296         return;
297     }
298
299     let arg_is_alloc_layout = match inputs[0].kind() {
300         ty::Adt(ref adt, _) => adt.did() == alloc_layout_did,
301         _ => false,
302     };
303
304     if !arg_is_alloc_layout {
305         tcx.sess.span_err(decl.inputs[0].span, "argument should be `Layout`");
306     }
307
308     let DefKind::Fn = tcx.def_kind(fn_id) else {
309         let span = tcx.def_span(fn_id);
310         tcx.sess.span_err(span, "`#[alloc_error_handler]` should be a function");
311         return;
312     };
313
314     let generic_counts = tcx.generics_of(fn_id).own_counts();
315     if generic_counts.types != 0 {
316         let span = tcx.def_span(fn_id);
317         tcx.sess.span_err(span, "`#[alloc_error_handler]` function should have no type parameters");
318     }
319     if generic_counts.consts != 0 {
320         let span = tcx.def_span(fn_id);
321         tcx.sess
322             .span_err(span, "`#[alloc_error_handler]` function should have no const parameters");
323     }
324 }