Skip to content

Commit

Permalink
Remove defaults table and attach defaults directly to tyvars
Browse files Browse the repository at this point in the history
  • Loading branch information
jroesch authored and Jared Roesch committed Jul 26, 2015
1 parent bbdca2c commit 49eb2c6
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 41 deletions.
54 changes: 40 additions & 14 deletions src/librustc/middle/infer/mod.rs
Expand Up @@ -95,9 +95,6 @@ pub struct InferCtxt<'a, 'tcx: 'a> {
normalize: bool,

err_count_on_creation: usize,

// Default Type Parameter fallbacks
pub defaults: RefCell<FnvHashMap<Ty<'tcx>, Ty<'tcx>>>,
}

/// A map returned by `skolemize_late_bound_regions()` indicating the skolemized
Expand Down Expand Up @@ -353,8 +350,7 @@ pub fn new_infer_ctxt<'a, 'tcx>(tcx: &'a ty::ctxt<'tcx>,
parameter_environment: param_env.unwrap_or(tcx.empty_parameter_environment()),
fulfillment_cx: RefCell::new(traits::FulfillmentContext::new(errors_will_be_reported)),
normalize: false,
err_count_on_creation: tcx.sess.err_count(),
defaults: RefCell::new(FnvHashMap()),
err_count_on_creation: tcx.sess.err_count()
}
}

Expand Down Expand Up @@ -657,27 +653,44 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
}

/// Returns a type variable's default fallback if any exists. A default
/// must be attached to the variable when created, if it is created
/// without a default, this will return None.
///
/// See `new_ty_var_with_default` to create a type variable with a default.
/// See `type_variable::Default` for details about what a default entails.
pub fn default(&self, ty: Ty<'tcx>) -> Option<type_variable::Default<'tcx>> {
match ty.sty {
ty::TyInfer(ty::TyVar(vid)) => self.type_variables.borrow().default(vid),
_ => None
}
}

pub fn unsolved_variables(&self) -> Vec<ty::Ty<'tcx>> {
let mut variables = Vec::new();

let unbound_ty_vars = self.type_variables
.borrow()
.unsolved_variables()
.into_iter().map(|t| self.tcx.mk_var(t));
.into_iter()
.map(|t| self.tcx.mk_var(t));

let unbound_int_vars = self.int_unification_table
.borrow_mut()
.unsolved_variables()
.into_iter().map(|v| self.tcx.mk_int_var(v));
.into_iter()
.map(|v| self.tcx.mk_int_var(v));

let unbound_float_vars = self.float_unification_table
.borrow_mut()
.unsolved_variables()
.into_iter().map(|v| self.tcx.mk_float_var(v));
.into_iter()
.map(|v| self.tcx.mk_float_var(v));

variables.extend(unbound_ty_vars);
variables.extend(unbound_int_vars);
variables.extend(unbound_float_vars);

return variables;
}

Expand Down Expand Up @@ -984,13 +997,22 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn next_ty_var_id(&self, diverging: bool) -> TyVid {
self.type_variables
.borrow_mut()
.new_var(diverging)
.new_var(diverging, None)
}

pub fn next_ty_var(&self) -> Ty<'tcx> {
self.tcx.mk_var(self.next_ty_var_id(false))
}

