mod _impl;
mod checks;
mod suggestions;
pub use _impl::*;
pub use checks::*;
pub use suggestions::*;
use crate::astconv::AstConv;
use crate::check::coercion::DynamicCoerceMany;
use crate::check::{Diverges, EnclosingBreakables, Inherited, UnsafetyState};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_infer::infer;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
use rustc_middle::hir::map::blocks::FnLikeNode;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::{self, Const, Ty, TyCtxt};
use rustc_session::Session;
use rustc_span::{self, Span};
use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
use std::cell::{Cell, RefCell};
use std::ops::Deref;
pub struct FnCtxt<'a, 'tcx> {
pub(super) body_id: hir::HirId,
pub(super) param_env: ty::ParamEnv<'tcx>,
err_count_on_creation: usize,
pub(super) ret_coercion: Option<RefCell<DynamicCoerceMany<'tcx>>>,
pub(super) ret_coercion_impl_trait: Option<Ty<'tcx>>,
pub(super) ret_type_span: Option<Span>,
pub(super) in_tail_expr: bool,
pub(super) ret_coercion_span: RefCell<Option<Span>>,
pub(super) resume_yield_tys: Option<(Ty<'tcx>, Ty<'tcx>)>,
pub(super) ps: RefCell<UnsafetyState>,
pub(super) diverges: Cell<Diverges>,
pub(super) has_errors: Cell<bool>,
pub(super) enclosing_breakables: RefCell<EnclosingBreakables<'tcx>>,
pub(super) inh: &'a Inherited<'a, 'tcx>,
}
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub fn new(
inh: &'a Inherited<'a, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
body_id: hir::HirId,
) -> FnCtxt<'a, 'tcx> {
FnCtxt {
body_id,
param_env,
err_count_on_creation: inh.tcx.sess.err_count(),
ret_coercion: None,
ret_coercion_impl_trait: None,
ret_type_span: None,
in_tail_expr: false,
ret_coercion_span: RefCell::new(None),
resume_yield_tys: None,
ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)),
diverges: Cell::new(Diverges::Maybe),
has_errors: Cell::new(false),
enclosing_breakables: RefCell::new(EnclosingBreakables {
stack: Vec::new(),
by_id: Default::default(),
}),
inh,
}
}
pub fn cause(&self, span: Span, code: ObligationCauseCode<'tcx>) -> ObligationCause<'tcx> {
ObligationCause::new(span, self.body_id, code)
}
pub fn misc(&self, span: Span) -> ObligationCause<'tcx> {
self.cause(span, ObligationCauseCode::MiscObligation)
}
pub fn sess(&self) -> &Session {
&self.tcx.sess
}
pub fn errors_reported_since_creation(&self) -> bool {
self.tcx.sess.err_count() > self.err_count_on_creation
}
}
impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> {
type Target = Inherited<'a, 'tcx>;
fn deref(&self) -> &Self::Target {
&self.inh
}
}
impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
self.tcx
}
fn item_def_id(&self) -> Option<DefId> {
None
}
fn default_constness_for_trait_bounds(&self) -> hir::Constness {
let node = self.tcx.hir().get(self.body_id);
if let Some(fn_like) = FnLikeNode::from_node(node) {
fn_like.constness()
} else {
hir::Constness::NotConst
}
}
fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> {
let tcx = self.tcx;
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
let item_id = tcx.hir().ty_param_owner(hir_id);
let item_def_id = tcx.hir().local_def_id(item_id);
let generics = tcx.generics_of(item_def_id);
let index = generics.param_def_id_to_index[&def_id];
ty::GenericPredicates {
parent: None,
predicates: tcx.arena.alloc_from_iter(
self.param_env.caller_bounds().iter().filter_map(|predicate| {
match predicate.skip_binders() {
ty::PredicateAtom::Trait(data, _) if data.self_ty().is_param(index) => {
let span = tcx.def_span(def_id);
Some((predicate, span))
}
_ => None,
}
}),
),
}
}
fn re_infer(&self, def: Option<&ty::GenericParamDef>, span: Span) -> Option<ty::Region<'tcx>> {
let v = match def {
Some(def) => infer::EarlyBoundRegion(span, def.name),
None => infer::MiscVariable(span),
};
Some(self.next_region_var(v))
}
fn allow_ty_infer(&self) -> bool {
true
}
fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
if let Some(param) = param {
if let GenericArgKind::Type(ty) = self.var_for_def(span, param).unpack() {
return ty;
}
unreachable!()
} else {
self.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::TypeInference,
span,
})
}
}
fn ct_infer(
&self,
ty: Ty<'tcx>,
param: Option<&ty::GenericParamDef>,
span: Span,
) -> &'tcx Const<'tcx> {
if let Some(param) = param {
if let GenericArgKind::Const(ct) = self.var_for_def(span, param).unpack() {
return ct;
}
unreachable!()
} else {
self.next_const_var(
ty,
ConstVariableOrigin { kind: ConstVariableOriginKind::ConstInference, span },
)
}
}
fn projected_ty_from_poly_trait_ref(
&self,
span: Span,
item_def_id: DefId,
item_segment: &hir::PathSegment<'_>,
poly_trait_ref: ty::PolyTraitRef<'tcx>,
) -> Ty<'tcx> {
let (trait_ref, _) = self.replace_bound_vars_with_fresh_vars(
span,
infer::LateBoundRegionConversionTime::AssocTypeProjection(item_def_id),
poly_trait_ref,
);
let item_substs = <dyn AstConv<'tcx>>::create_substs_for_associated_item(
self,
self.tcx,
span,
item_def_id,
item_segment,
trait_ref.substs,
);
self.tcx().mk_projection(item_def_id, item_substs)
}
fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
if ty.has_escaping_bound_vars() {
ty
} else {
self.normalize_associated_types_in(span, &ty)
}
}
fn set_tainted_by_errors(&self) {
self.infcx.set_tainted_by_errors()
}
fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, _span: Span) {
self.write_ty(hir_id, ty)
}
}