mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-02 19:53:46 +00:00
extract instantiate_anon_types
to the InferCtxt
No functional change.
This commit is contained in:
parent
4a967c9df7
commit
e96f4be03d
200
src/librustc/infer/anon_types/mod.rs
Normal file
200
src/librustc/infer/anon_types/mod.rs
Normal file
@ -0,0 +1,200 @@
|
||||
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use hir::def_id::DefId;
|
||||
use infer::{InferCtxt, InferOk, TypeVariableOrigin};
|
||||
use syntax::ast;
|
||||
use traits::{self, PredicateObligation};
|
||||
use ty::{self, Ty};
|
||||
use ty::fold::{BottomUpFolder, TypeFoldable};
|
||||
use ty::subst::Substs;
|
||||
use util::nodemap::DefIdMap;
|
||||
|
||||
pub type AnonTypeMap<'tcx> = DefIdMap<AnonTypeDecl<'tcx>>;
|
||||
|
||||
/// Information about the anonymous, abstract types whose values we
|
||||
/// are inferring in this function (these are the `impl Trait` that
|
||||
/// appear in the return type).
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct AnonTypeDecl<'tcx> {
|
||||
/// The substitutions that we apply to the abstract that that this
|
||||
/// `impl Trait` desugars to. e.g., if:
|
||||
///
|
||||
/// fn foo<'a, 'b, T>() -> impl Trait<'a>
|
||||
///
|
||||
/// winds up desugared to:
|
||||
///
|
||||
/// abstract type Foo<'x, T>: Trait<'x>
|
||||
/// fn foo<'a, 'b, T>() -> Foo<'a, T>
|
||||
///
|
||||
/// then `substs` would be `['a, T]`.
|
||||
pub substs: &'tcx Substs<'tcx>,
|
||||
|
||||
/// The type variable that represents the value of the abstract type
|
||||
/// that we require. In other words, after we compile this function,
|
||||
/// we will be created a constraint like:
|
||||
///
|
||||
/// Foo<'a, T> = ?C
|
||||
///
|
||||
/// where `?C` is the value of this type variable. =) It may
|
||||
/// naturally refer to the type and lifetime parameters in scope
|
||||
/// in this function, though ultimately it should only reference
|
||||
/// those that are arguments to `Foo` in the constraint above. (In
|
||||
/// other words, `?C` should not include `'b`, even though it's a
|
||||
/// lifetime parameter on `foo`.)
|
||||
pub concrete_ty: Ty<'tcx>,
|
||||
|
||||
/// True if the `impl Trait` bounds include region bounds.
|
||||
/// For example, this would be true for:
|
||||
///
|
||||
/// fn foo<'a, 'b, 'c>() -> impl Trait<'c> + 'a + 'b
|
||||
///
|
||||
/// but false for:
|
||||
///
|
||||
/// fn foo<'c>() -> impl Trait<'c>
|
||||
///
|
||||
/// unless `Trait` was declared like:
|
||||
///
|
||||
/// trait Trait<'c>: 'c
|
||||
///
|
||||
/// in which case it would be true.
|
||||
///
|
||||
/// This is used during regionck to decide whether we need to
|
||||
/// impose any additional constraints to ensure that region
|
||||
/// variables in `concrete_ty` wind up being constrained to
|
||||
/// something from `substs` (or, at minimum, things that outlive
|
||||
/// the fn body). (Ultimately, writeback is responsible for this
|
||||
/// check.)
|
||||
pub has_required_region_bounds: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
/// Replace all anonymized types in `value` with fresh inference variables
|
||||
/// and creates appropriate obligations. For example, given the input:
|
||||
///
|
||||
/// impl Iterator<Item = impl Debug>
|
||||
///
|
||||
/// this method would create two type variables, `?0` and `?1`. It would
|
||||
/// return the type `?0` but also the obligations:
|
||||
///
|
||||
/// ?0: Iterator<Item = ?1>
|
||||
/// ?1: Debug
|
||||
///
|
||||
/// Moreover, it returns a `AnonTypeMap` that would map `?0` to
|
||||
/// info about the `impl Iterator<..>` type and `?1` to info about
|
||||
/// the `impl Debug` type.
|
||||
pub fn instantiate_anon_types<T: TypeFoldable<'tcx>>(
|
||||
&self,
|
||||
body_id: ast::NodeId,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
value: &T,
|
||||
) -> InferOk<'tcx, (T, AnonTypeMap<'tcx>)> {
|
||||
debug!(
|
||||
"instantiate_anon_types(value={:?}, body_id={:?}, param_env={:?})",
|
||||
value,
|
||||
body_id,
|
||||
param_env,
|
||||
);
|
||||
let mut instantiator = Instantiator {
|
||||
infcx: self,
|
||||
body_id,
|
||||
param_env,
|
||||
anon_types: DefIdMap(),
|
||||
obligations: vec![],
|
||||
};
|
||||
let value = instantiator.instantiate_anon_types_in_map(value);
|
||||
InferOk {
|
||||
value: (value, instantiator.anon_types),
|
||||
obligations: instantiator.obligations,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Instantiator<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
||||
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
|
||||
body_id: ast::NodeId,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
anon_types: AnonTypeMap<'tcx>,
|
||||
obligations: Vec<PredicateObligation<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
|
||||
fn instantiate_anon_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: &T) -> T {
|
||||
debug!("instantiate_anon_types_in_map(value={:?})", value);
|
||||
value.fold_with(&mut BottomUpFolder {
|
||||
tcx: self.infcx.tcx,
|
||||
fldop: |ty| if let ty::TyAnon(def_id, substs) = ty.sty {
|
||||
self.fold_anon_ty(ty, def_id, substs)
|
||||
} else {
|
||||
ty
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
fn fold_anon_ty(
|
||||
&mut self,
|
||||
ty: Ty<'tcx>,
|
||||
def_id: DefId,
|
||||
substs: &'tcx Substs<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
let infcx = self.infcx;
|
||||
let tcx = infcx.tcx;
|
||||
|
||||
debug!(
|
||||
"instantiate_anon_types: TyAnon(def_id={:?}, substs={:?})",
|
||||
def_id,
|
||||
substs
|
||||
);
|
||||
|
||||
// Use the same type variable if the exact same TyAnon appears more
|
||||
// than once in the return type (e.g. if it's passed to a type alias).
|
||||
if let Some(anon_defn) = self.anon_types.get(&def_id) {
|
||||
return anon_defn.concrete_ty;
|
||||
}
|
||||
let span = tcx.def_span(def_id);
|
||||
let ty_var = infcx.next_ty_var(TypeVariableOrigin::TypeInference(span));
|
||||
|
||||
let predicates_of = tcx.predicates_of(def_id);
|
||||
let bounds = predicates_of.instantiate(tcx, substs);
|
||||
debug!("instantiate_anon_types: bounds={:?}", bounds);
|
||||
|
||||
let required_region_bounds = tcx.required_region_bounds(ty, bounds.predicates.clone());
|
||||
debug!(
|
||||
"instantiate_anon_types: required_region_bounds={:?}",
|
||||
required_region_bounds
|
||||
);
|
||||
|
||||
self.anon_types.insert(
|
||||
def_id,
|
||||
AnonTypeDecl {
|
||||
substs,
|
||||
concrete_ty: ty_var,
|
||||
has_required_region_bounds: !required_region_bounds.is_empty(),
|
||||
},
|
||||
);
|
||||
debug!("instantiate_anon_types: ty_var={:?}", ty_var);
|
||||
|
||||
for predicate in bounds.predicates {
|
||||
// Change the predicate to refer to the type variable,
|
||||
// which will be the concrete type, instead of the TyAnon.
|
||||
// This also instantiates nested `impl Trait`.
|
||||
let predicate = self.instantiate_anon_types_in_map(&predicate);
|
||||
|
||||
let cause = traits::ObligationCause::new(span, self.body_id, traits::SizedReturnType);
|
||||
|
||||
// Require that the predicate holds for the concrete type.
|
||||
debug!("instantiate_anon_types: predicate={:?}", predicate);
|
||||
self.obligations
|
||||
.push(traits::Obligation::new(cause, self.param_env, predicate));
|
||||
}
|
||||
|
||||
ty_var
|
||||
}
|
||||
}
|
@ -48,6 +48,7 @@ use self::outlives::env::OutlivesEnvironment;
|
||||
use self::type_variable::TypeVariableOrigin;
|
||||
use self::unify_key::ToType;
|
||||
|
||||
pub mod anon_types;
|
||||
pub mod at;
|
||||
mod combine;
|
||||
mod equate;
|
||||
|
@ -90,6 +90,7 @@ use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
|
||||
use std::slice;
|
||||
use namespace::Namespace;
|
||||
use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin};
|
||||
use rustc::infer::anon_types::AnonTypeDecl;
|
||||
use rustc::infer::type_variable::{TypeVariableOrigin};
|
||||
use rustc::middle::region;
|
||||
use rustc::ty::subst::{Kind, Subst, Substs};
|
||||
@ -97,7 +98,7 @@ use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCo
|
||||
use rustc::ty::{ParamTy, LvaluePreference, NoPreference, PreferMutLvalue};
|
||||
use rustc::ty::{self, Ty, TyCtxt, Visibility};
|
||||
use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
|
||||
use rustc::ty::fold::{BottomUpFolder, TypeFoldable};
|
||||
use rustc::ty::fold::TypeFoldable;
|
||||
use rustc::ty::maps::Providers;
|
||||
use rustc::ty::util::{Representability, IntTypeExt};
|
||||
use errors::{DiagnosticBuilder, DiagnosticId};
|
||||
@ -225,62 +226,6 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||
body_id: Option<hir::BodyId>,
|
||||
}
|
||||
|
||||
/// Information about the anonymous, abstract types whose values we
|
||||
/// are inferring in this function (these are the `impl Trait` that
|
||||
/// appear in the return type).
|
||||
#[derive(Debug)]
|
||||
struct AnonTypeDecl<'tcx> {
|
||||
/// The substitutions that we apply to the abstract that that this
|
||||
/// `impl Trait` desugars to. e.g., if:
|
||||
///
|
||||
/// fn foo<'a, 'b, T>() -> impl Trait<'a>
|
||||
///
|
||||
/// winds up desugared to:
|
||||
///
|
||||
/// abstract type Foo<'x, T>: Trait<'x>
|
||||
/// fn foo<'a, 'b, T>() -> Foo<'a, T>
|
||||
///
|
||||
/// then `substs` would be `['a, T]`.
|
||||
substs: &'tcx Substs<'tcx>,
|
||||
|
||||
/// The type variable that represents the value of the abstract type
|
||||
/// that we require. In other words, after we compile this function,
|
||||
/// we will be created a constraint like:
|
||||
///
|
||||
/// Foo<'a, T> = ?C
|
||||
///
|
||||
/// where `?C` is the value of this type variable. =) It may
|
||||
/// naturally refer to the type and lifetime parameters in scope
|
||||
/// in this function, though ultimately it should only reference
|
||||
/// those that are arguments to `Foo` in the constraint above. (In
|
||||
/// other words, `?C` should not include `'b`, even though it's a
|
||||
/// lifetime parameter on `foo`.)
|
||||
concrete_ty: Ty<'tcx>,
|
||||
|
||||
/// True if the `impl Trait` bounds include region bounds.
|
||||
/// For example, this would be true for:
|
||||
///
|
||||
/// fn foo<'a, 'b, 'c>() -> impl Trait<'c> + 'a + 'b
|
||||
///
|
||||
/// but false for:
|
||||
///
|
||||
/// fn foo<'c>() -> impl Trait<'c>
|
||||
///
|
||||
/// unless `Trait` was declared like:
|
||||
///
|
||||
/// trait Trait<'c>: 'c
|
||||
///
|
||||
/// in which case it would be true.
|
||||
///
|
||||
/// This is used during regionck to decide whether we need to
|
||||
/// impose any additional constraints to ensure that region
|
||||
/// variables in `concrete_ty` wind up being constrained to
|
||||
/// something from `substs` (or, at minimum, things that outlive
|
||||
/// the fn body). (Ultimately, writeback is responsible for this
|
||||
/// check.)
|
||||
has_required_region_bounds: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> Deref for Inherited<'a, 'gcx, 'tcx> {
|
||||
type Target = InferCtxt<'a, 'gcx, 'tcx>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
@ -892,8 +837,6 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
&fn_sig);
|
||||
|
||||
let fcx = check_fn(&inh, param_env, fn_sig, decl, id, body, false).0;
|
||||
// Ensure anon_types have been instantiated prior to entering regionck
|
||||
fcx.instantiate_anon_types(&fn_sig.output());
|
||||
fcx
|
||||
} else {
|
||||
let fcx = FnCtxt::new(&inh, param_env, body.value.id);
|
||||
@ -1042,7 +985,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
|
||||
|
||||
let ret_ty = fn_sig.output();
|
||||
fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::SizedReturnType);
|
||||
let ret_ty = fcx.instantiate_anon_types(&ret_ty);
|
||||
let ret_ty = fcx.instantiate_anon_types_from_return_value(&ret_ty);
|
||||
fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
|
||||
fn_sig = fcx.tcx.mk_fn_sig(
|
||||
fn_sig.inputs().iter().cloned(),
|
||||
@ -1933,60 +1876,28 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
result
|
||||
}
|
||||
|
||||
/// Replace all anonymized types with fresh inference variables
|
||||
/// and record them for writeback.
|
||||
fn instantiate_anon_types<T: TypeFoldable<'tcx>>(&self, value: &T) -> T {
|
||||
debug!("instantiate_anon_types(value={:?})", value);
|
||||
value.fold_with(&mut BottomUpFolder { tcx: self.tcx, fldop: |ty| {
|
||||
if let ty::TyAnon(def_id, substs) = ty.sty {
|
||||
debug!("instantiate_anon_types: TyAnon(def_id={:?}, substs={:?})", def_id, substs);
|
||||
/// Replace the anonymized types from the return value of the
|
||||
/// function with type variables and records the `AnonTypeMap` for
|
||||
/// later use during writeback. See
|
||||
/// `InferCtxt::instantiate_anon_types` for more details.
|
||||
fn instantiate_anon_types_from_return_value<T: TypeFoldable<'tcx>>(&self, value: &T) -> T {
|
||||
debug!("instantiate_anon_types_from_return_value(value={:?})", value);
|
||||
|
||||
// Use the same type variable if the exact same TyAnon appears more
|
||||
// than once in the return type (e.g. if it's passed to a type alias).
|
||||
if let Some(anon_defn) = self.anon_types.borrow().get(&def_id) {
|
||||
return anon_defn.concrete_ty;
|
||||
}
|
||||
let span = self.tcx.def_span(def_id);
|
||||
let ty_var = self.next_ty_var(TypeVariableOrigin::TypeInference(span));
|
||||
let (value, anon_type_map) = self.register_infer_ok_obligations(
|
||||
self.instantiate_anon_types(
|
||||
self.body_id,
|
||||
self.param_env,
|
||||
value,
|
||||
)
|
||||
);
|
||||
|
||||
let predicates_of = self.tcx.predicates_of(def_id);
|
||||
let bounds = predicates_of.instantiate(self.tcx, substs);
|
||||
debug!("instantiate_anon_types: bounds={:?}", bounds);
|
||||
let mut anon_types = self.anon_types.borrow_mut();
|
||||
for (ty, decl) in anon_type_map {
|
||||
let old_value = anon_types.insert(ty, decl);
|
||||
assert!(old_value.is_none(), "instantiated twice: {:?}/{:?}", ty, decl);
|
||||
}
|
||||
|
||||
let required_region_bounds =
|
||||
self.tcx.required_region_bounds(ty, bounds.predicates.clone());
|
||||
debug!("instantiate_anon_types: required_region_bounds={:?}",
|
||||
required_region_bounds);
|
||||
|
||||
self.anon_types.borrow_mut().insert(def_id, AnonTypeDecl {
|
||||
substs,
|
||||
concrete_ty: ty_var,
|
||||
has_required_region_bounds: !required_region_bounds.is_empty(),
|
||||
});
|
||||
debug!("instantiate_anon_types: ty_var={:?}", ty_var);
|
||||
|
||||
for predicate in bounds.predicates {
|
||||
// Change the predicate to refer to the type variable,
|
||||
// which will be the concrete type, instead of the TyAnon.
|
||||
// This also instantiates nested `impl Trait`.
|
||||
let predicate = self.instantiate_anon_types(&predicate);
|
||||
|
||||
// Require that the predicate holds for the concrete type.
|
||||
let cause = traits::ObligationCause::new(span,
|
||||
self.body_id,
|
||||
traits::SizedReturnType);
|
||||
|
||||
debug!("instantiate_anon_types: predicate={:?}", predicate);
|
||||
self.register_predicate(traits::Obligation::new(cause,
|
||||
self.param_env,
|
||||
predicate));
|
||||
}
|
||||
|
||||
ty_var
|
||||
} else {
|
||||
ty
|
||||
}
|
||||
}})
|
||||
value
|
||||
}
|
||||
|
||||
fn normalize_associated_types_in<T>(&self, span: Span, value: &T) -> T
|
||||
|
@ -81,6 +81,7 @@ This API is completely unstable and subject to change.
|
||||
#![feature(match_default_bindings)]
|
||||
#![feature(never_type)]
|
||||
#![feature(quote)]
|
||||
#![feature(refcell_replace_swap)]
|
||||
#![feature(rustc_diagnostic_macros)]
|
||||
#![feature(slice_patterns)]
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user