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::{
16 HirTyLowerer, InherentAssocCandidate, RegionInferReason,
17};
18use rustc_infer::infer::{self, RegionVariableOrigin};
19use rustc_infer::traits::{DynCompatibilityViolation, Obligation};
20use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt};
21use rustc_session::Session;
22use rustc_span::{self, DUMMY_SP, ErrorGuaranteed, Ident, Span, sym};
23use rustc_trait_selection::error_reporting::TypeErrCtxt;
24use rustc_trait_selection::traits::{
25 self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt,
26};
27
28use crate::coercion::DynamicCoerceMany;
29use crate::fallback::DivergingFallbackBehavior;
30use crate::fn_ctxt::checks::DivergingBlockBehavior;
31use crate::{CoroutineTypes, Diverges, EnclosingBreakables, TypeckRootCtxt};
32
33pub(crate) struct FnCtxt<'a, 'tcx> {
45 pub(super) body_id: LocalDefId,
46
47 pub(super) param_env: ty::ParamEnv<'tcx>,
54
55 pub(super) ret_coercion: Option<RefCell<DynamicCoerceMany<'tcx>>>,
66
67 pub(super) ret_coercion_span: Cell<Option<Span>>,
69
70 pub(super) coroutine_types: Option<CoroutineTypes<'tcx>>,
71
72 pub(super) diverges: Cell<Diverges>,
106
107 pub(super) function_diverges_because_of_empty_arguments: Cell<Diverges>,
110
111 pub(super) is_whole_body: Cell<bool>,
113
114 pub(super) enclosing_breakables: RefCell<EnclosingBreakables<'tcx>>,
115
116 pub(super) root_ctxt: &'a TypeckRootCtxt<'tcx>,
117
118 pub(super) fallback_has_occurred: Cell<bool>,
119
120 pub(super) diverging_fallback_behavior: DivergingFallbackBehavior,
121 pub(super) diverging_block_behavior: DivergingBlockBehavior,
122
123 pub(super) trait_ascriptions: RefCell<ItemLocalMap<Vec<ty::Clause<'tcx>>>>,
128
129 pub(super) has_rustc_attrs: bool,
132}
133
134impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
135 pub(crate) fn new(
136 root_ctxt: &'a TypeckRootCtxt<'tcx>,
137 param_env: ty::ParamEnv<'tcx>,
138 body_id: LocalDefId,
139 ) -> FnCtxt<'a, 'tcx> {
140 let (diverging_fallback_behavior, diverging_block_behavior) =
141 never_type_behavior(root_ctxt.tcx);
142 FnCtxt {
143 body_id,
144 param_env,
145 ret_coercion: None,
146 ret_coercion_span: Cell::new(None),
147 coroutine_types: None,
148 diverges: Cell::new(Diverges::Maybe),
149 function_diverges_because_of_empty_arguments: Cell::new(Diverges::Maybe),
150 is_whole_body: Cell::new(false),
151 enclosing_breakables: RefCell::new(EnclosingBreakables {
152 stack: Vec::new(),
153 by_id: Default::default(),
154 }),
155 root_ctxt,
156 fallback_has_occurred: Cell::new(false),
157 diverging_fallback_behavior,
158 diverging_block_behavior,
159 trait_ascriptions: Default::default(),
160 has_rustc_attrs: root_ctxt.tcx.features().rustc_attrs(),
161 }
162 }
163
164 pub(crate) fn dcx(&self) -> DiagCtxtHandle<'a> {
165 self.root_ctxt.infcx.dcx()
166 }
167
168 pub(crate) fn cause(
169 &self,
170 span: Span,
171 code: ObligationCauseCode<'tcx>,
172 ) -> ObligationCause<'tcx> {
173 ObligationCause::new(span, self.body_id, code)
174 }
175
176 pub(crate) fn misc(&self, span: Span) -> ObligationCause<'tcx> {
177 self.cause(span, ObligationCauseCode::Misc)
178 }
179
180 pub(crate) fn sess(&self) -> &Session {
181 self.tcx.sess
182 }
183
184 pub(crate) fn err_ctxt(&'a self) -> TypeErrCtxt<'a, 'tcx> {
190 TypeErrCtxt {
191 infcx: &self.infcx,
192 typeck_results: Some(self.typeck_results.borrow()),
193 fallback_has_occurred: self.fallback_has_occurred.get(),
194 normalize_fn_sig: Box::new(|fn_sig| {
195 if fn_sig.has_escaping_bound_vars() {
196 return fn_sig;
197 }
198 self.probe(|_| {
199 let ocx = ObligationCtxt::new(self);
200 let normalized_fn_sig =
201 ocx.normalize(&ObligationCause::dummy(), self.param_env, fn_sig);
202 if ocx.select_all_or_error().is_empty() {
203 let normalized_fn_sig = self.resolve_vars_if_possible(normalized_fn_sig);
204 if !normalized_fn_sig.has_infer() {
205 return normalized_fn_sig;
206 }
207 }
208 fn_sig
209 })
210 }),
211 autoderef_steps: Box::new(|ty| {
212 let mut autoderef = self.autoderef(DUMMY_SP, ty).silence_errors();
213 let mut steps = vec![];
214 while let Some((ty, _)) = autoderef.next() {
215 steps.push((ty, autoderef.current_obligations()));
216 }
217 steps
218 }),
219 }
220 }
221}
222
223impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> {
224 type Target = TypeckRootCtxt<'tcx>;
225 fn deref(&self) -> &Self::Target {
226 self.root_ctxt
227 }
228}
229
230impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
231 fn tcx(&self) -> TyCtxt<'tcx> {
232 self.tcx
233 }
234
235 fn dcx(&self) -> DiagCtxtHandle<'_> {
236 self.root_ctxt.dcx()
237 }
238
239 fn item_def_id(&self) -> LocalDefId {
240 self.body_id
241 }
242
243 fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx> {
244 let v = match reason {
245 RegionInferReason::Param(def) => {
246 RegionVariableOrigin::RegionParameterDefinition(span, def.name)
247 }
248 _ => RegionVariableOrigin::Misc(span),
249 };
250 self.next_region_var(v)
251 }
252
253 fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
254 match param {
255 Some(param) => self.var_for_def(span, param).as_type().unwrap(),
256 None => self.next_ty_var(span),
257 }
258 }
259
260 fn ct_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx> {
261 match param {
263 Some(param) => self.var_for_def(span, param).as_const().unwrap(),
264 None => self.next_const_var(span),
265 }
266 }
267
268 fn register_trait_ascription_bounds(
269 &self,
270 bounds: Vec<(ty::Clause<'tcx>, Span)>,
271 hir_id: HirId,
272 _span: Span,
273 ) {
274 for (clause, span) in bounds {
275 if clause.has_escaping_bound_vars() {
276 self.dcx().span_delayed_bug(span, "clause should have no escaping bound vars");
277 continue;
278 }
279
280 self.trait_ascriptions.borrow_mut().entry(hir_id.local_id).or_default().push(clause);
281
282 let clause = self.normalize(span, clause);
283 self.register_predicate(Obligation::new(
284 self.tcx,
285 self.misc(span),
286 self.param_env,
287 clause,
288 ));
289 }
290 }
291
292 fn probe_ty_param_bounds(
293 &self,
294 _: Span,
295 def_id: LocalDefId,
296 _: Ident,
297 ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]> {
298 let tcx = self.tcx;
299 let item_def_id = tcx.hir_ty_param_owner(def_id);
300 let generics = tcx.generics_of(item_def_id);
301 let index = generics.param_def_id_to_index[&def_id.to_def_id()];
302 let span = tcx.def_span(def_id);
304
305 ty::EarlyBinder::bind(tcx.arena.alloc_from_iter(
306 self.param_env.caller_bounds().iter().filter_map(|predicate| {
307 match predicate.kind().skip_binder() {
308 ty::ClauseKind::Trait(data) if data.self_ty().is_param(index) => {
309 Some((predicate, span))
310 }
311 _ => None,
312 }
313 }),
314 ))
315 }
316
317 fn select_inherent_assoc_candidates(
318 &self,
319 span: Span,
320 self_ty: Ty<'tcx>,
321 candidates: Vec<InherentAssocCandidate>,
322 ) -> (Vec<InherentAssocCandidate>, Vec<FulfillmentError<'tcx>>) {
323 let tcx = self.tcx();
324 let infcx = &self.infcx;
325 let mut fulfillment_errors = vec![];
326
327 let mut filter_iat_candidate = |self_ty, impl_| {
328 let ocx = ObligationCtxt::new_with_diagnostics(self);
329 let self_ty = ocx.normalize(&ObligationCause::dummy(), self.param_env, self_ty);
330
331 let impl_args = infcx.fresh_args_for_item(span, impl_);
332 let impl_ty = tcx.type_of(impl_).instantiate(tcx, impl_args);
333 let impl_ty = ocx.normalize(&ObligationCause::dummy(), self.param_env, impl_ty);
334
335 if ocx.eq(&ObligationCause::dummy(), self.param_env, impl_ty, self_ty).is_err() {
337 return false;
338 }
339
340 let impl_bounds = tcx.predicates_of(impl_).instantiate(tcx, impl_args);
342 let impl_bounds = ocx.normalize(&ObligationCause::dummy(), self.param_env, impl_bounds);
343 let impl_obligations = traits::predicates_for_generics(
344 |_, _| ObligationCause::dummy(),
345 self.param_env,
346 impl_bounds,
347 );
348 ocx.register_obligations(impl_obligations);
349
350 let mut errors = ocx.select_where_possible();
351 if !errors.is_empty() {
352 fulfillment_errors.append(&mut errors);
353 return false;
354 }
355
356 true
357 };
358
359 let mut universes = if self_ty.has_escaping_bound_vars() {
360 vec![None; self_ty.outer_exclusive_binder().as_usize()]
361 } else {
362 vec![]
363 };
364
365 let candidates =
366 traits::with_replaced_escaping_bound_vars(infcx, &mut universes, self_ty, |self_ty| {
367 candidates
368 .into_iter()
369 .filter(|&InherentAssocCandidate { impl_, .. }| {
370 infcx.probe(|_| filter_iat_candidate(self_ty, impl_))
371 })
372 .collect()
373 });
374
375 (candidates, fulfillment_errors)
376 }
377
378 fn lower_assoc_item_path(
379 &self,
380 span: Span,
381 item_def_id: DefId,
382 item_segment: &rustc_hir::PathSegment<'tcx>,
383 poly_trait_ref: ty::PolyTraitRef<'tcx>,
384 ) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> {
385 let trait_ref = self.instantiate_binder_with_fresh_vars(
386 span,
387 infer::BoundRegionConversionTime::AssocTypeProjection(item_def_id),
389 poly_trait_ref,
390 );
391
392 let item_args = self.lowerer().lower_generic_args_of_assoc_item(
393 span,
394 item_def_id,
395 item_segment,
396 trait_ref.args,
397 );
398
399 Ok((item_def_id, item_args))
400 }
401
402 fn probe_adt(&self, span: Span, ty: Ty<'tcx>) -> Option<ty::AdtDef<'tcx>> {
403 match ty.kind() {
404 ty::Adt(adt_def, _) => Some(*adt_def),
405 ty::Alias(ty::Projection | ty::Inherent | ty::Free, _)
407 if !ty.has_escaping_bound_vars() =>
408 {
409 if self.next_trait_solver() {
410 self.try_structurally_resolve_type(span, ty).ty_adt_def()
411 } else {
412 self.normalize(span, ty).ty_adt_def()
413 }
414 }
415 _ => None,
416 }
417 }
418
419 fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span) {
420 let ty = if !ty.has_escaping_bound_vars() {
422 if let ty::Alias(ty::Projection | ty::Free, ty::AliasTy { args, def_id, .. }) =
427 ty.kind()
428 {
429 self.add_required_obligations_for_hir(span, *def_id, args, hir_id);
430 }
431
432 self.normalize(span, ty)
433 } else {
434 ty
435 };
436 self.write_ty(hir_id, ty)
437 }
438
439 fn infcx(&self) -> Option<&infer::InferCtxt<'tcx>> {
440 Some(&self.infcx)
441 }
442
443 fn lower_fn_sig(
444 &self,
445 decl: &rustc_hir::FnDecl<'tcx>,
446 _generics: Option<&rustc_hir::Generics<'_>>,
447 _hir_id: rustc_hir::HirId,
448 _hir_ty: Option<&hir::Ty<'_>>,
449 ) -> (Vec<Ty<'tcx>>, Ty<'tcx>) {
450 let input_tys = decl.inputs.iter().map(|a| self.lowerer().lower_ty(a)).collect();
451
452 let output_ty = match decl.output {
453 hir::FnRetTy::Return(output) => self.lowerer().lower_ty(output),
454 hir::FnRetTy::DefaultReturn(..) => self.tcx().types.unit,
455 };
456 (input_tys, output_ty)
457 }
458
459 fn dyn_compatibility_violations(&self, trait_def_id: DefId) -> Vec<DynCompatibilityViolation> {
460 self.tcx.dyn_compatibility_violations(trait_def_id).to_vec()
461 }
462}
463
464#[derive(Clone, Copy, Debug)]
470pub(crate) struct LoweredTy<'tcx> {
471 pub raw: Ty<'tcx>,
473
474 pub normalized: Ty<'tcx>,
476}
477
478impl<'tcx> LoweredTy<'tcx> {
479 fn from_raw(fcx: &FnCtxt<'_, 'tcx>, span: Span, raw: Ty<'tcx>) -> LoweredTy<'tcx> {
480 let normalized = if fcx.next_trait_solver() {
485 fcx.try_structurally_resolve_type(span, raw)
486 } else {
487 fcx.normalize(span, raw)
488 };
489 LoweredTy { raw, normalized }
490 }
491}
492
493fn never_type_behavior(tcx: TyCtxt<'_>) -> (DivergingFallbackBehavior, DivergingBlockBehavior) {
494 let (fallback, block) = parse_never_type_options_attr(tcx);
495 let fallback = fallback.unwrap_or_else(|| default_fallback(tcx));
496 let block = block.unwrap_or_default();
497
498 (fallback, block)
499}
500
501fn default_fallback(tcx: TyCtxt<'_>) -> DivergingFallbackBehavior {
503 if tcx.sess.edition().at_least_rust_2024() {
505 return DivergingFallbackBehavior::ToNever;
506 }
507
508 if tcx.features().never_type_fallback() {
510 return DivergingFallbackBehavior::ContextDependent;
511 }
512
513 DivergingFallbackBehavior::ToUnit
515}
516
517fn parse_never_type_options_attr(
518 tcx: TyCtxt<'_>,
519) -> (Option<DivergingFallbackBehavior>, Option<DivergingBlockBehavior>) {
520 let mut fallback = None;
524 let mut block = None;
525
526 let items = if tcx.features().rustc_attrs() {
527 tcx.get_attr(CRATE_DEF_ID, sym::rustc_never_type_options)
528 .map(|attr| attr.meta_item_list().unwrap())
529 } else {
530 None
531 };
532 let items = items.unwrap_or_default();
533
534 for item in items {
535 if item.has_name(sym::fallback) && fallback.is_none() {
536 let mode = item.value_str().unwrap();
537 match mode {
538 sym::unit => fallback = Some(DivergingFallbackBehavior::ToUnit),
539 sym::niko => fallback = Some(DivergingFallbackBehavior::ContextDependent),
540 sym::never => fallback = Some(DivergingFallbackBehavior::ToNever),
541 sym::no => fallback = Some(DivergingFallbackBehavior::NoFallback),
542 _ => {
543 tcx.dcx().span_err(item.span(), format!("unknown never type fallback mode: `{mode}` (supported: `unit`, `niko`, `never` and `no`)"));
544 }
545 };
546 continue;
547 }
548
549 if item.has_name(sym::diverging_block_default) && block.is_none() {
550 let default = item.value_str().unwrap();
551 match default {
552 sym::unit => block = Some(DivergingBlockBehavior::Unit),
553 sym::never => block = Some(DivergingBlockBehavior::Never),
554 _ => {
555 tcx.dcx().span_err(item.span(), format!("unknown diverging block default: `{default}` (supported: `unit` and `never`)"));
556 }
557 };
558 continue;
559 }
560
561 tcx.dcx().span_err(
562 item.span(),
563 format!(
564 "unknown or duplicate never type option: `{}` (supported: `fallback`, `diverging_block_default`)",
565 item.name().unwrap()
566 ),
567 );
568 }
569
570 (fallback, block)
571}