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

RFC 213: Implement Default Type Parameter Fallback #26870

Merged
merged 18 commits into from
Jul 26, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions src/doc/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -2368,6 +2368,8 @@ The currently implemented features of the reference compiler are:
internally without imposing on callers
(i.e. making them behave like function calls in
terms of encapsulation).
* - `default_type_parameter_fallback` - Allows type parameter defaults to
influence type inference.

If a feature is promoted to a language feature, then all existing programs will
start to receive compilation warnings about `#![feature]` directives which enabled
Expand Down
21 changes: 19 additions & 2 deletions src/librustc/ast_map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ pub enum Node<'ast> {
NodeStructCtor(&'ast StructDef),

NodeLifetime(&'ast Lifetime),
NodeTyParam(&'ast TyParam)
}

/// Represents an entry and its parent NodeID.
Expand All @@ -142,6 +143,7 @@ enum MapEntry<'ast> {
EntryBlock(NodeId, &'ast Block),
EntryStructCtor(NodeId, &'ast StructDef),
EntryLifetime(NodeId, &'ast Lifetime),
EntryTyParam(NodeId, &'ast TyParam),

/// Roots for node trees.
RootCrate,
Expand Down Expand Up @@ -175,7 +177,8 @@ impl<'ast> MapEntry<'ast> {
NodePat(n) => EntryPat(p, n),
NodeBlock(n) => EntryBlock(p, n),
NodeStructCtor(n) => EntryStructCtor(p, n),
NodeLifetime(n) => EntryLifetime(p, n)
NodeLifetime(n) => EntryLifetime(p, n),
NodeTyParam(n) => EntryTyParam(p, n),
}
}

Expand All @@ -194,6 +197,7 @@ impl<'ast> MapEntry<'ast> {
EntryBlock(id, _) => id,
EntryStructCtor(id, _) => id,
EntryLifetime(id, _) => id,
EntryTyParam(id, _) => id,
_ => return None
})
}
Expand All @@ -213,6 +217,7 @@ impl<'ast> MapEntry<'ast> {
EntryBlock(_, n) => NodeBlock(n),
EntryStructCtor(_, n) => NodeStructCtor(n),
EntryLifetime(_, n) => NodeLifetime(n),
EntryTyParam(_, n) => NodeTyParam(n),
_ => return None
})
}
Expand Down Expand Up @@ -573,6 +578,7 @@ impl<'ast> Map<'ast> {
Some(NodePat(pat)) => pat.span,
Some(NodeBlock(block)) => block.span,
Some(NodeStructCtor(_)) => self.expect_item(self.get_parent(id)).span,
Some(NodeTyParam(ty_param)) => ty_param.span,
_ => return None,
};
Some(sp)
Expand Down Expand Up @@ -815,6 +821,14 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
self.parent_node = parent_node;
}

fn visit_generics(&mut self, generics: &'ast Generics) {
for ty_param in generics.ty_params.iter() {
self.insert(ty_param.id, NodeTyParam(ty_param));
}

visit::walk_generics(self, generics);
}

fn visit_trait_item(&mut self, ti: &'ast TraitItem) {
let parent_node = self.parent_node;
self.parent_node = ti.id;
Expand Down Expand Up @@ -1015,7 +1029,7 @@ impl<'a> NodePrinter for pprust::State<'a> {
NodePat(a) => self.print_pat(&*a),
NodeBlock(a) => self.print_block(&*a),
NodeLifetime(a) => self.print_lifetime(&*a),

NodeTyParam(_) => panic!("cannot print TyParam"),
// these cases do not carry enough information in the
// ast_map to reconstruct their full structure for pretty
// printing.
Expand Down Expand Up @@ -1123,6 +1137,9 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
format!("lifetime {}{}",
pprust::lifetime_to_string(&**l), id_str)
}
Some(NodeTyParam(ref ty_param)) => {
format!("typaram {:?}{}", ty_param, id_str)
}
None => {
format!("unknown node{}", id_str)
}
Expand Down
1 change: 1 addition & 0 deletions src/librustc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
#![feature(slice_splits)]
#![feature(slice_patterns)]
#![feature(slice_position_elem)]
#![feature(slice_concat_ext)]
#![feature(staged_api)]
#![feature(str_char)]
#![feature(str_match_indices)]
Expand Down
2 changes: 2 additions & 0 deletions src/librustc/metadata/tydecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -833,6 +833,7 @@ fn parse_type_param_def_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F)
assert_eq!(next(st), '|');
let index = parse_u32(st);
assert_eq!(next(st), '|');
let default_def_id = parse_def_(st, NominalType, conv);
let default = parse_opt(st, |st| parse_ty_(st, conv));
let object_lifetime_default = parse_object_lifetime_default(st, conv);

