rustc_hir_typeck/fn_ctxt/
mod.rs1mod _impl;
2mod adjust_fulfillment_errors;
3mod arg_matrix;
4mod checks;
5mod inspect_obligations;
6mod suggestions;
7
8use std::cell::{Cell, RefCell};
9use std::ops::Deref;
10
11use hir::def_id::CRATE_DEF_ID;
12use rustc_errors::DiagCtxtHandle;
13use rustc_hir::def_id::{DefId, LocalDefId};
14use rustc_hir::{self as hir, HirId, ItemLocalMap};
15use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, RegionInferReason};
16use rustc_infer::infer;
17use rustc_infer::traits::{DynCompatibilityViolation, Obligation};
18use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt};
19use rustc_session::Session;
20use rustc_span::{self, DUMMY_SP, ErrorGuaranteed, Ident, Span, sym};
21use rustc_trait_selection::error_reporting::TypeErrCtxt;
22use rustc_trait_selection::error_reporting::infer::sub_relations::SubRelations;
23use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt};
24
25use crate::coercion::DynamicCoerceMany;
26use crate::fallback::DivergingFallbackBehavior;
27use crate::fn_ctxt::checks::DivergingBlockBehavior;
28use crate::{CoroutineTypes, Diverges, EnclosingBreakables, TypeckRootCtxt};
29
30pub(crate) struct FnCtxt<'a, 'tcx> {
42 pub(super) body_id: LocalDefId,
43
44 pub(super) param_env: ty::ParamEnv<'tcx>,
51
52 pub(super) ret_coercion: Option<RefCell<DynamicCoerceMany<'tcx>>>,
63
64 pub(super) ret_coercion_span: Cell<Option<Span>>,
66
67 pub(super) coroutine_types: Option<CoroutineTypes<'tcx>>,
68
69 pub(super) diverges: Cell<Diverges>,
103
104 pub(super) function_diverges_because_of_empty_arguments: Cell<Diverges>,
107
108 pub(super) is_whole_body: Cell<bool>,
110
111 pub(super) enclosing_breakables: RefCell<EnclosingBreakables<'tcx>>,
112
113 pub(super) root_ctxt: &'a TypeckRootCtxt<'tcx>,
114
115 pub(super) fallback_has_occurred: Cell<bool>,
116
117 pub(super) diverging_fallback_behavior: DivergingFallbackBehavior,
118 pub(super) diverging_block_behavior: DivergingBlockBehavior,
119
120 pub(super) trait_ascriptions: RefCell<ItemLocalMap<Vec<ty::Clause<'tcx>>>>,
125}
126
127impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
128 pub(crate) fn new(
129 root_ctxt: &'a TypeckRootCtxt<'tcx>,
130 param_env: ty::ParamEnv<'tcx>,
131 body_id: LocalDefId,
132 ) -> FnCtxt<'a, 'tcx> {
133 let (diverging_fallback_behavior, diverging_block_behavior) =
134 never_type_behavior(root_ctxt.tcx);
135 FnCtxt {
136 body_id,
137 param_env,
138 ret_coercion: None,
139 ret_coercion_span: Cell::new(None),
140 coroutine_types: None,
141 diverges: Cell::new(Diverges::Maybe),
142 function_diverges_because_of_empty_arguments: Cell::new(Diverges::Maybe),
143 is_whole_body: Cell::new(false),
144 enclosing_breakables: RefCell::new(EnclosingBreakables {
145 stack: Vec::new(),
146 by_id: Default::default(),
147 }),
148 root_ctxt,
149 fallback_has_occurred: Cell::new(false),
150 diverging_fallback_behavior,
151 diverging_block_behavior,
152 trait_ascriptions: Default::default(),
153 }
154 }
155
156 pub(crate) fn dcx(&self) -> DiagCtxtHandle<'a> {
157 self.root_ctxt.infcx.dcx()
158 }
159
160 pub(crate) fn cause(
161 &self,
162 span: Span,
163 code: ObligationCauseCode<'tcx>,
164 ) -> ObligationCause<'tcx> {
165 ObligationCause::new(span, self.body_id, code)
166 }
167
168 pub(crate) fn misc(&self, span: Span) -> ObligationCause<'tcx> {
169 self.cause(span, ObligationCauseCode::Misc)
170 }
171
172 pub(crate) fn sess(&self) -> &Session {
173 self.tcx.sess
174 }
175
176 pub(crate) fn err_ctxt(&'a self) -> TypeErrCtxt<'a, 'tcx> {
182 let mut sub_relations = SubRelations::default();
183 sub_relations.add_constraints(
184 self,
185 self.fulfillment_cx.borrow_mut().pending_obligations().iter().map(|o| o.predicate),
186 );
187 TypeErrCtxt {
188 infcx: &self.infcx,
189 sub_relations: RefCell::new(sub_relations),
190 typeck_results: Some(self.typeck_results.borrow()),
191 fallback_has_occurred: self.fallback_has_occurred.get(),
192 normalize_fn_sig: Box::new(|fn_sig| {
193 if fn_sig.has_escaping_bound_vars() {
194 return fn_sig;
195 }
196 self.probe(|_| {
197 let ocx = ObligationCtxt::new(self);
198 let normalized_fn_sig =
199 ocx.normalize(&ObligationCause::dummy(), self.param_env, fn_sig);
200 if ocx.select_all_or_error().is_empty() {
201 let normalized_fn_sig = self.resolve_vars_if_possible(normalized_fn_sig);
202 if !normalized_fn_sig.has_infer() {
203 return normalized_fn_sig;
204 }
205 }
206 fn_sig
207 })
208 }),
209 autoderef_steps: Box::new(|ty| {
210 let mut autoderef = self.autoderef(DUMMY_SP, ty).silence_errors();
211 let mut steps = vec![];
212 while let Some((ty, _)) = autoderef.next() {
213 steps.push((ty, autoderef.current_obligations()));
214 }
215 steps
216 }),
217 }
218 }
219}
220
221impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> {
222 type Target = TypeckRootCtxt<'tcx>;
223 fn deref(&self) -> &Self::Target {
224 self.root_ctxt
225 }
226}
227
228impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
229 fn tcx(&self) -> TyCtxt<'tcx> {
230 self.tcx
231 }
232
233 fn dcx(&self) -> DiagCtxtHandle<'_> {
234 self.root_ctxt.dcx()
235 }
236
237 fn item_def_id(&self) -> LocalDefId {
238 self.body_id
239 }
240
241 fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx> {
242 let v = match reason {
243 RegionInferReason::Param(def) => infer::RegionParameterDefinition(span, def.name),
244 _ => infer::MiscVariable(span),
245 };
246 self.next_region_var(v)
247 }
248
249 fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
250 match param {
251 Some(param) => self.var_for_def(span, param).as_type().unwrap(),
252 None => self.next_ty_var(span),
253 }
254 }
255
256 fn ct_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx> {
257 match param {
259 Some(param) => self.var_for_def(span, param).as_const().unwrap(),
260 None => self.next_const_var(span),
261 }
262 }
263
264 fn register_trait_ascription_bounds(
265 &self,
266 bounds: Vec<(ty::Clause<'tcx>, Span)>,
267 hir_id: HirId,
268 _span: Span,
269 ) {
270 for (clause, span) in bounds {
271 if clause.has_escaping_bound_vars() {
272 self.dcx().span_delayed_bug(span, "clause should have no escaping bound vars");
273 continue;
274 }
275
276 self.trait_ascriptions.borrow_mut().entry(hir_id.local_id).or_default().push(clause);
277
278 let clause = self.normalize(span, clause);
279 self.register_predicate(Obligation::new(
280 self.tcx,
281 self.misc(span),
282 self.param_env,
283 clause,
284 ));
285 }
286 }
287
288 fn probe_ty_param_bounds(
289 &self,
290 _: Span,
291 def_id: LocalDefId,
292 _: Ident,
293 ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]> {
294 let tcx = self.tcx;
295 let item_def_id = tcx.hir_ty_param_owner(def_id);
296 let generics = tcx.generics_of(item_def_id);
297 let index = generics.param_def_id_to_index[&def_id.to_def_id()];
298 let span = tcx.def_span(def_id);
300
301 ty::EarlyBinder::bind(tcx.arena.alloc_from_iter(
302 self.param_env.caller_bounds().iter().filter_map(|predicate| {
303 match predicate.kind().skip_binder() {
304 ty::ClauseKind::Trait(data) if data.self_ty().is_param(index) => {
305 Some((predicate, span))
306 }
307 _ => None,
308 }
309 }),
310 ))
311 }
312
313 fn lower_assoc_item_path(
314 &self,
315 span: Span,
316 item_def_id: DefId,
317 item_segment: &rustc_hir::PathSegment<'tcx>,
318 poly_trait_ref: ty::PolyTraitRef<'tcx>,
319 ) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> {
320 let trait_ref = self.instantiate_binder_with_fresh_vars(
321 span,
322 infer::BoundRegionConversionTime::AssocTypeProjection(item_def_id),
324 poly_trait_ref,
325 );
326
327 let item_args = self.lowerer().lower_generic_args_of_assoc_item(
328 span,
329 item_def_id,
330 item_segment,
331 trait_ref.args,
332 );
333
334 Ok((item_def_id, item_args))
335 }
336
337 fn probe_adt(&self, span: Span, ty: Ty<'tcx>) -> Option<ty::AdtDef<'tcx>> {
338 match ty.kind() {
339 ty::Adt(adt_def, _) => Some(*adt_def),
340 ty::Alias(ty::Projection | ty::Inherent | ty::Free, _)
342 if !ty.has_escaping_bound_vars() =>
343 {
344 if self.next_trait_solver() {
345 self.try_structurally_resolve_type(span, ty).ty_adt_def()
346 } else {
347 self.normalize(span, ty).ty_adt_def()
348 }
349 }
350 _ => None,
351 }
352 }
353
354 fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span) {
355 let ty = if !ty.has_escaping_bound_vars() {
357 if let ty::Alias(ty::Projection | ty::Free, ty::AliasTy { args, def_id, .. }) =
362 ty.kind()
363 {
364 self.add_required_obligations_for_hir(span, *def_id, args, hir_id);
365 }
366
367 self.normalize(span, ty)
368 } else {
369 ty
370 };
371 self.write_ty(hir_id, ty)
372 }
373
374 fn infcx(&self) -> Option<&infer::InferCtxt<'tcx>> {
375 Some(&self.infcx)
376 }
377
378 fn lower_fn_sig(
379 &self,
380 decl: &rustc_hir::FnDecl<'tcx>,
381 _generics: Option<&rustc_hir::Generics<'_>>,
382 _hir_id: rustc_hir::HirId,
383 _hir_ty: Option<&hir::Ty<'_>>,
384 ) -> (Vec<Ty<'tcx>>, Ty<'tcx>) {
385 let input_tys = decl.inputs.iter().map(|a| self.lowerer().lower_arg_ty(a, None)).collect();
386
387 let output_ty = match decl.output {
388 hir::FnRetTy::Return(output) => self.lowerer().lower_ty(output),
389 hir::FnRetTy::DefaultReturn(..) => self.tcx().types.unit,
390 };
391 (input_tys, output_ty)
392 }
393
394 fn dyn_compatibility_violations(&self, trait_def_id: DefId) -> Vec<DynCompatibilityViolation> {
395 self.tcx.dyn_compatibility_violations(trait_def_id).to_vec()
396 }
397}
398
399#[derive(Clone, Copy, Debug)]
405pub(crate) struct LoweredTy<'tcx> {
406 pub raw: Ty<'tcx>,
408
409 pub normalized: Ty<'tcx>,
411}
412
413impl<'tcx> LoweredTy<'tcx> {
414 fn from_raw(fcx: &FnCtxt<'_, 'tcx>, span: Span, raw: Ty<'tcx>) -> LoweredTy<'tcx> {
415 let normalized = if fcx.next_trait_solver() {
419 fcx.try_structurally_resolve_type(span, raw)
420 } else {
421 fcx.normalize(span, raw)
422 };
423 LoweredTy { raw, normalized }
424 }
425}
426
427fn never_type_behavior(tcx: TyCtxt<'_>) -> (DivergingFallbackBehavior, DivergingBlockBehavior) {
428 let (fallback, block) = parse_never_type_options_attr(tcx);
429 let fallback = fallback.unwrap_or_else(|| default_fallback(tcx));
430 let block = block.unwrap_or_default();
431
432 (fallback, block)
433}
434
435fn default_fallback(tcx: TyCtxt<'_>) -> DivergingFallbackBehavior {
437 if tcx.sess.edition().at_least_rust_2024() {
439 return DivergingFallbackBehavior::ToNever;
440 }
441
442 if tcx.features().never_type_fallback() {
444 return DivergingFallbackBehavior::ContextDependent;
445 }
446
447 DivergingFallbackBehavior::ToUnit
449}
450
451fn parse_never_type_options_attr(
452 tcx: TyCtxt<'_>,
453) -> (Option<DivergingFallbackBehavior>, Option<DivergingBlockBehavior>) {
454 let mut fallback = None;
458 let mut block = None;
459
460 let items = tcx
461 .get_attr(CRATE_DEF_ID, sym::rustc_never_type_options)
462 .map(|attr| attr.meta_item_list().unwrap())
463 .unwrap_or_default();
464
465 for item in items {
466 if item.has_name(sym::fallback) && fallback.is_none() {
467 let mode = item.value_str().unwrap();
468 match mode {
469 sym::unit => fallback = Some(DivergingFallbackBehavior::ToUnit),
470 sym::niko => fallback = Some(DivergingFallbackBehavior::ContextDependent),
471 sym::never => fallback = Some(DivergingFallbackBehavior::ToNever),
472 sym::no => fallback = Some(DivergingFallbackBehavior::NoFallback),
473 _ => {
474 tcx.dcx().span_err(item.span(), format!("unknown never type fallback mode: `{mode}` (supported: `unit`, `niko`, `never` and `no`)"));
475 }
476 };
477 continue;
478 }
479
480 if item.has_name(sym::diverging_block_default) && block.is_none() {
481 let default = item.value_str().unwrap();
482 match default {
483 sym::unit => block = Some(DivergingBlockBehavior::Unit),
484 sym::never => block = Some(DivergingBlockBehavior::Never),
485 _ => {
486 tcx.dcx().span_err(item.span(), format!("unknown diverging block default: `{default}` (supported: `unit` and `never`)"));
487 }
488 };
489 continue;
490 }
491
492 tcx.dcx().span_err(
493 item.span(),
494 format!(
495 "unknown or duplicate never type option: `{}` (supported: `fallback`, `diverging_block_default`)",
496 item.name().unwrap()
497 ),
498 );
499 }
500
501 (fallback, block)
502}