Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Default Type Parameter Fallback: Revival #46206

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
7e8509f
Change fallback priorties to prefer user defaults
jroesch Aug 11, 2015
f20a4d8
Refactor default type parameter fallback
jroesch Aug 19, 2015
9b07e1b
Address nits and add assertation
jroesch Aug 19, 2015
b29ba68
Fix tidy
jroesch Aug 19, 2015
233397e
Ensure defaults are normalized after application
jroesch Aug 25, 2015
bff6d6b
Address nits and fix tidy ... again
jroesch Sep 3, 2015
28609d5
Rebase fixes
jroesch Sep 16, 2015
978bbca
wip
nikomatsakis Mar 10, 2016
f279dd6
Manually merge moved files
leoyvens Nov 20, 2017
d4654b1
Fix rebase of default-type-param-fallback branch
leoyvens Nov 20, 2017
ad30796
trying stuff out
leoyvens Nov 20, 2017
e1ef324
downgrade verbose logs from `debug!` to `trace!`
leoyvens Nov 21, 2017
b9e9f0f
Combine propagates defaults.
leoyvens Nov 21, 2017
ce861ae
Conservative default type param fallback.
leoyvens Nov 22, 2017
8b44ca5
Fix regression on diverging fallback, remove old user fallback implem…
leoyvens Nov 22, 2017
9239233
Give priority to defaults in fns and impls over defaults in types.
leoyvens Nov 22, 2017
9a98d23
Feature gate default type parameter fallback.
leoyvens Nov 22, 2017
ced2600
Remove default data from TypeVariableValue::Bounded.
leoyvens Nov 22, 2017
f27f976
Fix rebase conflict
leoyvens Nov 22, 2017
bdda07b
Set OriginOfTyParam for methods.
leoyvens Nov 23, 2017
3857826
Run pass tests.
leoyvens Nov 23, 2017
5362bbe
Tests for default fallback: ui tests, run fail test, more run pass te…
leoyvens Nov 23, 2017
0bd87ef
Adjust fallback algorithm.
leoyvens Nov 25, 2017
babfa76
Get normalization of dependent defaults right.
leoyvens Nov 26, 2017
14a9420
Fallback: Don't skip conflicting defaults.
leoyvens Nov 26, 2017
423de71
Fallback: Stop relying on sty equality, use rollbacks.
leoyvens Nov 27, 2017
91da0cc
Refactor tests.
leoyvens Nov 27, 2017
da4dcad
Fallback: Tests to clarify defaults for `Self` in trait impls.
leoyvens Nov 28, 2017
90a42a8
Test interaction with specialization.
leoyvens Nov 28, 2017
d84f3ed
Test that trait definition owns the default, not the impl.
leoyvens Nov 29, 2017
4753319
Test associated type as default, test that elided params are not infe…
leoyvens Nov 29, 2017
bad548a
Fix "associated type not found" when using associated type in default.
leoyvens Nov 29, 2017
5c28224
Propagate defaults in fudge
leoyvens Nov 30, 2017
973f782
Use fallbacks to avoid "the type of this value must be known in this …
leoyvens Nov 30, 2017
06e7456
Fix fallback for `_` placeholders.
leoyvens Nov 30, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/librustc/hir/map/definitions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,10 +279,10 @@ impl DefPath {
let mut data = vec![];
let mut index = Some(start_index);
loop {
debug!("DefPath::make: krate={:?} index={:?}", krate, index);
trace!("DefPath::make: krate={:?} index={:?}", krate, index);
let p = index.unwrap();
let key = get_key(p);
debug!("DefPath::make: key={:?}", key);
trace!("DefPath::make: key={:?}", key);
match key.disambiguated_data.data {
DefPathData::CrateRoot => {
assert!(key.parent.is_none());
Expand Down
8 changes: 8 additions & 0 deletions src/librustc/ich/impls_ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -462,11 +462,19 @@ for ty::RegionParameterDef {
}
}

impl_stable_hash_for!(enum ty::OriginOfTyParam {
Fn,
Impl,
TyDef,
Other
});

impl_stable_hash_for!(struct ty::TypeParameterDef {
name,
def_id,
index,
has_default,
origin,
object_lifetime_default,
pure_wrt_drop,
synthetic
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/infer/combine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,8 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, '
}

let origin = variables.origin(vid);
let new_var_id = variables.new_var(false, origin, None);
let default = variables.default(vid).as_user().clone();
let new_var_id = variables.new_var(false, origin, default);
let u = self.tcx().mk_var(new_var_id);
debug!("generalize: replacing original vid={:?} with new={:?}",
vid, u);
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/infer/error_reporting/need_type_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
fn extract_type_name(&self, ty: &'a Ty<'tcx>) -> String {
if let ty::TyInfer(ty::TyVar(ty_vid)) = (*ty).sty {
let ty_vars = self.type_variables.borrow();
if let TypeVariableOrigin::TypeParameterDefinition(_, name) =
*ty_vars.var_origin(ty_vid) {
if let TypeVariableOrigin::TypeParameterDefinition(_, name, _) =
ty_vars.var_origin(ty_vid) {
name.to_string()
} else {
ty.to_string()
Expand Down
6 changes: 3 additions & 3 deletions src/librustc/infer/fudge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {

pub struct RegionFudger<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
type_variables: &'a TypeVariableMap,
type_variables: &'a TypeVariableMap<'tcx>,
region_vars: &'a Vec<ty::RegionVid>,
origin: &'a RegionVariableOrigin,
}
Expand All @@ -135,11 +135,11 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFudger<'a, 'gcx, 'tcx> {
ty
}

Some(&origin) => {
Some(&(origin, ref default)) => {
// This variable was created during the
// fudging. Recreate it with a fresh variable
// here.
self.infcx.next_ty_var(origin)
self.infcx.next_ty_var_with_default(default.clone(), origin)
}
}
}
Expand Down
55 changes: 26 additions & 29 deletions src/librustc/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -695,23 +695,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, '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.
///
/// This code does not apply to integral or floating point variables,
/// only to use declared defaults.
///
/// 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<'tcx>> {
// Returns a vector containing all type variables that have an applicable default,
// along with their defaults.
//
// NB: You must be careful to only apply defaults once, if a variable is unififed
// it many no longer be unsolved and apply a second default will mostly likely
// result in a type error.
pub fn candidates_for_fallback(&self) -> Vec<Ty<'tcx>> {
let mut variables = Vec::new();

let unbound_ty_vars = self.type_variables
Expand All @@ -737,7 +727,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
variables.extend(unbound_float_vars);

return variables;
}
}

fn combine_fields(&'a self, trace: TypeTrace<'tcx>, param_env: ty::ParamEnv<'tcx>)
-> CombineFields<'a, 'gcx, 'tcx> {
Expand Down Expand Up @@ -1032,6 +1022,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
.new_var(diverging, origin, None)
}

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

self.tcx.mk_var(ty_var_id)
}

pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
self.tcx.mk_var(self.next_ty_var_id(false, origin))
}
Expand Down Expand Up @@ -1093,7 +1093,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
-> Ty<'tcx> {
let default = if def.has_default {
let default = self.tcx.type_of(def.def_id);
Some(type_variable::Default {
Some(type_variable::UserDefault {
ty: default.subst_spanned(self.tcx, substs, Some(span)),
origin_span: span,
def_id: def.def_id
Expand All @@ -1102,14 +1102,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
None
};

let origin = TypeVariableOrigin::TypeParameterDefinition(span,
def.name,
def.origin);

let ty_var_id = self.type_variables
.borrow_mut()
.new_var(false,
TypeVariableOrigin::TypeParameterDefinition(span, def.name),
default);

self.tcx.mk_var(ty_var_id)
self.tcx.mk_var(self.type_variables.borrow_mut().new_var(false, origin, default))
}

/// Given a set of generics defined on a type or impl, returns a substitution mapping each
Expand Down Expand Up @@ -1361,13 +1358,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
pub fn report_conflicting_default_types(&self,
span: Span,
body_id: ast::NodeId,
expected: type_variable::Default<'tcx>,
actual: type_variable::Default<'tcx>) {
expected: type_variable::UserDefault<'tcx>,
actual: type_variable::UserDefault<'tcx>) {
let trace = TypeTrace {
cause: ObligationCause::misc(span, body_id),
values: Types(ExpectedFound {
expected: expected.ty,
found: actual.ty
found: actual.ty,
})
};

Expand Down
95 changes: 60 additions & 35 deletions src/librustc/infer/type_variable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ pub enum TypeVariableOrigin {
MiscVariable(Span),
NormalizeProjectionType(Span),
TypeInference(Span),
TypeParameterDefinition(Span, ast::Name),
TypeParameterDefinition(Span, ast::Name, ty::OriginOfTyParam),

/// one of the upvars or closure kind parameters in a `ClosureSubsts`
/// (before it has been determined)
Expand All @@ -70,25 +70,44 @@ pub enum TypeVariableOrigin {
Generalized(ty::TyVid),
}

pub type TypeVariableMap = FxHashMap<ty::TyVid, TypeVariableOrigin>;
pub type TypeVariableMap<'tcx> = FxHashMap<ty::TyVid, (TypeVariableOrigin,
Option<UserDefault<'tcx>>)>;

struct TypeVariableData<'tcx> {
value: TypeVariableValue<'tcx>,
origin: TypeVariableOrigin,
diverging: bool
default: Default<'tcx>,
}

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

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum Default<'tcx> {
User(UserDefault<'tcx>),
Integer,
Float,
Diverging,
None,
}

impl<'tcx> Default<'tcx> {
pub fn as_user(&self) -> Option<UserDefault<'tcx>> {
match *self {
Default::User(ref user_default) => Some(user_default.clone()),
Default::None => None,
_ => bug!("Default exists but is not user"),
}
}
}

// We will use this to store the required information to recapitulate what happened when
// an error occurs.
// We will use this to store the required information to recapitulate
// what happened when an error occurs.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Default<'tcx> {
pub struct UserDefault<'tcx> {
/// The default type provided by the user
pub ty: Ty<'tcx>,
/// The span where the default was incurred
pub origin_span: Span,
Expand All @@ -102,9 +121,8 @@ pub struct Snapshot {
sub_snapshot: ut::Snapshot<ty::TyVid>,
}

struct Instantiate<'tcx> {
struct Instantiate {
vid: ty::TyVid,
default: Option<Default<'tcx>>,
}

struct Delegate<'tcx>(PhantomData<&'tcx ()>);
Expand All @@ -118,19 +136,19 @@ impl<'tcx> TypeVariableTable<'tcx> {
}
}

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 default(&self, vid: ty::TyVid) -> &Default<'tcx> {
&self.values.get(vid.index as usize).default
}

pub fn var_diverges<'a>(&'a self, vid: ty::TyVid) -> bool {
self.values.get(vid.index as usize).diverging
match self.values.get(vid.index as usize).default {
Default::Diverging => true,
_ => false,
}
}

pub fn var_origin(&self, vid: ty::TyVid) -> &TypeVariableOrigin {
&self.values.get(vid.index as usize).origin
pub fn var_origin(&self, vid: ty::TyVid) -> TypeVariableOrigin {
self.values.get(vid.index as usize).origin
}

/// Records that `a == b`, depending on `dir`.
Expand Down Expand Up @@ -165,8 +183,8 @@ impl<'tcx> TypeVariableTable<'tcx> {
};

match old_value {
TypeVariableValue::Bounded { default } => {
self.values.record(Instantiate { vid: vid, default: default });
TypeVariableValue::Bounded => {
self.values.record(Instantiate { vid: vid });
}
TypeVariableValue::Known(old_ty) => {
bug!("instantiating type variable `{:?}` twice: new-value = {:?}, old-value={:?}",
Expand All @@ -178,14 +196,22 @@ impl<'tcx> TypeVariableTable<'tcx> {
pub fn new_var(&mut self,
diverging: bool,
origin: TypeVariableOrigin,
default: Option<Default<'tcx>>,) -> ty::TyVid {
debug!("new_var(diverging={:?}, origin={:?})", diverging, origin);
default: Option<UserDefault<'tcx>>,) -> ty::TyVid {
debug!("new_var(diverging={:?}, origin={:?} default={:?})", diverging, origin, default);
self.eq_relations.new_key(());
self.sub_relations.new_key(());

let default = if diverging {
Default::Diverging
} else {
default.map(|u| Default::User(u))
.unwrap_or(Default::None)
};

let index = self.values.push(TypeVariableData {
value: Bounded { default: default },
value: Bounded,
origin,
diverging,
default,
});
let v = ty::TyVid { index: index as u32 };
debug!("new_var: diverging={:?} index={:?}", diverging, v);
Expand Down Expand Up @@ -235,7 +261,7 @@ impl<'tcx> TypeVariableTable<'tcx> {
pub fn probe_root(&mut self, vid: ty::TyVid) -> Option<Ty<'tcx>> {
debug_assert!(self.root_var(vid) == vid);
match self.values.get(vid.index as usize).value {
Bounded { .. } => None,
Bounded => None,
Known(t) => Some(t)
}
}
Expand Down Expand Up @@ -289,7 +315,7 @@ impl<'tcx> TypeVariableTable<'tcx> {
/// ty-variables created during the snapshot, and the values
/// `{V2}` are the root variables that they were unified with,
/// along with their origin.
pub fn types_created_since_snapshot(&mut self, s: &Snapshot) -> TypeVariableMap {
pub fn types_created_since_snapshot(&mut self, s: &Snapshot) -> TypeVariableMap<'tcx> {
let actions_since_snapshot = self.values.actions_since_snapshot(&s.snapshot);

actions_since_snapshot
Expand All @@ -300,7 +326,8 @@ impl<'tcx> TypeVariableTable<'tcx> {
})
.map(|vid| {
let origin = self.values.get(vid.index as usize).origin.clone();
(vid, origin)
let default = self.default(vid).clone().as_user();
(vid, (origin, default))
})
.collect()
}
Expand Down Expand Up @@ -331,12 +358,12 @@ impl<'tcx> TypeVariableTable<'tcx> {
debug!("NewElem({}) new_elem_threshold={}", index, new_elem_threshold);
}

sv::UndoLog::Other(Instantiate { vid, .. }) => {
sv::UndoLog::Other(Instantiate { vid }) => {
if vid.index < new_elem_threshold {
// quick check to see if this variable was
// created since the snapshot started or not.
let escaping_type = match self.values.get(vid.index as usize).value {
Bounded { .. } => bug!(),
Bounded => bug!(),
Known(ty) => ty,
};
escaping_types.push(escaping_type);
Expand Down Expand Up @@ -367,12 +394,10 @@ impl<'tcx> TypeVariableTable<'tcx> {

impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> {
type Value = TypeVariableData<'tcx>;
type Undo = Instantiate<'tcx>;
type Undo = Instantiate;

fn reverse(values: &mut Vec<TypeVariableData<'tcx>>, action: Instantiate<'tcx>) {
let Instantiate { vid, default } = action;
values[vid.index as usize].value = Bounded {
default,
};
fn reverse(values: &mut Vec<TypeVariableData<'tcx>>, action: Instantiate) {
let Instantiate { vid } = action;
values[vid.index as usize].value = Bounded;
}
}
6 changes: 4 additions & 2 deletions src/librustc/traits/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ use middle::const_val;
use std::fmt;
use syntax::ast;
use session::DiagnosticMessageId;
use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
use ty::{self, AdtKind, OriginOfTyParam, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
use ty::error::ExpectedFound;
use ty::fast_reject;
use ty::fold::TypeFolder;
Expand Down Expand Up @@ -1134,7 +1134,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
let infcx = self.infcx;
self.var_map.entry(ty).or_insert_with(||
infcx.next_ty_var(
TypeVariableOrigin::TypeParameterDefinition(DUMMY_SP, name)))
TypeVariableOrigin::TypeParameterDefinition(DUMMY_SP,
name,
OriginOfTyParam::Other)))
} else {
ty.super_fold_with(self)
}
Expand Down
Loading