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