Expand All @@ -841,6 +842,7 @@ fn parse_type_param_def_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F)
def_id: def_id,
space: space,
index: index,
default_def_id: default_def_id,
default: default,
object_lifetime_default: object_lifetime_default,
}
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/metadata/tyencode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -409,9 +409,9 @@ pub fn enc_region_bounds<'a, 'tcx>(w: &mut Encoder,

pub fn enc_type_param_def<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>,
v: &ty::TypeParameterDef<'tcx>) {
mywrite!(w, "{}:{}|{}|{}|",
mywrite!(w, "{}:{}|{}|{}|{}|",
token::get_name(v.name), (cx.ds)(v.def_id),
v.space.to_uint(), v.index);
v.space.to_uint(), v.index, (cx.ds)(v.default_def_id));
enc_opt(w, v.default, |w, t| enc_ty(w, cx, t));
enc_object_lifetime_default(w, cx, v.object_lifetime_default);
}
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/middle/infer/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -893,8 +893,8 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
self.report_inference_failure(vo.clone());
}
self.give_suggestion(same_regions);
for &(ref trace, terr) in trace_origins {
self.report_and_explain_type_error(trace.clone(), &terr);
for &(ref trace, ref terr) in trace_origins {
self.report_and_explain_type_error(trace.clone(), terr);
}
}

Expand Down
127 changes: 119 additions & 8 deletions src/librustc/middle/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,50 @@ 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.
///
/// 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::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));

let unbound_int_vars = self.int_unification_table
.borrow_mut()
.unsolved_variables()
.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));

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

return variables;
}

fn combine_fields(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>)
-> CombineFields<'a, 'tcx> {
CombineFields {infcx: self,
Expand Down Expand Up @@ -956,13 +1000,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 @@ -996,20 +1049,55 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
.collect()
}

// We have to take `&mut Substs` in order to provide the correct substitutions for defaults
// along the way, for this reason we don't return them.
pub fn type_vars_for_defs(&self,
span: Span,
space: subst::ParamSpace,
substs: &mut Substs<'tcx>,
defs: &[ty::TypeParameterDef<'tcx>]) {

let mut vars = Vec::with_capacity(defs.len());

for def in defs.iter() {
let default = def.default.map(|default| {
type_variable::Default {
ty: default.subst_spanned(self.tcx, substs, Some(span)),
origin_span: span,
def_id: def.default_def_id
}
});

let ty_var = self.next_ty_var_with_default(default);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we still are not substituting here, right? I am guessing you'll have problems related to references to other variables, as well as maybe Self...?

substs.types.push(space, ty_var);
vars.push(ty_var)
}
}

/// Given a set of generics defined on a type or impl, returns a substitution mapping each
/// type/region parameter to a fresh inference variable.
pub fn fresh_substs_for_generics(&self,
span: Span,
generics: &ty::Generics<'tcx>)
-> subst::Substs<'tcx>
{
let type_params =
generics.types.map(
|_| self.next_ty_var());
let type_params = subst::VecPerParamSpace::empty();

let region_params =
generics.regions.map(
|d| self.next_region_var(EarlyBoundRegion(span, d.name)));
subst::Substs::new(type_params, region_params)

let mut substs = subst::Substs::new(type_params, region_params);

for space in subst::ParamSpace::all().iter() {
self.type_vars_for_defs(
span,
*space,
&mut substs,
generics.types.get_slice(*space));
}

return substs;
}

/// Given a set of generics defined on a trait, returns a substitution mapping each output
Expand All @@ -1027,13 +1115,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
assert!(generics.regions.len(subst::SelfSpace) == 0);
assert!(generics.regions.len(subst::FnSpace) == 0);

let type_parameter_count = generics.types.len(subst::TypeSpace);
let type_parameters = self.next_ty_vars(type_parameter_count);
let type_params = Vec::new();

let region_param_defs = generics.regions.get_slice(subst::TypeSpace);
let regions = self.region_vars_for_defs(span, region_param_defs);

subst::Substs::new_trait(type_parameters, regions, self_ty)
let mut substs = subst::Substs::new_trait(type_params, regions, self_ty);

let type_parameter_defs = generics.types.get_slice(subst::TypeSpace);
self.type_vars_for_defs(span, subst::TypeSpace, &mut substs, type_parameter_defs);

return substs;
}

pub fn fresh_bound_region(&self, debruijn: ty::DebruijnIndex) -> ty::Region {
Expand Down Expand Up @@ -1268,6 +1360,25 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
self.report_and_explain_type_error(trace, err);
}

pub fn report_conflicting_default_types(&self,
span: Span,
expected: type_variable::Default<'tcx>,
actual: type_variable::Default<'tcx>) {
let trace = TypeTrace {
origin: Misc(span),
values: Types(ty::ExpectedFound {
expected: expected.ty,
found: actual.ty
})
};

self.report_and_explain_type_error(trace,
&TypeError::TyParamDefaultMismatch(ty::ExpectedFound {
expected: expected,
found: actual
}));
}

pub fn replace_late_bound_regions_with_fresh_var<T>(
&self,
span: Span,
Expand Down
Loading