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