pub fn next_ty_var_with_default(&self,
default: Option<type_variable::Default<'tcx>>) -> Ty<'tcx> {
let ty_var_id = self.type_variables
.borrow_mut()
.new_var(false, default);

self.tcx.mk_var(ty_var_id)
}

pub fn next_diverging_ty_var(&self) -> Ty<'tcx> {
self.tcx.mk_var(self.next_ty_var_id(true))
}
Expand Down Expand Up @@ -1027,14 +1049,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn type_vars_for_defs(&self,
defs: &[ty::TypeParameterDef<'tcx>])
-> Vec<ty::Ty<'tcx>> {
let mut substs = Substs::empty();
let mut vars = Vec::with_capacity(defs.len());

for def in defs.iter() {
let ty_var = self.next_ty_var();
match def.default {
None => {},
Some(default) => { self.defaults.borrow_mut().insert(ty_var, default); }
}
let default = def.default.map(|default| {
type_variable::Default {
ty: default
}
});
//.subst(self.tcx, &substs)
let ty_var = self.next_ty_var_with_default(default);
substs.types.push(subst::ParamSpace::SelfSpace, ty_var);
vars.push(ty_var)
}

Expand Down
45 changes: 33 additions & 12 deletions src/librustc/middle/infer/type_variable.rs
Expand Up @@ -30,7 +30,17 @@ struct TypeVariableData<'tcx> {

enum TypeVariableValue<'tcx> {
Known(Ty<'tcx>),
Bounded(Vec<Relation>),
Bounded {
relations: Vec<Relation>,
default: Option<Default<'tcx>>
}
}

// We will use this to store the required information to recapitulate what happened when
// an error occurs.
#[derive(Clone)]
pub struct Default<'tcx> {
pub ty: Ty<'tcx>
}

pub struct Snapshot {
Expand Down Expand Up @@ -72,6 +82,13 @@ impl<'tcx> TypeVariableTable<'tcx> {
relations(self.values.get_mut(a.index as usize))
}

pub fn default(&self, vid: ty::TyVid) -> Option<Default<'tcx>> {
match &self.values.get(vid.index as usize).value {
&Known(_) => None,
&Bounded { ref default, .. } => default.clone()
}
}

pub fn var_diverges<'a>(&'a self, vid: ty::TyVid) -> bool {
self.values.get(vid.index as usize).diverging
}
Expand Down Expand Up @@ -102,7 +119,7 @@ impl<'tcx> TypeVariableTable<'tcx> {
};

let relations = match old_value {
Bounded(b) => b,
Bounded { relations, .. } => relations,
Known(_) => panic!("Asked to instantiate variable that is \
already instantiated")
};
Expand All @@ -114,17 +131,19 @@ impl<'tcx> TypeVariableTable<'tcx> {
self.values.record(SpecifyVar(vid, relations));
}

pub fn new_var(&mut self, diverging: bool) -> ty::TyVid {
pub fn new_var(&mut self,
diverging: bool,
default: Option<Default<'tcx>>) -> ty::TyVid {
let index = self.values.push(TypeVariableData {
value: Bounded(vec![]),
value: Bounded { relations: vec![], default: default },
diverging: diverging
});
ty::TyVid { index: index as u32 }
}

pub fn probe(&self, vid: ty::TyVid) -> Option<Ty<'tcx>> {
match self.values.get(vid.index as usize).value {
Bounded(..) => None,
Bounded { .. } => None,
Known(t) => Some(t)
}
}
Expand Down Expand Up @@ -197,12 +216,14 @@ impl<'tcx> TypeVariableTable<'tcx> {
}

pub fn unsolved_variables(&self) -> Vec<ty::TyVid> {
self.values.iter().enumerate().filter_map(|(i, value)|
match &value.value {
self.values
.iter()
.enumerate()
.filter_map(|(i, value)| match &value.value {
&TypeVariableValue::Known(_) => None,
&TypeVariableValue::Bounded(_) => Some(ty::TyVid { index: i as u32 })
}
).collect()
&TypeVariableValue::Bounded { .. } => Some(ty::TyVid { index: i as u32 })
})
.collect()
}
}

