Auto merge of #76906 - Nicholas-Baron:shorten_typeck_check, r=oli-obk
Split rustc_typeck::check into separate files Contributing to #60302.
This commit is contained in:
commit
c113030f6b
7 changed files with 5090 additions and 4972 deletions
1344
compiler/rustc_typeck/src/check/check.rs
Normal file
1344
compiler/rustc_typeck/src/check/check.rs
Normal file
File diff suppressed because it is too large
Load diff
78
compiler/rustc_typeck/src/check/diverges.rs
Normal file
78
compiler/rustc_typeck/src/check/diverges.rs
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
use rustc_span::source_map::DUMMY_SP;
|
||||||
|
use rustc_span::{self, Span};
|
||||||
|
use std::{cmp, ops};
|
||||||
|
|
||||||
|
/// Tracks whether executing a node may exit normally (versus
|
||||||
|
/// return/break/panic, which "diverge", leaving dead code in their
|
||||||
|
/// wake). Tracked semi-automatically (through type variables marked
|
||||||
|
/// as diverging), with some manual adjustments for control-flow
|
||||||
|
/// primitives (approximating a CFG).
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub enum Diverges {
|
||||||
|
/// Potentially unknown, some cases converge,
|
||||||
|
/// others require a CFG to determine them.
|
||||||
|
Maybe,
|
||||||
|
|
||||||
|
/// Definitely known to diverge and therefore
|
||||||
|
/// not reach the next sibling or its parent.
|
||||||
|
Always {
|
||||||
|
/// The `Span` points to the expression
|
||||||
|
/// that caused us to diverge
|
||||||
|
/// (e.g. `return`, `break`, etc).
|
||||||
|
span: Span,
|
||||||
|
/// In some cases (e.g. a `match` expression
|
||||||
|
/// where all arms diverge), we may be
|
||||||
|
/// able to provide a more informative
|
||||||
|
/// message to the user.
|
||||||
|
/// If this is `None`, a default message
|
||||||
|
/// will be generated, which is suitable
|
||||||
|
/// for most cases.
|
||||||
|
custom_note: Option<&'static str>,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// Same as `Always` but with a reachability
|
||||||
|
/// warning already emitted.
|
||||||
|
WarnedAlways,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convenience impls for combining `Diverges`.
|
||||||
|
|
||||||
|
impl ops::BitAnd for Diverges {
|
||||||
|
type Output = Self;
|
||||||
|
fn bitand(self, other: Self) -> Self {
|
||||||
|
cmp::min(self, other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::BitOr for Diverges {
|
||||||
|
type Output = Self;
|
||||||
|
fn bitor(self, other: Self) -> Self {
|
||||||
|
cmp::max(self, other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::BitAndAssign for Diverges {
|
||||||
|
fn bitand_assign(&mut self, other: Self) {
|
||||||
|
*self = *self & other;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::BitOrAssign for Diverges {
|
||||||
|
fn bitor_assign(&mut self, other: Self) {
|
||||||
|
*self = *self | other;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Diverges {
|
||||||
|
/// Creates a `Diverges::Always` with the provided `span` and the default note message.
|
||||||
|
pub(super) fn always(span: Span) -> Diverges {
|
||||||
|
Diverges::Always { span, custom_note: None }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn is_always(self) -> bool {
|
||||||
|
// Enum comparison ignores the
|
||||||
|
// contents of fields, so we just
|
||||||
|
// fill them in with garbage here.
|
||||||
|
self >= Diverges::Always { span: DUMMY_SP, custom_note: None }
|
||||||
|
}
|
||||||
|
}
|
117
compiler/rustc_typeck/src/check/expectation.rs
Normal file
117
compiler/rustc_typeck/src/check/expectation.rs
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
|
use rustc_middle::ty::{self, Ty};
|
||||||
|
use rustc_span::{self, Span};
|
||||||
|
|
||||||
|
use super::Expectation::*;
|
||||||
|
use super::FnCtxt;
|
||||||
|
|
||||||
|
/// When type-checking an expression, we propagate downward
|
||||||
|
/// whatever type hint we are able in the form of an `Expectation`.
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub enum Expectation<'tcx> {
|
||||||
|
/// We know nothing about what type this expression should have.
|
||||||
|
NoExpectation,
|
||||||
|
|
||||||
|
/// This expression should have the type given (or some subtype).
|
||||||
|
ExpectHasType(Ty<'tcx>),
|
||||||
|
|
||||||
|
/// This expression will be cast to the `Ty`.
|
||||||
|
ExpectCastableToType(Ty<'tcx>),
|
||||||
|
|
||||||
|
/// This rvalue expression will be wrapped in `&` or `Box` and coerced
|
||||||
|
/// to `&Ty` or `Box<Ty>`, respectively. `Ty` is `[A]` or `Trait`.
|
||||||
|
ExpectRvalueLikeUnsized(Ty<'tcx>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'tcx> Expectation<'tcx> {
|
||||||
|
// Disregard "castable to" expectations because they
|
||||||
|
// can lead us astray. Consider for example `if cond
|
||||||
|
// {22} else {c} as u8` -- if we propagate the
|
||||||
|
// "castable to u8" constraint to 22, it will pick the
|
||||||
|
// type 22u8, which is overly constrained (c might not
|
||||||
|
// be a u8). In effect, the problem is that the
|
||||||
|
// "castable to" expectation is not the tightest thing
|
||||||
|
// we can say, so we want to drop it in this case.
|
||||||
|
// The tightest thing we can say is "must unify with
|
||||||
|
// else branch". Note that in the case of a "has type"
|
||||||
|
// constraint, this limitation does not hold.
|
||||||
|
|
||||||
|
// If the expected type is just a type variable, then don't use
|
||||||
|
// an expected type. Otherwise, we might write parts of the type
|
||||||
|
// when checking the 'then' block which are incompatible with the
|
||||||
|
// 'else' branch.
|
||||||
|
pub(super) fn adjust_for_branches(&self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> {
|
||||||
|
match *self {
|
||||||
|
ExpectHasType(ety) => {
|
||||||
|
let ety = fcx.shallow_resolve(ety);
|
||||||
|
if !ety.is_ty_var() { ExpectHasType(ety) } else { NoExpectation }
|
||||||
|
}
|
||||||
|
ExpectRvalueLikeUnsized(ety) => ExpectRvalueLikeUnsized(ety),
|
||||||
|
_ => NoExpectation,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Provides an expectation for an rvalue expression given an *optional*
|
||||||
|
/// hint, which is not required for type safety (the resulting type might
|
||||||
|
/// be checked higher up, as is the case with `&expr` and `box expr`), but
|
||||||
|
/// is useful in determining the concrete type.
|
||||||
|
///
|
||||||
|
/// The primary use case is where the expected type is a fat pointer,
|
||||||
|
/// like `&[isize]`. For example, consider the following statement:
|
||||||
|
///
|
||||||
|
/// let x: &[isize] = &[1, 2, 3];
|
||||||
|
///
|
||||||
|
/// In this case, the expected type for the `&[1, 2, 3]` expression is
|
||||||
|
/// `&[isize]`. If however we were to say that `[1, 2, 3]` has the
|
||||||
|
/// expectation `ExpectHasType([isize])`, that would be too strong --
|
||||||
|
/// `[1, 2, 3]` does not have the type `[isize]` but rather `[isize; 3]`.
|
||||||
|
/// It is only the `&[1, 2, 3]` expression as a whole that can be coerced
|
||||||
|
/// to the type `&[isize]`. Therefore, we propagate this more limited hint,
|
||||||
|
/// which still is useful, because it informs integer literals and the like.
|
||||||
|
/// See the test case `test/ui/coerce-expect-unsized.rs` and #20169
|
||||||
|
/// for examples of where this comes up,.
|
||||||
|
pub(super) fn rvalue_hint(fcx: &FnCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Expectation<'tcx> {
|
||||||
|
match fcx.tcx.struct_tail_without_normalization(ty).kind() {
|
||||||
|
ty::Slice(_) | ty::Str | ty::Dynamic(..) => ExpectRvalueLikeUnsized(ty),
|
||||||
|
_ => ExpectHasType(ty),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolves `expected` by a single level if it is a variable. If
|
||||||
|
// there is no expected type or resolution is not possible (e.g.,
|
||||||
|
// no constraints yet present), just returns `None`.
|
||||||
|
fn resolve(self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> {
|
||||||
|
match self {
|
||||||
|
NoExpectation => NoExpectation,
|
||||||
|
ExpectCastableToType(t) => ExpectCastableToType(fcx.resolve_vars_if_possible(&t)),
|
||||||
|
ExpectHasType(t) => ExpectHasType(fcx.resolve_vars_if_possible(&t)),
|
||||||
|
ExpectRvalueLikeUnsized(t) => ExpectRvalueLikeUnsized(fcx.resolve_vars_if_possible(&t)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn to_option(self, fcx: &FnCtxt<'a, 'tcx>) -> Option<Ty<'tcx>> {
|
||||||
|
match self.resolve(fcx) {
|
||||||
|
NoExpectation => None,
|
||||||
|
ExpectCastableToType(ty) | ExpectHasType(ty) | ExpectRvalueLikeUnsized(ty) => Some(ty),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// It sometimes happens that we want to turn an expectation into
|
||||||
|
/// a **hard constraint** (i.e., something that must be satisfied
|
||||||
|
/// for the program to type-check). `only_has_type` will return
|
||||||
|
/// such a constraint, if it exists.
|
||||||
|
pub(super) fn only_has_type(self, fcx: &FnCtxt<'a, 'tcx>) -> Option<Ty<'tcx>> {
|
||||||
|
match self.resolve(fcx) {
|
||||||
|
ExpectHasType(ty) => Some(ty),
|
||||||
|
NoExpectation | ExpectCastableToType(_) | ExpectRvalueLikeUnsized(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Like `only_has_type`, but instead of returning `None` if no
|
||||||
|
/// hard constraint exists, creates a fresh type variable.
|
||||||
|
pub(super) fn coercion_target_type(self, fcx: &FnCtxt<'a, 'tcx>, span: Span) -> Ty<'tcx> {
|
||||||
|
self.only_has_type(fcx).unwrap_or_else(|| {
|
||||||
|
fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
3200
compiler/rustc_typeck/src/check/fn_ctxt.rs
Normal file
3200
compiler/rustc_typeck/src/check/fn_ctxt.rs
Normal file
File diff suppressed because it is too large
Load diff
120
compiler/rustc_typeck/src/check/gather_locals.rs
Normal file
120
compiler/rustc_typeck/src/check/gather_locals.rs
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
use crate::check::{FnCtxt, LocalTy, UserType};
|
||||||
|
use rustc_hir as hir;
|
||||||
|
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
|
||||||
|
use rustc_hir::PatKind;
|
||||||
|
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
|
use rustc_middle::ty::Ty;
|
||||||
|
use rustc_span::Span;
|
||||||
|
use rustc_trait_selection::traits;
|
||||||
|
|
||||||
|
pub(super) struct GatherLocalsVisitor<'a, 'tcx> {
|
||||||
|
fcx: &'a FnCtxt<'a, 'tcx>,
|
||||||
|
parent_id: hir::HirId,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> {
|
||||||
|
pub(super) fn new(fcx: &'a FnCtxt<'a, 'tcx>, parent_id: hir::HirId) -> Self {
|
||||||
|
Self { fcx, parent_id }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assign(&mut self, span: Span, nid: hir::HirId, ty_opt: Option<LocalTy<'tcx>>) -> Ty<'tcx> {
|
||||||
|
match ty_opt {
|
||||||
|
None => {
|
||||||
|
// Infer the variable's type.
|
||||||
|
let var_ty = self.fcx.next_ty_var(TypeVariableOrigin {
|
||||||
|
kind: TypeVariableOriginKind::TypeInference,
|
||||||
|
span,
|
||||||
|
});
|
||||||
|
self.fcx
|
||||||
|
.locals
|
||||||
|
.borrow_mut()
|
||||||
|
.insert(nid, LocalTy { decl_ty: var_ty, revealed_ty: var_ty });
|
||||||
|
var_ty
|
||||||
|
}
|
||||||
|
Some(typ) => {
|
||||||
|
// Take type that the user specified.
|
||||||
|
self.fcx.locals.borrow_mut().insert(nid, typ);
|
||||||
|
typ.revealed_ty
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
|
||||||
|
type Map = intravisit::ErasedMap<'tcx>;
|
||||||
|
|
||||||
|
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
|
||||||
|
NestedVisitorMap::None
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add explicitly-declared locals.
|
||||||
|
fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) {
|
||||||
|
let local_ty = match local.ty {
|
||||||
|
Some(ref ty) => {
|
||||||
|
let o_ty = self.fcx.to_ty(&ty);
|
||||||
|
|
||||||
|
let revealed_ty = if self.fcx.tcx.features().impl_trait_in_bindings {
|
||||||
|
self.fcx.instantiate_opaque_types_from_value(self.parent_id, &o_ty, ty.span)
|
||||||
|
} else {
|
||||||
|
o_ty
|
||||||
|
};
|
||||||
|
|
||||||
|
let c_ty = self
|
||||||
|
.fcx
|
||||||
|
.inh
|
||||||
|
.infcx
|
||||||
|
.canonicalize_user_type_annotation(&UserType::Ty(revealed_ty));
|
||||||
|
debug!(
|
||||||
|
"visit_local: ty.hir_id={:?} o_ty={:?} revealed_ty={:?} c_ty={:?}",
|
||||||
|
ty.hir_id, o_ty, revealed_ty, c_ty
|
||||||
|
);
|
||||||
|
self.fcx
|
||||||
|
.typeck_results
|
||||||
|
.borrow_mut()
|
||||||
|
.user_provided_types_mut()
|
||||||
|
.insert(ty.hir_id, c_ty);
|
||||||
|
|
||||||
|
Some(LocalTy { decl_ty: o_ty, revealed_ty })
|
||||||
|
}
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
self.assign(local.span, local.hir_id, local_ty);
|
||||||
|
|
||||||
|
debug!(
|
||||||
|
"local variable {:?} is assigned type {}",
|
||||||
|
local.pat,
|
||||||
|
self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&local.hir_id).unwrap().decl_ty)
|
||||||
|
);
|
||||||
|
intravisit::walk_local(self, local);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add pattern bindings.
|
||||||
|
fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) {
|
||||||
|
if let PatKind::Binding(_, _, ident, _) = p.kind {
|
||||||
|
let var_ty = self.assign(p.span, p.hir_id, None);
|
||||||
|
|
||||||
|
if !self.fcx.tcx.features().unsized_locals {
|
||||||
|
self.fcx.require_type_is_sized(var_ty, p.span, traits::VariableType(p.hir_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!(
|
||||||
|
"pattern binding {} is assigned to {} with type {:?}",
|
||||||
|
ident,
|
||||||
|
self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&p.hir_id).unwrap().decl_ty),
|
||||||
|
var_ty
|
||||||
|
);
|
||||||
|
}
|
||||||
|
intravisit::walk_pat(self, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't descend into the bodies of nested closures.
|
||||||
|
fn visit_fn(
|
||||||
|
&mut self,
|
||||||
|
_: intravisit::FnKind<'tcx>,
|
||||||
|
_: &'tcx hir::FnDecl<'tcx>,
|
||||||
|
_: hir::BodyId,
|
||||||
|
_: Span,
|
||||||
|
_: hir::HirId,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
167
compiler/rustc_typeck/src/check/inherited.rs
Normal file
167
compiler/rustc_typeck/src/check/inherited.rs
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
use super::callee::DeferredCallResolution;
|
||||||
|
use super::MaybeInProgressTables;
|
||||||
|
|
||||||
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
|
use rustc_hir as hir;
|
||||||
|
use rustc_hir::def_id::{DefIdMap, LocalDefId};
|
||||||
|
use rustc_hir::HirIdMap;
|
||||||
|
use rustc_infer::infer;
|
||||||
|
use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
|
||||||
|
use rustc_middle::ty::fold::TypeFoldable;
|
||||||
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||||
|
use rustc_span::{self, Span};
|
||||||
|
use rustc_trait_selection::infer::InferCtxtExt as _;
|
||||||
|
use rustc_trait_selection::opaque_types::OpaqueTypeDecl;
|
||||||
|
use rustc_trait_selection::traits::{self, TraitEngine, TraitEngineExt};
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
/// Closures defined within the function. For example:
|
||||||
|
///
|
||||||
|
/// fn foo() {
|
||||||
|
/// bar(move|| { ... })
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// Here, the function `foo()` and the closure passed to
|
||||||
|
/// `bar()` will each have their own `FnCtxt`, but they will
|
||||||
|
/// share the inherited fields.
|
||||||
|
pub struct Inherited<'a, 'tcx> {
|
||||||
|
pub(super) infcx: InferCtxt<'a, 'tcx>,
|
||||||
|
|
||||||
|
pub(super) typeck_results: super::MaybeInProgressTables<'a, 'tcx>,
|
||||||
|
|
||||||
|
pub(super) locals: RefCell<HirIdMap<super::LocalTy<'tcx>>>,
|
||||||
|
|
||||||
|
pub(super) fulfillment_cx: RefCell<Box<dyn TraitEngine<'tcx>>>,
|
||||||
|
|
||||||
|
// Some additional `Sized` obligations badly affect type inference.
|
||||||
|
// These obligations are added in a later stage of typeck.
|
||||||
|
pub(super) deferred_sized_obligations:
|
||||||
|
RefCell<Vec<(Ty<'tcx>, Span, traits::ObligationCauseCode<'tcx>)>>,
|
||||||
|
|
||||||
|
// When we process a call like `c()` where `c` is a closure type,
|
||||||
|
// we may not have decided yet whether `c` is a `Fn`, `FnMut`, or
|
||||||
|
// `FnOnce` closure. In that case, we defer full resolution of the
|
||||||
|
// call until upvar inference can kick in and make the
|
||||||
|
// decision. We keep these deferred resolutions grouped by the
|
||||||
|
// def-id of the closure, so that once we decide, we can easily go
|
||||||
|
// back and process them.
|
||||||
|
pub(super) deferred_call_resolutions: RefCell<DefIdMap<Vec<DeferredCallResolution<'tcx>>>>,
|
||||||
|
|
||||||
|
pub(super) deferred_cast_checks: RefCell<Vec<super::cast::CastCheck<'tcx>>>,
|
||||||
|
|
||||||
|
pub(super) deferred_generator_interiors:
|
||||||
|
RefCell<Vec<(hir::BodyId, Ty<'tcx>, hir::GeneratorKind)>>,
|
||||||
|
|
||||||
|
// Opaque types found in explicit return types and their
|
||||||
|
// associated fresh inference variable. Writeback resolves these
|
||||||
|
// variables to get the concrete type, which can be used to
|
||||||
|
// 'de-opaque' OpaqueTypeDecl, after typeck is done with all functions.
|
||||||
|
pub(super) opaque_types: RefCell<DefIdMap<OpaqueTypeDecl<'tcx>>>,
|
||||||
|
|
||||||
|
/// A map from inference variables created from opaque
|
||||||
|
/// type instantiations (`ty::Infer`) to the actual opaque
|
||||||
|
/// type (`ty::Opaque`). Used during fallback to map unconstrained
|
||||||
|
/// opaque type inference variables to their corresponding
|
||||||
|
/// opaque type.
|
||||||
|
pub(super) opaque_types_vars: RefCell<FxHashMap<Ty<'tcx>, Ty<'tcx>>>,
|
||||||
|
|
||||||
|
pub(super) body_id: Option<hir::BodyId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'tcx> Deref for Inherited<'a, 'tcx> {
|
||||||
|
type Target = InferCtxt<'a, 'tcx>;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.infcx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper type of a temporary returned by `Inherited::build(...)`.
|
||||||
|
/// Necessary because we can't write the following bound:
|
||||||
|
/// `F: for<'b, 'tcx> where 'tcx FnOnce(Inherited<'b, 'tcx>)`.
|
||||||
|
pub struct InheritedBuilder<'tcx> {
|
||||||
|
infcx: infer::InferCtxtBuilder<'tcx>,
|
||||||
|
def_id: LocalDefId,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Inherited<'_, 'tcx> {
|
||||||
|
pub fn build(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> InheritedBuilder<'tcx> {
|
||||||
|
let hir_owner = tcx.hir().local_def_id_to_hir_id(def_id).owner;
|
||||||
|
|
||||||
|
InheritedBuilder {
|
||||||
|
infcx: tcx.infer_ctxt().with_fresh_in_progress_typeck_results(hir_owner),
|
||||||
|
def_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> InheritedBuilder<'tcx> {
|
||||||
|
pub fn enter<F, R>(&mut self, f: F) -> R
|
||||||
|
where
|
||||||
|
F: for<'a> FnOnce(Inherited<'a, 'tcx>) -> R,
|
||||||
|
{
|
||||||
|
let def_id = self.def_id;
|
||||||
|
self.infcx.enter(|infcx| f(Inherited::new(infcx, def_id)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Inherited<'a, 'tcx> {
|
||||||
|
pub(super) fn new(infcx: InferCtxt<'a, 'tcx>, def_id: LocalDefId) -> Self {
|
||||||
|
let tcx = infcx.tcx;
|
||||||
|
let item_id = tcx.hir().local_def_id_to_hir_id(def_id);
|
||||||
|
let body_id = tcx.hir().maybe_body_owned_by(item_id);
|
||||||
|
|
||||||
|
Inherited {
|
||||||
|
typeck_results: MaybeInProgressTables {
|
||||||
|
maybe_typeck_results: infcx.in_progress_typeck_results,
|
||||||
|
},
|
||||||
|
infcx,
|
||||||
|
fulfillment_cx: RefCell::new(TraitEngine::new(tcx)),
|
||||||
|
locals: RefCell::new(Default::default()),
|
||||||
|
deferred_sized_obligations: RefCell::new(Vec::new()),
|
||||||
|
deferred_call_resolutions: RefCell::new(Default::default()),
|
||||||
|
deferred_cast_checks: RefCell::new(Vec::new()),
|
||||||
|
deferred_generator_interiors: RefCell::new(Vec::new()),
|
||||||
|
opaque_types: RefCell::new(Default::default()),
|
||||||
|
opaque_types_vars: RefCell::new(Default::default()),
|
||||||
|
body_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn register_predicate(&self, obligation: traits::PredicateObligation<'tcx>) {
|
||||||
|
debug!("register_predicate({:?})", obligation);
|
||||||
|
if obligation.has_escaping_bound_vars() {
|
||||||
|
span_bug!(obligation.cause.span, "escaping bound vars in predicate {:?}", obligation);
|
||||||
|
}
|
||||||
|
self.fulfillment_cx.borrow_mut().register_predicate_obligation(self, obligation);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn register_predicates<I>(&self, obligations: I)
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = traits::PredicateObligation<'tcx>>,
|
||||||
|
{
|
||||||
|
for obligation in obligations {
|
||||||
|
self.register_predicate(obligation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn register_infer_ok_obligations<T>(&self, infer_ok: InferOk<'tcx, T>) -> T {
|
||||||
|
self.register_predicates(infer_ok.obligations);
|
||||||
|
infer_ok.value
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn normalize_associated_types_in<T>(
|
||||||
|
&self,
|
||||||
|
span: Span,
|
||||||
|
body_id: hir::HirId,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
value: &T,
|
||||||
|
) -> T
|
||||||
|
where
|
||||||
|
T: TypeFoldable<'tcx>,
|
||||||
|
{
|
||||||
|
let ok = self.partially_normalize_associated_types_in(span, body_id, param_env, value);
|
||||||
|
self.register_infer_ok_obligations(ok)
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue