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::{self, Const, Flags, Ty, TyCtxt, TypeVisitableExt, Unnormalized};
21use rustc_session::Session;
22use rustc_span::{self, DUMMY_SP, ErrorGuaranteed, Ident, Span};
23use rustc_trait_selection::error_reporting::TypeErrCtxt;
24use rustc_trait_selection::traits::{
25 self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt,
26};
27
28use crate::coercion::CoerceMany;
29use crate::{CoroutineTypes, Diverges, EnclosingBreakables, TypeckRootCtxt};
30
31pub(crate) struct FnCtxt<'a, 'tcx> {
43 pub(super) body_id: LocalDefId,
44
45 pub(super) param_env: ty::ParamEnv<'tcx>,
52
53 pub(super) ret_coercion: Option<RefCell<CoerceMany<'tcx>>>,
64
65 pub(super) ret_coercion_span: Cell<Option<Span>>,
67
68 pub(super) coroutine_types: Option<CoroutineTypes<'tcx>>,
69
70 pub(super) diverges: Cell<Diverges>,
104
105 pub(super) function_diverges_because_of_empty_arguments: Cell<Diverges>,
108
109 pub(super) is_whole_body: Cell<bool>,
111
112 pub(super) enclosing_breakables: RefCell<EnclosingBreakables<'tcx>>,
113
114 pub(super) root_ctxt: &'a TypeckRootCtxt<'tcx>,
115
116 pub(super) diverging_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 diverging_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 diverging_fallback_has_occurred: self.diverging_fallback_has_occurred.get(),
194 normalize_fn_sig: Box::new(|fn_sig| {
195 if fn_sig.skip_normalization().has_escaping_bound_vars() {
196 return fn_sig.skip_normalization();
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.evaluate_obligations_error_on_ambiguity().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.skip_normalization()
209 })
210 }),
211 autoderef_steps: Box::new(|ty| {
212 let mut autoderef = self.autoderef(DUMMY_SP, ty).silence_errors();
213 let mut steps = ::alloc::vec::Vec::new()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, Unnormalized::new_wip(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 = ::alloc::vec::Vec::new()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(
330 &ObligationCause::dummy(),
331 self.param_env,
332 Unnormalized::new_wip(self_ty),
333 );
334
335 let impl_args = infcx.fresh_args_for_item(span, impl_);
336 let impl_ty = tcx.type_of(impl_).instantiate(tcx, impl_args);
337 let impl_ty = ocx.normalize(&ObligationCause::dummy(), self.param_env, impl_ty);
338
339 if ocx.eq(&ObligationCause::dummy(), self.param_env, impl_ty, self_ty).is_err() {
341 return false;
342 }
343
344 let impl_bounds = tcx.predicates_of(impl_).instantiate(tcx, impl_args);
346 let impl_obligations = traits::predicates_for_generics(
347 |_, _| ObligationCause::dummy(),
348 |pred| ocx.normalize(&ObligationCause::dummy(), self.param_env, pred),
349 self.param_env,
350 impl_bounds,
351 );
352 ocx.register_obligations(impl_obligations);
353
354 let mut errors = ocx.try_evaluate_obligations();
355 if !errors.is_empty() {
356 fulfillment_errors.append(&mut errors);
357 return false;
358 }
359
360 true
361 };
362
363 let mut universes = if self_ty.has_escaping_bound_vars() {
364 ::alloc::vec::from_elem(None, self_ty.outer_exclusive_binder().as_usize())vec![None; self_ty.outer_exclusive_binder().as_usize()]
365 } else {
366 ::alloc::vec::Vec::new()vec![]
367 };
368
369 let candidates =
370 traits::with_replaced_escaping_bound_vars(infcx, &mut universes, self_ty, |self_ty| {
371 candidates
372 .into_iter()
373 .filter(|&InherentAssocCandidate { impl_, .. }| {
374 infcx.probe(|_| filter_iat_candidate(self_ty, impl_))
375 })
376 .collect()
377 });
378
379 (candidates, fulfillment_errors)
380 }
381
382 fn lower_assoc_item_path(
383 &self,
384 span: Span,
385 item_def_id: DefId,
386 item_segment: &rustc_hir::PathSegment<'tcx>,
387 poly_trait_ref: ty::PolyTraitRef<'tcx>,
388 ) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> {
389 let trait_ref = self.instantiate_binder_with_fresh_vars(
390 span,
391 infer::BoundRegionConversionTime::AssocTypeProjection(item_def_id),
393 poly_trait_ref,
394 );
395
396 let item_args = self.lowerer().lower_generic_args_of_assoc_item(
397 span,
398 item_def_id,
399 item_segment,
400 trait_ref.args,
401 );
402
403 Ok((item_def_id, item_args))
404 }
405
406 fn probe_adt(&self, span: Span, ty: Ty<'tcx>) -> Option<ty::AdtDef<'tcx>> {
407 match ty.kind() {
408 ty::Adt(adt_def, _) => Some(*adt_def),
409 ty::Alias(ty::AliasTy {
411 kind: ty::Projection { .. } | ty::Inherent { .. } | ty::Free { .. },
412 ..
413 }) if !ty.has_escaping_bound_vars() => {
414 if self.next_trait_solver() {
415 self.try_structurally_resolve_type(span, ty).ty_adt_def()
416 } else {
417 self.normalize(span, Unnormalized::new_wip(ty)).ty_adt_def()
418 }
419 }
420 _ => None,
421 }
422 }
423
424 fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span) {
425 let ty = if !ty.has_escaping_bound_vars() {
427 if let ty::Alias(ty::AliasTy {
432 kind: ty::Projection { def_id } | ty::Free { def_id },
433 args,
434 ..
435 }) = ty.kind()
436 {
437 self.add_required_obligations_for_hir(span, *def_id, args, hir_id);
438 }
439
440 self.normalize(span, Unnormalized::new_wip(ty))
441 } else {
442 ty
443 };
444 self.write_ty(hir_id, ty)
445 }
446
447 fn infcx(&self) -> Option<&infer::InferCtxt<'tcx>> {
448 Some(&self.infcx)
449 }
450
451 fn lower_fn_sig(
452 &self,
453 decl: &rustc_hir::FnDecl<'tcx>,
454 _generics: Option<&rustc_hir::Generics<'_>>,
455 _hir_id: rustc_hir::HirId,
456 _hir_ty: Option<&hir::Ty<'_>>,
457 ) -> (Vec<Ty<'tcx>>, Ty<'tcx>) {
458 let input_tys = decl.inputs.iter().map(|a| self.lowerer().lower_ty(a)).collect();
459
460 let output_ty = match decl.output {
461 hir::FnRetTy::Return(output) => self.lowerer().lower_ty(output),
462 hir::FnRetTy::DefaultReturn(..) => self.tcx().types.unit,
463 };
464 (input_tys, output_ty)
465 }
466
467 fn dyn_compatibility_violations(&self, trait_def_id: DefId) -> Vec<DynCompatibilityViolation> {
468 self.tcx.dyn_compatibility_violations(trait_def_id).to_vec()
469 }
470}
471
472#[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)]
478pub(crate) struct LoweredTy<'tcx> {
479 pub raw: Ty<'tcx>,
481
482 pub normalized: Ty<'tcx>,
484}
485
486impl<'tcx> LoweredTy<'tcx> {
487 fn from_raw(fcx: &FnCtxt<'_, 'tcx>, span: Span, raw: Ty<'tcx>) -> LoweredTy<'tcx> {
488 let normalized = if fcx.next_trait_solver() {
493 fcx.try_structurally_resolve_type(span, raw)
494 } else {
495 fcx.normalize(span, Unnormalized::new_wip(raw))
496 };
497 LoweredTy { raw, normalized }
498 }
499}
500
501fn never_type_behavior(tcx: TyCtxt<'_>) -> (DivergingFallbackBehavior, DivergingBlockBehavior) {
502 let (fallback, block) = parse_never_type_options_attr(tcx);
503 let fallback = fallback.unwrap_or_else(|| default_fallback(tcx));
504 let block = block.unwrap_or_default();
505
506 (fallback, block)
507}
508
509fn default_fallback(tcx: TyCtxt<'_>) -> DivergingFallbackBehavior {
511 if tcx.sess.edition().at_least_rust_2024() {
513 return DivergingFallbackBehavior::ToNever;
514 }
515
516 DivergingFallbackBehavior::ToUnit
518}
519
520fn parse_never_type_options_attr(
521 tcx: TyCtxt<'_>,
522) -> (Option<DivergingFallbackBehavior>, Option<DivergingBlockBehavior>) {
523 {
'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()
527}