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 rustc_errors::DiagCtxtHandle;
12use rustc_hir::attrs::{DivergingBlockBehavior, DivergingFallbackBehavior};
13use rustc_hir::def_id::{DefId, LocalDefId};
14use rustc_hir::{self as hir, HirId, ItemLocalMap, find_attr};
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::{
21 self, CantBeErased, Const, Flags, Ty, TyCtxt, TypeVisitableExt, TypingMode, Unnormalized,
22};
23use rustc_session::Session;
24use rustc_span::{self, DUMMY_SP, ErrorGuaranteed, Ident, Span};
25use rustc_trait_selection::error_reporting::TypeErrCtxt;
26use rustc_trait_selection::traits::{
27 self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt,
28};
29
30use crate::coercion::CoerceMany;
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<CoerceMany<'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) diverging_fallback_has_occurred: Cell<bool>,
121
122 pub(super) diverging_fallback_behavior: DivergingFallbackBehavior,
123 pub(super) diverging_block_behavior: DivergingBlockBehavior,
124
125 pub(super) trait_ascriptions: RefCell<ItemLocalMap<Vec<ty::Clause<'tcx>>>>,
130
131 pub(super) has_rustc_attrs: bool,
134}
135
136impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
137 pub(crate) fn new(
138 root_ctxt: &'a TypeckRootCtxt<'tcx>,
139 param_env: ty::ParamEnv<'tcx>,
140 body_id: LocalDefId,
141 ) -> FnCtxt<'a, 'tcx> {
142 let (diverging_fallback_behavior, diverging_block_behavior) =
143 never_type_behavior(root_ctxt.tcx);
144 FnCtxt {
145 body_id,
146 param_env,
147 ret_coercion: None,
148 ret_coercion_span: Cell::new(None),
149 coroutine_types: None,
150 diverges: Cell::new(Diverges::Maybe),
151 function_diverges_because_of_empty_arguments: Cell::new(Diverges::Maybe),
152 is_whole_body: Cell::new(false),
153 enclosing_breakables: RefCell::new(EnclosingBreakables {
154 stack: Vec::new(),
155 by_id: Default::default(),
156 }),
157 root_ctxt,
158 diverging_fallback_has_occurred: Cell::new(false),
159 diverging_fallback_behavior,
160 diverging_block_behavior,
161 trait_ascriptions: Default::default(),
162 has_rustc_attrs: root_ctxt.tcx.features().rustc_attrs(),
163 }
164 }
165
166 pub(crate) fn typing_mode(&self) -> TypingMode<'tcx, CantBeErased> {
167 self.infcx.typing_mode_raw().assert_not_erased()
170 }
171
172 pub(crate) fn dcx(&self) -> DiagCtxtHandle<'a> {
173 self.root_ctxt.infcx.dcx()
174 }
175
176 pub(crate) fn cause(
177 &self,
178 span: Span,
179 code: ObligationCauseCode<'tcx>,
180 ) -> ObligationCause<'tcx> {
181 ObligationCause::new(span, self.body_id, code)
182 }
183
184 pub(crate) fn misc(&self, span: Span) -> ObligationCause<'tcx> {
185 self.cause(span, ObligationCauseCode::Misc)
186 }
187
188 pub(crate) fn sess(&self) -> &Session {
189 self.tcx.sess
190 }
191
192 pub(crate) fn err_ctxt(&'a self) -> TypeErrCtxt<'a, 'tcx> {
198 TypeErrCtxt {
199 infcx: &self.infcx,
200 typeck_results: Some(self.typeck_results.borrow()),
201 diverging_fallback_has_occurred: self.diverging_fallback_has_occurred.get(),
202 normalize_fn_sig: Box::new(|fn_sig| {
203 if fn_sig.skip_normalization().has_escaping_bound_vars() {
204 return fn_sig.skip_normalization();
205 }
206 self.probe(|_| {
207 let ocx = ObligationCtxt::new(self);
208 let normalized_fn_sig =
209 ocx.normalize(&ObligationCause::dummy(), self.param_env, fn_sig);
210 if ocx.evaluate_obligations_error_on_ambiguity().is_empty() {
211 let normalized_fn_sig = self.resolve_vars_if_possible(normalized_fn_sig);
212 if !normalized_fn_sig.has_infer() {
213 return normalized_fn_sig;
214 }
215 }
216 fn_sig.skip_normalization()
217 })
218 }),
219 autoderef_steps: Box::new(|ty| {
220 let mut autoderef = self.autoderef(DUMMY_SP, ty).silence_errors();
221 let mut steps = ::alloc::vec::Vec::new()vec![];
222 while let Some((ty, _)) = autoderef.next() {
223 steps.push((ty, autoderef.current_obligations()));
224 }
225 steps
226 }),
227 }
228 }
229}
230
231impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> {
232 type Target = TypeckRootCtxt<'tcx>;
233 fn deref(&self) -> &Self::Target {
234 self.root_ctxt
235 }
236}
237
238impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
239 fn tcx(&self) -> TyCtxt<'tcx> {
240 self.tcx
241 }
242
243 fn dcx(&self) -> DiagCtxtHandle<'_> {
244 self.root_ctxt.dcx()
245 }
246
247 fn item_def_id(&self) -> LocalDefId {
248 self.body_id
249 }
250
251 fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx> {
252 let v = match reason {
253 RegionInferReason::Param(def) => {
254 RegionVariableOrigin::RegionParameterDefinition(span, def.name)
255 }
256 _ => RegionVariableOrigin::Misc(span),
257 };
258 self.next_region_var(v)
259 }
260
261 fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
262 match param {
263 Some(param) => self.var_for_def(span, param).as_type().unwrap(),
264 None => self.next_ty_var(span),
265 }
266 }
267
268 fn ct_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx> {
269 match param {
271 Some(param) => self.var_for_def(span, param).as_const().unwrap(),
272 None => self.next_const_var(span),
273 }
274 }
275
276 fn register_trait_ascription_bounds(
277 &self,
278 bounds: Vec<(ty::Clause<'tcx>, Span)>,
279 hir_id: HirId,
280 _span: Span,
281 ) {
282 for (clause, span) in bounds {
283 if clause.has_escaping_bound_vars() {
284 self.dcx().span_delayed_bug(span, "clause should have no escaping bound vars");
285 continue;
286 }
287
288 self.trait_ascriptions.borrow_mut().entry(hir_id.local_id).or_default().push(clause);
289
290 let clause = self.normalize(span, Unnormalized::new_wip(clause));
291 self.register_predicate(Obligation::new(
292 self.tcx,
293 self.misc(span),
294 self.param_env,
295 clause,
296 ));
297 }
298 }
299
300 fn probe_ty_param_bounds(
301 &self,
302 _: Span,
303 def_id: LocalDefId,
304 _: Ident,
305 ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]> {
306 let tcx = self.tcx;
307 let item_def_id = tcx.hir_ty_param_owner(def_id);
308 let generics = tcx.generics_of(item_def_id);
309 let index = generics.param_def_id_to_index[&def_id.to_def_id()];
310 let span = tcx.def_span(def_id);
312
313 ty::EarlyBinder::bind(tcx.arena.alloc_from_iter(
314 self.param_env.caller_bounds().iter().filter_map(|predicate| {
315 match predicate.kind().skip_binder() {
316 ty::ClauseKind::Trait(data) if data.self_ty().is_param(index) => {
317 Some((predicate, span))
318 }
319 _ => None,
320 }
321 }),
322 ))
323 }
324
325 fn select_inherent_assoc_candidates(
326 &self,
327 span: Span,
328 self_ty: Ty<'tcx>,
329 candidates: Vec<InherentAssocCandidate>,
330 ) -> (Vec<InherentAssocCandidate>, Vec<FulfillmentError<'tcx>>) {
331 let tcx = self.tcx();
332 let infcx = &self.infcx;
333 let mut fulfillment_errors = ::alloc::vec::Vec::new()vec![];
334
335 let mut filter_iat_candidate = |self_ty, impl_| {
336 let ocx = ObligationCtxt::new_with_diagnostics(self);
337 let self_ty = ocx.normalize(
338 &ObligationCause::dummy(),
339 self.param_env,
340 Unnormalized::new_wip(self_ty),
341 );
342
343 let impl_args = infcx.fresh_args_for_item(span, impl_);
344 let impl_ty = tcx.type_of(impl_).instantiate(tcx, impl_args);
345 let impl_ty = ocx.normalize(&ObligationCause::dummy(), self.param_env, impl_ty);
346
347 if ocx.eq(&ObligationCause::dummy(), self.param_env, impl_ty, self_ty).is_err() {
349 return false;
350 }
351
352 let impl_bounds = tcx.predicates_of(impl_).instantiate(tcx, impl_args);
354 let impl_obligations = traits::predicates_for_generics(
355 |_, _| ObligationCause::dummy(),
356 |pred| ocx.normalize(&ObligationCause::dummy(), self.param_env, pred),
357 self.param_env,
358 impl_bounds,
359 );
360 ocx.register_obligations(impl_obligations);
361
362 let mut errors = ocx.try_evaluate_obligations();
363 if !errors.is_empty() {
364 fulfillment_errors.append(&mut errors);
365 return false;
366 }
367
368 true
369 };
370
371 let mut universes = if self_ty.has_escaping_bound_vars() {
372 ::alloc::vec::from_elem(None, self_ty.outer_exclusive_binder().as_usize())vec![None; self_ty.outer_exclusive_binder().as_usize()]
373 } else {
374 ::alloc::vec::Vec::new()vec![]
375 };
376
377 let candidates =
378 traits::with_replaced_escaping_bound_vars(infcx, &mut universes, self_ty, |self_ty| {
379 candidates
380 .into_iter()
381 .filter(|&InherentAssocCandidate { impl_, .. }| {
382 infcx.probe(|_| filter_iat_candidate(self_ty, impl_))
383 })
384 .collect()
385 });
386
387 (candidates, fulfillment_errors)
388 }
389
390 fn lower_assoc_item_path(
391 &self,
392 span: Span,
393 item_def_id: DefId,
394 item_segment: &rustc_hir::PathSegment<'tcx>,
395 poly_trait_ref: ty::PolyTraitRef<'tcx>,
396 ) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> {
397 let trait_ref = self.instantiate_binder_with_fresh_vars(
398 span,
399 infer::BoundRegionConversionTime::AssocTypeProjection(item_def_id),
401 poly_trait_ref,
402 );
403
404 let item_args = self.lowerer().lower_generic_args_of_assoc_item(
405 span,
406 item_def_id,
407 item_segment,
408 trait_ref.args,
409 );
410
411 Ok((item_def_id, item_args))
412 }
413
414 fn probe_adt(&self, span: Span, ty: Ty<'tcx>) -> Option<ty::AdtDef<'tcx>> {
415 match ty.kind() {
416 ty::Adt(adt_def, _) => Some(*adt_def),
417 ty::Alias(ty::AliasTy {
419 kind: ty::Projection { .. } | ty::Inherent { .. } | ty::Free { .. },
420 ..
421 }) if !ty.has_escaping_bound_vars() => {
422 self.normalize(span, Unnormalized::new_wip(ty)).ty_adt_def()
423 }
424 _ => None,
425 }
426 }
427
428 fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span) {
429 let ty = if !ty.has_escaping_bound_vars() {
431 if let ty::Alias(ty::AliasTy {
436 kind: ty::Projection { def_id } | ty::Free { def_id },
437 args,
438 ..
439 }) = ty.kind()
440 {
441 self.add_required_obligations_for_hir(span, *def_id, args, hir_id);
442 }
443
444 self.normalize(span, Unnormalized::new_wip(ty))
445 } else {
446 ty
447 };
448 self.write_ty(hir_id, ty)
449 }
450
451 fn infcx(&self) -> Option<&infer::InferCtxt<'tcx>> {
452 Some(&self.infcx)
453 }
454
455 fn lower_fn_sig(
456 &self,
457 decl: &rustc_hir::FnDecl<'tcx>,
458 _generics: Option<&rustc_hir::Generics<'_>>,
459 _hir_id: rustc_hir::HirId,
460 _hir_ty: Option<&hir::Ty<'_>>,
461 ) -> (Vec<Ty<'tcx>>, Ty<'tcx>) {
462 let input_tys = decl.inputs.iter().map(|a| self.lowerer().lower_ty(a)).collect();
463
464 let output_ty = match decl.output {
465 hir::FnRetTy::Return(output) => self.lowerer().lower_ty(output),
466 hir::FnRetTy::DefaultReturn(..) => self.tcx().types.unit,
467 };
468 (input_tys, output_ty)
469 }
470
471 fn dyn_compatibility_violations(&self, trait_def_id: DefId) -> Vec<DynCompatibilityViolation> {
472 self.tcx.dyn_compatibility_violations(trait_def_id).to_vec()
473 }
474}
475
476#[derive(#[automatically_derived]
impl<'tcx> ::core::clone::Clone for LoweredTy<'tcx> {
#[inline]
fn clone(&self) -> LoweredTy<'tcx> {
let _: ::core::clone::AssertParamIsClone<Ty<'tcx>>;
let _: ::core::clone::AssertParamIsClone<Ty<'tcx>>;
*self
}
}Clone, #[automatically_derived]
impl<'tcx> ::core::marker::Copy for LoweredTy<'tcx> { }Copy, #[automatically_derived]
impl<'tcx> ::core::fmt::Debug for LoweredTy<'tcx> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "LoweredTy",
"raw", &self.raw, "normalized", &&self.normalized)
}
}Debug)]
482pub(crate) struct LoweredTy<'tcx> {
483 pub raw: Ty<'tcx>,
485
486 pub normalized: Ty<'tcx>,
488}
489
490impl<'tcx> LoweredTy<'tcx> {
491 fn from_raw(fcx: &FnCtxt<'_, 'tcx>, span: Span, raw: Ty<'tcx>) -> LoweredTy<'tcx> {
492 let normalized = fcx.normalize(span, Unnormalized::new_wip(raw));
493 LoweredTy { raw, normalized }
494 }
495}
496
497fn never_type_behavior(tcx: TyCtxt<'_>) -> (DivergingFallbackBehavior, DivergingBlockBehavior) {
498 let (fallback, block) = parse_never_type_options_attr(tcx);
499 let fallback = fallback.unwrap_or_else(|| default_fallback(tcx));
500 let block = block.unwrap_or_default();
501
502 (fallback, block)
503}
504
505fn default_fallback(tcx: TyCtxt<'_>) -> DivergingFallbackBehavior {
507 if tcx.sess.edition().at_least_rust_2024() {
509 return DivergingFallbackBehavior::ToNever;
510 }
511
512 DivergingFallbackBehavior::ToUnit
514}
515
516fn parse_never_type_options_attr(
517 tcx: TyCtxt<'_>,
518) -> (Option<DivergingFallbackBehavior>, Option<DivergingBlockBehavior>) {
519 {
'done:
{
for i in tcx.hir_krate_attrs() {
#[allow(unused_imports)]
use rustc_hir::attrs::AttributeKind::*;
let i: &rustc_hir::Attribute = i;
match i {
rustc_hir::Attribute::Parsed(RustcNeverTypeOptions {
fallback, diverging_block_default }) => {
break 'done Some((*fallback, *diverging_block_default));
}
rustc_hir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}find_attr!(tcx, crate, RustcNeverTypeOptions {fallback, diverging_block_default} => (*fallback, *diverging_block_default)).unwrap_or_default()
523}