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