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:
Niko Matsakis 2014-12-12 06:13:42 -05:00
parent 3cf0fbeee9
commit 416e62924e
6 changed files with 104 additions and 100 deletions

View File

@ -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 |

View File

@ -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>)

View File

@ -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
} }
} }

View File

@ -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);

View File

@ -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)
} }
} }

View File

@ -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,