mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
Rename the code that replaces unbound variables to "freshen" rather than "skolemize" -- strictly speaking, this is not skolemization, because it is not discharging quantifiers. Also, the trait selection code will still be doing true skolemization, so it would be a confusing overlap of names.
This commit is contained in:
parent
3cf0fbeee9
commit
416e62924e
@ -8,21 +8,21 @@
|
|||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
//! Skolemization is the process of replacing unknown variables with fresh types. The idea is that
|
//! Freshening is the process of replacing unknown variables with fresh types. The idea is that
|
||||||
//! the type, after skolemization, contains no inference variables but instead contains either a
|
//! the type, after freshening, contains no inference variables but instead contains either a
|
||||||
//! value for each variable or fresh "arbitrary" types wherever a variable would have been.
|
//! value for each variable or fresh "arbitrary" types wherever a variable would have been.
|
||||||
//!
|
//!
|
||||||
//! Skolemization is used primarily to get a good type for inserting into a cache. The result
|
//! Freshening is used primarily to get a good type for inserting into a cache. The result
|
||||||
//! summarizes what the type inferencer knows "so far". The primary place it is used right now is
|
//! summarizes what the type inferencer knows "so far". The primary place it is used right now is
|
||||||
//! in the trait matching algorithm, which needs to be able to cache whether an `impl` self type
|
//! in the trait matching algorithm, which needs to be able to cache whether an `impl` self type
|
||||||
//! matches some other type X -- *without* affecting `X`. That means if that if the type `X` is in
|
//! matches some other type X -- *without* affecting `X`. That means if that if the type `X` is in
|
||||||
//! fact an unbound type variable, we want the match to be regarded as ambiguous, because depending
|
//! fact an unbound type variable, we want the match to be regarded as ambiguous, because depending
|
||||||
//! on what type that type variable is ultimately assigned, the match may or may not succeed.
|
//! on what type that type variable is ultimately assigned, the match may or may not succeed.
|
||||||
//!
|
//!
|
||||||
//! Note that you should be careful not to allow the output of skolemization to leak to the user in
|
//! Note that you should be careful not to allow the output of freshening to leak to the user in
|
||||||
//! error messages or in any other form. Skolemization is only really useful as an internal detail.
|
//! error messages or in any other form. Freshening is only really useful as an internal detail.
|
||||||
//!
|
//!
|
||||||
//! __An important detail concerning regions.__ The skolemizer also replaces *all* regions with
|
//! __An important detail concerning regions.__ The freshener also replaces *all* regions with
|
||||||
//! 'static. The reason behind this is that, in general, we do not take region relationships into
|
//! 'static. The reason behind this is that, in general, we do not take region relationships into
|
||||||
//! account when making type-overloaded decisions. This is important because of the design of the
|
//! account when making type-overloaded decisions. This is important because of the design of the
|
||||||
//! region inferencer, which is not based on unification but rather on accumulating and then
|
//! region inferencer, which is not based on unification but rather on accumulating and then
|
||||||
@ -39,26 +39,26 @@ use std::collections::hash_map;
|
|||||||
use super::InferCtxt;
|
use super::InferCtxt;
|
||||||
use super::unify::InferCtxtMethodsForSimplyUnifiableTypes;
|
use super::unify::InferCtxtMethodsForSimplyUnifiableTypes;
|
||||||
|
|
||||||
pub struct TypeSkolemizer<'a, 'tcx:'a> {
|
pub struct TypeFreshener<'a, 'tcx:'a> {
|
||||||
infcx: &'a InferCtxt<'a, 'tcx>,
|
infcx: &'a InferCtxt<'a, 'tcx>,
|
||||||
skolemization_count: uint,
|
freshen_count: uint,
|
||||||
skolemization_map: hash_map::HashMap<ty::InferTy, Ty<'tcx>>,
|
freshen_map: hash_map::HashMap<ty::InferTy, Ty<'tcx>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> TypeSkolemizer<'a, 'tcx> {
|
impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
|
||||||
pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> TypeSkolemizer<'a, 'tcx> {
|
pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> TypeFreshener<'a, 'tcx> {
|
||||||
TypeSkolemizer {
|
TypeFreshener {
|
||||||
infcx: infcx,
|
infcx: infcx,
|
||||||
skolemization_count: 0,
|
freshen_count: 0,
|
||||||
skolemization_map: hash_map::HashMap::new(),
|
freshen_map: hash_map::HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn skolemize<F>(&mut self,
|
fn freshen<F>(&mut self,
|
||||||
opt_ty: Option<Ty<'tcx>>,
|
opt_ty: Option<Ty<'tcx>>,
|
||||||
key: ty::InferTy,
|
key: ty::InferTy,
|
||||||
skolemizer: F)
|
freshener: F)
|
||||||
-> Ty<'tcx> where
|
-> Ty<'tcx> where
|
||||||
F: FnOnce(uint) -> ty::InferTy,
|
F: FnOnce(uint) -> ty::InferTy,
|
||||||
{
|
{
|
||||||
match opt_ty {
|
match opt_ty {
|
||||||
@ -66,12 +66,12 @@ impl<'a, 'tcx> TypeSkolemizer<'a, 'tcx> {
|
|||||||
None => { }
|
None => { }
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.skolemization_map.entry(key) {
|
match self.freshen_map.entry(key) {
|
||||||
hash_map::Occupied(entry) => *entry.get(),
|
hash_map::Occupied(entry) => *entry.get(),
|
||||||
hash_map::Vacant(entry) => {
|
hash_map::Vacant(entry) => {
|
||||||
let index = self.skolemization_count;
|
let index = self.freshen_count;
|
||||||
self.skolemization_count += 1;
|
self.freshen_count += 1;
|
||||||
let t = ty::mk_infer(self.infcx.tcx, skolemizer(index));
|
let t = ty::mk_infer(self.infcx.tcx, freshener(index));
|
||||||
entry.set(t);
|
entry.set(t);
|
||||||
t
|
t
|
||||||
}
|
}
|
||||||
@ -79,7 +79,7 @@ impl<'a, 'tcx> TypeSkolemizer<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> TypeFolder<'tcx> for TypeSkolemizer<'a, 'tcx> {
|
impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
|
||||||
fn tcx<'b>(&'b self) -> &'b ty::ctxt<'tcx> {
|
fn tcx<'b>(&'b self) -> &'b ty::ctxt<'tcx> {
|
||||||
self.infcx.tcx
|
self.infcx.tcx
|
||||||
}
|
}
|
||||||
@ -106,37 +106,37 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeSkolemizer<'a, 'tcx> {
|
|||||||
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
||||||
match t.sty {
|
match t.sty {
|
||||||
ty::ty_infer(ty::TyVar(v)) => {
|
ty::ty_infer(ty::TyVar(v)) => {
|
||||||
self.skolemize(self.infcx.type_variables.borrow().probe(v),
|
self.freshen(self.infcx.type_variables.borrow().probe(v),
|
||||||
ty::TyVar(v),
|
ty::TyVar(v),
|
||||||
ty::SkolemizedTy)
|
ty::FreshTy)
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::ty_infer(ty::IntVar(v)) => {
|
ty::ty_infer(ty::IntVar(v)) => {
|
||||||
self.skolemize(self.infcx.probe_var(v),
|
self.freshen(self.infcx.probe_var(v),
|
||||||
ty::IntVar(v),
|
ty::IntVar(v),
|
||||||
ty::SkolemizedIntTy)
|
ty::FreshIntTy)
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::ty_infer(ty::FloatVar(v)) => {
|
ty::ty_infer(ty::FloatVar(v)) => {
|
||||||
self.skolemize(self.infcx.probe_var(v),
|
self.freshen(self.infcx.probe_var(v),
|
||||||
ty::FloatVar(v),
|
ty::FloatVar(v),
|
||||||
ty::SkolemizedIntTy)
|
ty::FreshIntTy)
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::ty_infer(ty::SkolemizedTy(c)) |
|
ty::ty_infer(ty::FreshTy(c)) |
|
||||||
ty::ty_infer(ty::SkolemizedIntTy(c)) => {
|
ty::ty_infer(ty::FreshIntTy(c)) => {
|
||||||
if c >= self.skolemization_count {
|
if c >= self.freshen_count {
|
||||||
self.tcx().sess.bug(
|
self.tcx().sess.bug(
|
||||||
format!("Encountered a skolemized type with id {} \
|
format!("Encountered a freshend type with id {} \
|
||||||
but our counter is only at {}",
|
but our counter is only at {}",
|
||||||
c,
|
c,
|
||||||
self.skolemization_count).as_slice());
|
self.freshen_count).as_slice());
|
||||||
}
|
}
|
||||||
t
|
t
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::ty_open(..) => {
|
ty::ty_open(..) => {
|
||||||
self.tcx().sess.bug("Cannot skolemize an open existential type");
|
self.tcx().sess.bug("Cannot freshen an open existential type");
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::ty_bool |
|
ty::ty_bool |
|
@ -19,7 +19,7 @@ pub use self::TypeOrigin::*;
|
|||||||
pub use self::ValuePairs::*;
|
pub use self::ValuePairs::*;
|
||||||
pub use self::fixup_err::*;
|
pub use self::fixup_err::*;
|
||||||
pub use middle::ty::IntVarValue;
|
pub use middle::ty::IntVarValue;
|
||||||
pub use self::skolemize::TypeSkolemizer;
|
pub use self::freshen::TypeFreshener;
|
||||||
|
|
||||||
use middle::subst;
|
use middle::subst;
|
||||||
use middle::subst::Substs;
|
use middle::subst::Substs;
|
||||||
@ -57,7 +57,7 @@ pub mod lattice;
|
|||||||
pub mod lub;
|
pub mod lub;
|
||||||
pub mod region_inference;
|
pub mod region_inference;
|
||||||
pub mod resolve;
|
pub mod resolve;
|
||||||
mod skolemize;
|
mod freshen;
|
||||||
pub mod sub;
|
pub mod sub;
|
||||||
pub mod type_variable;
|
pub mod type_variable;
|
||||||
pub mod unify;
|
pub mod unify;
|
||||||
@ -505,8 +505,8 @@ pub struct CombinedSnapshot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
pub fn skolemize<T:TypeFoldable<'tcx>>(&self, t: T) -> T {
|
pub fn freshen<T:TypeFoldable<'tcx>>(&self, t: T) -> T {
|
||||||
t.fold_with(&mut self.skolemizer())
|
t.fold_with(&mut self.freshener())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_var_diverges(&'a self, ty: Ty) -> bool {
|
pub fn type_var_diverges(&'a self, ty: Ty) -> bool {
|
||||||
@ -516,8 +516,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn skolemizer<'b>(&'b self) -> TypeSkolemizer<'b, 'tcx> {
|
pub fn freshener<'b>(&'b self) -> TypeFreshener<'b, 'tcx> {
|
||||||
skolemize::TypeSkolemizer::new(self)
|
freshen::TypeFreshener::new(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn combine_fields<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>)
|
pub fn combine_fields<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>)
|
||||||
|
@ -30,7 +30,7 @@ use middle::mem_categorization::Typer;
|
|||||||
use middle::subst::{Subst, Substs, VecPerParamSpace};
|
use middle::subst::{Subst, Substs, VecPerParamSpace};
|
||||||
use middle::ty::{mod, Ty, RegionEscape};
|
use middle::ty::{mod, Ty, RegionEscape};
|
||||||
use middle::infer;
|
use middle::infer;
|
||||||
use middle::infer::{InferCtxt, TypeSkolemizer};
|
use middle::infer::{InferCtxt, TypeFreshener};
|
||||||
use middle::ty_fold::TypeFoldable;
|
use middle::ty_fold::TypeFoldable;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::hash_map::HashMap;
|
use std::collections::hash_map::HashMap;
|
||||||
@ -44,12 +44,12 @@ pub struct SelectionContext<'cx, 'tcx:'cx> {
|
|||||||
param_env: &'cx ty::ParameterEnvironment<'tcx>,
|
param_env: &'cx ty::ParameterEnvironment<'tcx>,
|
||||||
typer: &'cx (Typer<'tcx>+'cx),
|
typer: &'cx (Typer<'tcx>+'cx),
|
||||||
|
|
||||||
/// Skolemizer used specifically for skolemizing entries on the
|
/// Freshener used specifically for skolemizing entries on the
|
||||||
/// obligation stack. This ensures that all entries on the stack
|
/// obligation stack. This ensures that all entries on the stack
|
||||||
/// at one time will have the same set of skolemized entries,
|
/// at one time will have the same set of skolemized entries,
|
||||||
/// which is important for checking for trait bounds that
|
/// which is important for checking for trait bounds that
|
||||||
/// recursively require themselves.
|
/// recursively require themselves.
|
||||||
skolemizer: TypeSkolemizer<'cx, 'tcx>,
|
freshener: TypeFreshener<'cx, 'tcx>,
|
||||||
|
|
||||||
/// If true, indicates that the evaluation should be conservative
|
/// If true, indicates that the evaluation should be conservative
|
||||||
/// and consider the possibility of types outside this crate.
|
/// and consider the possibility of types outside this crate.
|
||||||
@ -73,8 +73,8 @@ struct TraitObligationStack<'prev, 'tcx: 'prev> {
|
|||||||
obligation: &'prev TraitObligation<'tcx>,
|
obligation: &'prev TraitObligation<'tcx>,
|
||||||
|
|
||||||
/// Trait ref from `obligation` but skolemized with the
|
/// Trait ref from `obligation` but skolemized with the
|
||||||
/// selection-context's skolemizer. Used to check for recursion.
|
/// selection-context's freshener. Used to check for recursion.
|
||||||
skol_trait_ref: Rc<ty::PolyTraitRef<'tcx>>,
|
fresh_trait_ref: Rc<ty::PolyTraitRef<'tcx>>,
|
||||||
|
|
||||||
previous: Option<&'prev TraitObligationStack<'prev, 'tcx>>
|
previous: Option<&'prev TraitObligationStack<'prev, 'tcx>>
|
||||||
}
|
}
|
||||||
@ -172,7 +172,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
infcx: infcx,
|
infcx: infcx,
|
||||||
param_env: param_env,
|
param_env: param_env,
|
||||||
typer: typer,
|
typer: typer,
|
||||||
skolemizer: infcx.skolemizer(),
|
freshener: infcx.freshener(),
|
||||||
intercrate: false,
|
intercrate: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -185,7 +185,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
infcx: infcx,
|
infcx: infcx,
|
||||||
param_env: param_env,
|
param_env: param_env,
|
||||||
typer: typer,
|
typer: typer,
|
||||||
skolemizer: infcx.skolemizer(),
|
freshener: infcx.freshener(),
|
||||||
intercrate: true,
|
intercrate: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -347,16 +347,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
// This suffices to allow chains like `FnMut` implemented in
|
// This suffices to allow chains like `FnMut` implemented in
|
||||||
// terms of `Fn` etc, but we could probably make this more
|
// terms of `Fn` etc, but we could probably make this more
|
||||||
// precise still.
|
// precise still.
|
||||||
let input_types = stack.skol_trait_ref.value.input_types();
|
let input_types = stack.fresh_trait_ref.value.input_types();
|
||||||
let unbound_input_types = input_types.iter().any(|&t| ty::type_is_skolemized(t));
|
let unbound_input_types = input_types.iter().any(|&t| ty::type_is_fresh(t));
|
||||||
if
|
if
|
||||||
unbound_input_types &&
|
unbound_input_types &&
|
||||||
(self.intercrate ||
|
(self.intercrate ||
|
||||||
stack.iter().skip(1).any(
|
stack.iter().skip(1).any(
|
||||||
|prev| stack.skol_trait_ref.value.def_id == prev.skol_trait_ref.value.def_id))
|
|prev| stack.fresh_trait_ref.value.def_id == prev.fresh_trait_ref.value.def_id))
|
||||||
{
|
{
|
||||||
debug!("evaluate_stack({}) --> unbound argument, recursion --> ambiguous",
|
debug!("evaluate_stack({}) --> unbound argument, recursion --> ambiguous",
|
||||||
stack.skol_trait_ref.repr(self.tcx()));
|
stack.fresh_trait_ref.repr(self.tcx()));
|
||||||
return EvaluatedToAmbig;
|
return EvaluatedToAmbig;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -373,19 +373,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
// `Option<Box<List<T>>>` is `Send` if `Box<List<T>>` is
|
// `Option<Box<List<T>>>` is `Send` if `Box<List<T>>` is
|
||||||
// `Send`.
|
// `Send`.
|
||||||
//
|
//
|
||||||
// Note that we do this comparison using the `skol_trait_ref`
|
// Note that we do this comparison using the `fresh_trait_ref`
|
||||||
// fields. Because these have all been skolemized using
|
// fields. Because these have all been skolemized using
|
||||||
// `self.skolemizer`, we can be sure that (a) this will not
|
// `self.freshener`, we can be sure that (a) this will not
|
||||||
// affect the inferencer state and (b) that if we see two
|
// affect the inferencer state and (b) that if we see two
|
||||||
// skolemized types with the same index, they refer to the
|
// skolemized types with the same index, they refer to the
|
||||||
// same unbound type variable.
|
// same unbound type variable.
|
||||||
if
|
if
|
||||||
stack.iter()
|
stack.iter()
|
||||||
.skip(1) // skip top-most frame
|
.skip(1) // skip top-most frame
|
||||||
.any(|prev| stack.skol_trait_ref == prev.skol_trait_ref)
|
.any(|prev| stack.fresh_trait_ref == prev.fresh_trait_ref)
|
||||||
{
|
{
|
||||||
debug!("evaluate_stack({}) --> recursive",
|
debug!("evaluate_stack({}) --> recursive",
|
||||||
stack.skol_trait_ref.repr(self.tcx()));
|
stack.fresh_trait_ref.repr(self.tcx()));
|
||||||
return EvaluatedToOk;
|
return EvaluatedToOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -445,20 +445,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check the cache. Note that we skolemize the trait-ref
|
// Check the cache. Note that we skolemize the trait-ref
|
||||||
// separately rather than using `stack.skol_trait_ref` -- this
|
// separately rather than using `stack.fresh_trait_ref` -- this
|
||||||
// is because we want the unbound variables to be replaced
|
// is because we want the unbound variables to be replaced
|
||||||
// with fresh skolemized types starting from index 0.
|
// with fresh skolemized types starting from index 0.
|
||||||
let cache_skol_trait_ref =
|
let cache_fresh_trait_ref =
|
||||||
self.infcx.skolemize(stack.obligation.trait_ref.clone());
|
self.infcx.freshen(stack.obligation.trait_ref.clone());
|
||||||
debug!("candidate_from_obligation(cache_skol_trait_ref={}, obligation={})",
|
debug!("candidate_from_obligation(cache_fresh_trait_ref={}, obligation={})",
|
||||||
cache_skol_trait_ref.repr(self.tcx()),
|
cache_fresh_trait_ref.repr(self.tcx()),
|
||||||
stack.repr(self.tcx()));
|
stack.repr(self.tcx()));
|
||||||
assert!(!stack.obligation.trait_ref.has_escaping_regions());
|
assert!(!stack.obligation.trait_ref.has_escaping_regions());
|
||||||
|
|
||||||
match self.check_candidate_cache(cache_skol_trait_ref.clone()) {
|
match self.check_candidate_cache(cache_fresh_trait_ref.clone()) {
|
||||||
Some(c) => {
|
Some(c) => {
|
||||||
debug!("CACHE HIT: cache_skol_trait_ref={}, candidate={}",
|
debug!("CACHE HIT: cache_fresh_trait_ref={}, candidate={}",
|
||||||
cache_skol_trait_ref.repr(self.tcx()),
|
cache_fresh_trait_ref.repr(self.tcx()),
|
||||||
c.repr(self.tcx()));
|
c.repr(self.tcx()));
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
@ -467,9 +467,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
|
|
||||||
// If no match, compute result and insert into cache.
|
// If no match, compute result and insert into cache.
|
||||||
let candidate = self.candidate_from_obligation_no_cache(stack);
|
let candidate = self.candidate_from_obligation_no_cache(stack);
|
||||||
debug!("CACHE MISS: cache_skol_trait_ref={}, candidate={}",
|
debug!("CACHE MISS: cache_fresh_trait_ref={}, candidate={}",
|
||||||
cache_skol_trait_ref.repr(self.tcx()), candidate.repr(self.tcx()));
|
cache_fresh_trait_ref.repr(self.tcx()), candidate.repr(self.tcx()));
|
||||||
self.insert_candidate_cache(cache_skol_trait_ref, candidate.clone());
|
self.insert_candidate_cache(cache_fresh_trait_ref, candidate.clone());
|
||||||
candidate
|
candidate
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -569,7 +569,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn pick_candidate_cache(&self,
|
fn pick_candidate_cache(&self,
|
||||||
cache_skol_trait_ref: &Rc<ty::PolyTraitRef<'tcx>>)
|
cache_fresh_trait_ref: &Rc<ty::PolyTraitRef<'tcx>>)
|
||||||
-> &SelectionCache<'tcx>
|
-> &SelectionCache<'tcx>
|
||||||
{
|
{
|
||||||
// High-level idea: we have to decide whether to consult the
|
// High-level idea: we have to decide whether to consult the
|
||||||
@ -591,7 +591,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
// If the trait refers to any parameters in scope, then use
|
// If the trait refers to any parameters in scope, then use
|
||||||
// the cache of the param-environment.
|
// the cache of the param-environment.
|
||||||
if
|
if
|
||||||
cache_skol_trait_ref.value.input_types().iter().any(
|
cache_fresh_trait_ref.value.input_types().iter().any(
|
||||||
|&t| ty::type_has_self(t) || ty::type_has_params(t))
|
|&t| ty::type_has_self(t) || ty::type_has_params(t))
|
||||||
{
|
{
|
||||||
return &self.param_env.selection_cache;
|
return &self.param_env.selection_cache;
|
||||||
@ -604,7 +604,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
// See the discussion in doc.rs for more details.
|
// See the discussion in doc.rs for more details.
|
||||||
if
|
if
|
||||||
!self.param_env.caller_bounds.is_empty() &&
|
!self.param_env.caller_bounds.is_empty() &&
|
||||||
cache_skol_trait_ref.value.input_types().iter().any(
|
cache_fresh_trait_ref.value.input_types().iter().any(
|
||||||
|&t| ty::type_has_ty_infer(t))
|
|&t| ty::type_has_ty_infer(t))
|
||||||
{
|
{
|
||||||
return &self.param_env.selection_cache;
|
return &self.param_env.selection_cache;
|
||||||
@ -615,21 +615,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn check_candidate_cache(&mut self,
|
fn check_candidate_cache(&mut self,
|
||||||
cache_skol_trait_ref: Rc<ty::PolyTraitRef<'tcx>>)
|
cache_fresh_trait_ref: Rc<ty::PolyTraitRef<'tcx>>)
|
||||||
-> Option<SelectionResult<'tcx, Candidate<'tcx>>>
|
-> Option<SelectionResult<'tcx, Candidate<'tcx>>>
|
||||||
{
|
{
|
||||||
let cache = self.pick_candidate_cache(&cache_skol_trait_ref);
|
let cache = self.pick_candidate_cache(&cache_fresh_trait_ref);
|
||||||
let hashmap = cache.hashmap.borrow();
|
let hashmap = cache.hashmap.borrow();
|
||||||
hashmap.get(&cache_skol_trait_ref).map(|c| (*c).clone())
|
hashmap.get(&cache_fresh_trait_ref).map(|c| (*c).clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_candidate_cache(&mut self,
|
fn insert_candidate_cache(&mut self,
|
||||||
cache_skol_trait_ref: Rc<ty::PolyTraitRef<'tcx>>,
|
cache_fresh_trait_ref: Rc<ty::PolyTraitRef<'tcx>>,
|
||||||
candidate: SelectionResult<'tcx, Candidate<'tcx>>)
|
candidate: SelectionResult<'tcx, Candidate<'tcx>>)
|
||||||
{
|
{
|
||||||
let cache = self.pick_candidate_cache(&cache_skol_trait_ref);
|
let cache = self.pick_candidate_cache(&cache_fresh_trait_ref);
|
||||||
let mut hashmap = cache.hashmap.borrow_mut();
|
let mut hashmap = cache.hashmap.borrow_mut();
|
||||||
hashmap.insert(cache_skol_trait_ref, candidate);
|
hashmap.insert(cache_fresh_trait_ref, candidate);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assemble_candidates<'o>(&mut self,
|
fn assemble_candidates<'o>(&mut self,
|
||||||
@ -1269,8 +1269,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ty::ty_open(_) |
|
ty::ty_open(_) |
|
||||||
ty::ty_infer(ty::SkolemizedTy(_)) |
|
ty::ty_infer(ty::FreshTy(_)) |
|
||||||
ty::ty_infer(ty::SkolemizedIntTy(_)) => {
|
ty::ty_infer(ty::FreshIntTy(_)) => {
|
||||||
self.tcx().sess.bug(
|
self.tcx().sess.bug(
|
||||||
format!(
|
format!(
|
||||||
"asked to assemble builtin bounds of unexpected type: {}",
|
"asked to assemble builtin bounds of unexpected type: {}",
|
||||||
@ -1831,11 +1831,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
obligation: &'o TraitObligation<'tcx>)
|
obligation: &'o TraitObligation<'tcx>)
|
||||||
-> TraitObligationStack<'o, 'tcx>
|
-> TraitObligationStack<'o, 'tcx>
|
||||||
{
|
{
|
||||||
let skol_trait_ref = obligation.trait_ref.fold_with(&mut self.skolemizer);
|
let fresh_trait_ref = obligation.trait_ref.fold_with(&mut self.freshener);
|
||||||
|
|
||||||
TraitObligationStack {
|
TraitObligationStack {
|
||||||
obligation: obligation,
|
obligation: obligation,
|
||||||
skol_trait_ref: skol_trait_ref,
|
fresh_trait_ref: fresh_trait_ref,
|
||||||
previous: previous_stack.map(|p| p), // FIXME variance
|
previous: previous_stack.map(|p| p), // FIXME variance
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1538,12 +1538,16 @@ pub enum InferTy {
|
|||||||
TyVar(TyVid),
|
TyVar(TyVid),
|
||||||
IntVar(IntVid),
|
IntVar(IntVid),
|
||||||
FloatVar(FloatVid),
|
FloatVar(FloatVid),
|
||||||
SkolemizedTy(uint),
|
|
||||||
|
/// A `FreshTy` is one that is generated as a replacement for an
|
||||||
|
/// unbound type variable. This is convenient for caching etc. See
|
||||||
|
/// `middle::infer::freshen` for more details.
|
||||||
|
FreshTy(uint),
|
||||||
|
|
||||||
// FIXME -- once integral fallback is impl'd, we should remove
|
// FIXME -- once integral fallback is impl'd, we should remove
|
||||||
// this type. It's only needed to prevent spurious errors for
|
// this type. It's only needed to prevent spurious errors for
|
||||||
// integers whose type winds up never being constrained.
|
// integers whose type winds up never being constrained.
|
||||||
SkolemizedIntTy(uint),
|
FreshIntTy(uint),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Copy for InferTy {}
|
impl Copy for InferTy {}
|
||||||
@ -1610,8 +1614,8 @@ impl fmt::Show for InferTy {
|
|||||||
TyVar(ref v) => v.fmt(f),
|
TyVar(ref v) => v.fmt(f),
|
||||||
IntVar(ref v) => v.fmt(f),
|
IntVar(ref v) => v.fmt(f),
|
||||||
FloatVar(ref v) => v.fmt(f),
|
FloatVar(ref v) => v.fmt(f),
|
||||||
SkolemizedTy(v) => write!(f, "SkolemizedTy({})", v),
|
FreshTy(v) => write!(f, "FreshTy({})", v),
|
||||||
SkolemizedIntTy(v) => write!(f, "SkolemizedIntTy({})", v),
|
FreshIntTy(v) => write!(f, "FreshIntTy({})", v),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2986,7 +2990,7 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scalar and unique types are sendable, and durable
|
// Scalar and unique types are sendable, and durable
|
||||||
ty_infer(ty::SkolemizedIntTy(_)) |
|
ty_infer(ty::FreshIntTy(_)) |
|
||||||
ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
|
ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
|
||||||
ty_bare_fn(_) | ty::ty_char => {
|
ty_bare_fn(_) | ty::ty_char => {
|
||||||
TC::None
|
TC::None
|
||||||
@ -3592,10 +3596,10 @@ pub fn type_is_integral(ty: Ty) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_is_skolemized(ty: Ty) -> bool {
|
pub fn type_is_fresh(ty: Ty) -> bool {
|
||||||
match ty.sty {
|
match ty.sty {
|
||||||
ty_infer(SkolemizedTy(_)) => true,
|
ty_infer(FreshTy(_)) => true,
|
||||||
ty_infer(SkolemizedIntTy(_)) => true,
|
ty_infer(FreshIntTy(_)) => true,
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4428,8 +4432,8 @@ pub fn ty_sort_string<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> String {
|
|||||||
ty_infer(TyVar(_)) => "inferred type".to_string(),
|
ty_infer(TyVar(_)) => "inferred type".to_string(),
|
||||||
ty_infer(IntVar(_)) => "integral variable".to_string(),
|
ty_infer(IntVar(_)) => "integral variable".to_string(),
|
||||||
ty_infer(FloatVar(_)) => "floating-point variable".to_string(),
|
ty_infer(FloatVar(_)) => "floating-point variable".to_string(),
|
||||||
ty_infer(SkolemizedTy(_)) => "skolemized type".to_string(),
|
ty_infer(FreshTy(_)) => "skolemized type".to_string(),
|
||||||
ty_infer(SkolemizedIntTy(_)) => "skolemized integral type".to_string(),
|
ty_infer(FreshIntTy(_)) => "skolemized integral type".to_string(),
|
||||||
ty_param(ref p) => {
|
ty_param(ref p) => {
|
||||||
if p.space == subst::SelfSpace {
|
if p.space == subst::SelfSpace {
|
||||||
"Self".to_string()
|
"Self".to_string()
|
||||||
@ -5594,7 +5598,7 @@ pub fn object_region_bounds<'tcx>(tcx: &ctxt<'tcx>,
|
|||||||
// Since we don't actually *know* the self type for an object,
|
// Since we don't actually *know* the self type for an object,
|
||||||
// this "open(err)" serves as a kind of dummy standin -- basically
|
// this "open(err)" serves as a kind of dummy standin -- basically
|
||||||
// a skolemized type.
|
// a skolemized type.
|
||||||
let open_ty = ty::mk_infer(tcx, SkolemizedTy(0));
|
let open_ty = ty::mk_infer(tcx, FreshTy(0));
|
||||||
|
|
||||||
let opt_trait_ref = opt_principal.map_or(Vec::new(), |principal| {
|
let opt_trait_ref = opt_principal.map_or(Vec::new(), |principal| {
|
||||||
let substs = principal.substs().with_self_ty(open_ty);
|
let substs = principal.substs().with_self_ty(open_ty);
|
||||||
|
@ -374,8 +374,8 @@ pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String {
|
|||||||
ty::IntVar(ref vid) if print_var_ids => vid.repr(cx),
|
ty::IntVar(ref vid) if print_var_ids => vid.repr(cx),
|
||||||
ty::FloatVar(ref vid) if print_var_ids => vid.repr(cx),
|
ty::FloatVar(ref vid) if print_var_ids => vid.repr(cx),
|
||||||
ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => format!("_"),
|
ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => format!("_"),
|
||||||
ty::SkolemizedTy(v) => format!("SkolemizedTy({})", v),
|
ty::FreshTy(v) => format!("FreshTy({})", v),
|
||||||
ty::SkolemizedIntTy(v) => format!("SkolemizedIntTy({})", v)
|
ty::FreshIntTy(v) => format!("FreshIntTy({})", v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -848,12 +848,12 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use skolemize to simultaneously replace all type variables with
|
// Use freshen to simultaneously replace all type variables with
|
||||||
// their bindings and replace all regions with 'static. This is
|
// their bindings and replace all regions with 'static. This is
|
||||||
// sort of overkill because we do not expect there to be any
|
// sort of overkill because we do not expect there to be any
|
||||||
// unbound type variables, hence no skolemized types should ever
|
// unbound type variables, hence no `TyFresh` types should ever be
|
||||||
// be inserted.
|
// inserted.
|
||||||
let vtable = vtable.fold_with(&mut infcx.skolemizer());
|
let vtable = vtable.fold_with(&mut infcx.freshener());
|
||||||
|
|
||||||
info!("Cache miss: {}", trait_ref.repr(ccx.tcx()));
|
info!("Cache miss: {}", trait_ref.repr(ccx.tcx()));
|
||||||
ccx.trait_cache().borrow_mut().insert(trait_ref,
|
ccx.trait_cache().borrow_mut().insert(trait_ref,
|
||||||
|
Loading…
Reference in New Issue
Block a user