Expand All @@ -213,7 +234,7 @@ impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> {
fn reverse(values: &mut Vec<TypeVariableData<'tcx>>, action: UndoEntry) {
match action {
SpecifyVar(vid, relations) => {
values[vid.index as usize].value = Bounded(relations);
values[vid.index as usize].value = Bounded { relations: relations, default: None };
}

Relate(a, b) => {
Expand All @@ -227,6 +248,6 @@ impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> {
fn relations<'a>(v: &'a mut TypeVariableData) -> &'a mut Vec<Relation> {
match v.value {
Known(_) => panic!("var_sub_var: variable is known"),
Bounded(ref mut relations) => relations
Bounded { ref mut relations, .. } => relations
}
}
25 changes: 10 additions & 15 deletions src/librustc_typeck/check/mod.rs
Expand Up @@ -87,6 +87,7 @@ use fmt_macros::{Parser, Piece, Position};
use middle::astconv_util::{check_path_args, NO_TPS, NO_REGIONS};
use middle::def;
use middle::infer;
use middle::infer::type_variable;
use middle::pat_util::{self, pat_id_map};
use middle::privacy::{AllPublic, LastMod};
use middle::region::{self, CodeExtent};
Expand Down Expand Up @@ -1139,12 +1140,8 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
}

fn ty_infer(&self, default: Option<Ty<'tcx>>, _span: Span) -> Ty<'tcx> {
let ty_var = self.infcx().next_ty_var();
match default {
Some(default) => { self.infcx().defaults.borrow_mut().insert(ty_var, default); }
None => {}
}
ty_var
let default = default.map(|t| type_variable::Default { ty: t });
self.infcx().next_ty_var_with_default(default)
}

fn projected_ty_from_poly_trait_ref(&self,
Expand Down Expand Up @@ -1697,7 +1694,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn select_all_obligations_and_apply_defaults(&self) {
use middle::ty::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat, Neither};

debug!("select_all_obligations_and_apply_defaults: defaults={:?}", self.infcx().defaults);
// debug!("select_all_obligations_and_apply_defaults: defaults={:?}", self.infcx().defaults);

for _ in (0..self.tcx().sess.recursion_limit.get()) {
self.select_obligations_where_possible();
Expand Down Expand Up @@ -1725,11 +1722,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

// Collect the set of variables that need fallback applied
for ty in &unsolved_variables {
if self.inh.infcx.defaults.borrow().contains_key(ty) {
if let Some(_) = self.inh.infcx.default(ty) {
let resolved = self.infcx().resolve_type_vars_if_possible(ty);

debug!("select_all_obligations_and_apply_defaults: ty: {:?} with default: {:?}",
ty, self.inh.infcx.defaults.borrow().get(ty));
// debug!("select_all_obligations_and_apply_defaults: ty: {:?} with default: {:?}",
// ty, self.inh.infcx.defaults.borrow().get(ty));

match resolved.sty {
ty::TyInfer(ty::TyVar(_)) => {
Expand All @@ -1754,7 +1751,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

// Go through the unbound variables and unify them with the proper fallbacks
for ty in &unbound_tyvars {
// let resolved = self.infcx().resolve_type_vars_if_possible(ty);
if self.infcx().type_var_diverges(ty) {
demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().mk_nil());
} else {
Expand All @@ -1766,17 +1762,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.f64)
}
Neither => {
let default_map = self.inh.infcx.defaults.borrow();
if let Some(default) = default_map.get(ty) {
if let Some(default) = self.inh.infcx.default(ty) {
match infer::mk_eqty(self.infcx(), false,
infer::Misc(codemap::DUMMY_SP),
ty, default) {
ty, default.ty) {
Ok(()) => { /* ok */ }
Err(_) => {
self.infcx().report_conflicting_default_types(
codemap::DUMMY_SP,
ty,
default)
default.ty)
}
}
}
Expand Down
@@ -0,0 +1,23 @@
use std::marker::PhantomData;

trait Id {
type This;
}

impl<A> Id for A {
type This = A;
}

struct Foo<X: Default = usize, Y = <X as Id>::This> {
data: PhantomData<(X, Y)>
}

impl<X: Default, Y> Foo<X, Y> {
fn new() -> Foo<X, Y> {
Foo { data: PhantomData }
}
}

fn main() {
let foo = Foo::new();
}
@@ -0,0 +1,7 @@
use std::marker::PhantomData;

struct Foo<T,U=T> { data: PhantomData<(T, U)> }

fn main() {
let foo = Foo { data: PhantomData };
}
30 changes: 30 additions & 0 deletions src/test/run-pass/default_type_parameter_struct_and_type_alias.rs
@@ -0,0 +1,30 @@
use std::marker::PhantomData;

trait TypeEq<A> {}
impl<A> TypeEq<A> for A {}

struct DeterministicHasher;
struct RandomHasher;


struct MyHashMap<K, V, H=DeterministicHasher> {
data: PhantomData<(K, V, H)>
}

impl<K, V, H> MyHashMap<K, V, H> {
fn new() -> MyHashMap<K, V, H> {
MyHashMap { data: PhantomData }
}
}

mod mystd {
use super::{MyHashMap, RandomHasher};
pub type HashMap<K, V, H=RandomHasher> = MyHashMap<K, V, H>;
}

fn try_me<H>(hash_map: mystd::HashMap<i32, i32, H>) {}

fn main() {
let hash_map = mystd::HashMap::new();
try_me(hash_map);
}

0 comments on commit 49eb2c6

Please sign in to comment.