Skip to content

Implement default type parameters in generics. #11217

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

Merged
merged 1 commit into from
Jan 30, 2014
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
15 changes: 15 additions & 0 deletions src/librustc/front/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
("log_syntax", Active),
("trace_macros", Active),
("simd", Active),
("default_type_params", Active),

// These are used to test this portion of the compiler, they don't actually
// mean anything
Expand Down Expand Up @@ -234,6 +235,20 @@ impl Visitor<()> for Context {
}
visit::walk_expr(self, e, ());
}

fn visit_generics(&mut self, generics: &ast::Generics, _: ()) {
for type_parameter in generics.ty_params.iter() {
match type_parameter.default {
Some(ty) => {
self.gate_feature("default_type_params", ty.span,
"default type parameters are \
experimental and possibly buggy");
}
None => {}
}
}
visit::walk_generics(self, generics, ());
}
}

pub fn check_crate(sess: Session, crate: &ast::Crate) {
Expand Down
9 changes: 6 additions & 3 deletions src/librustc/metadata/tydecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -573,9 +573,12 @@ pub fn parse_type_param_def_data(data: &[u8], start: uint,
}

fn parse_type_param_def(st: &mut PState, conv: conv_did) -> ty::TypeParameterDef {
ty::TypeParameterDef {ident: parse_ident(st, ':'),
def_id: parse_def(st, NominalType, |x,y| conv(x,y)),
bounds: @parse_bounds(st, |x,y| conv(x,y))}
ty::TypeParameterDef {
ident: parse_ident(st, ':'),
def_id: parse_def(st, NominalType, |x,y| conv(x,y)),
bounds: @parse_bounds(st, |x,y| conv(x,y)),
default: parse_opt(st, |st| parse_ty(st, |x,y| conv(x,y)))
}
}

fn parse_bounds(st: &mut PState, conv: conv_did) -> ty::ParamBounds {
Expand Down
1 change: 1 addition & 0 deletions src/librustc/metadata/tyencode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -421,4 +421,5 @@ fn enc_bounds(w: &mut MemWriter, cx: @ctxt, bs: &ty::ParamBounds) {
pub fn enc_type_param_def(w: &mut MemWriter, cx: @ctxt, v: &ty::TypeParameterDef) {
mywrite!(w, "{}:{}|", cx.tcx.sess.str_of(v.ident), (cx.ds)(v.def_id));
enc_bounds(w, cx, v.bounds);
enc_opt(w, v.default, |w, t| enc_ty(w, cx, t));
}
9 changes: 9 additions & 0 deletions src/librustc/middle/lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ pub enum Lint {
AttributeUsage,
UnknownFeatures,
UnknownCrateType,
DefaultTypeParamUsage,

ManagedHeapMemory,
OwnedHeapMemory,
Expand Down Expand Up @@ -359,6 +360,7 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[
desc: "unknown features found in crate-level #[feature] directives",
default: deny,
}),

("unknown_crate_type",
LintSpec {
lint: UnknownCrateType,
Expand All @@ -379,6 +381,13 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[
desc: "unused result of an expression in a statement",
default: allow,
}),

("default_type_param_usage",
LintSpec {
lint: DefaultTypeParamUsage,
desc: "prevents explicitly setting a type parameter with a default",
default: deny,
}),
];

/*
Expand Down
4 changes: 4 additions & 0 deletions src/librustc/middle/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3931,6 +3931,10 @@ impl Resolver {
for bound in type_parameter.bounds.iter() {
self.resolve_type_parameter_bound(type_parameter.id, bound);
}
match type_parameter.default {
Some(ty) => self.resolve_type(ty),
None => {}
}
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/librustc/middle/subst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,8 @@ impl Subst for ty::TypeParameterDef {
ty::TypeParameterDef {
ident: self.ident,
def_id: self.def_id,
bounds: self.bounds.subst(tcx, substs)
bounds: self.bounds.subst(tcx, substs),
default: self.default.map(|x| x.subst(tcx, substs))
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/middle/trans/debuginfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2000,7 +2000,8 @@ fn trait_metadata(cx: &CrateContext,
ppaux::mutability_to_str(mutability) +
token::ident_to_str(&ident);
// Add type and region parameters
let name = ppaux::parameterized(cx.tcx, name, &substs.regions, substs.tps);
let name = ppaux::parameterized(cx.tcx, name, &substs.regions,
substs.tps, def_id, true);

let (containing_scope, definition_span) =
get_namespace_and_span_for_item(cx, def_id, usage_site_span);
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/middle/trans/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,8 @@ pub fn llvm_type_name(cx: &CrateContext,
an_enum => { "enum" }
};
let tstr = ppaux::parameterized(cx.tcx, ty::item_path_str(cx.tcx, did),
&ty::NonerasedRegions(opt_vec::Empty), tps);
&ty::NonerasedRegions(opt_vec::Empty),
tps, did, false);
if did.crate == 0 {
format!("{}.{}", name, tstr)
} else {
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -855,7 +855,8 @@ impl ToStr for IntVarValue {
pub struct TypeParameterDef {
ident: ast::Ident,
def_id: ast::DefId,
bounds: @ParamBounds
bounds: @ParamBounds,
default: Option<ty::t>
}

#[deriving(Encodable, Decodable, Clone)]
Expand Down
49 changes: 36 additions & 13 deletions src/librustc/middle/typeck/astconv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@


use middle::const_eval;
use middle::lint;
use middle::ty::{substs};
use middle::ty::{ty_param_substs_and_ty};
use middle::ty;
Expand Down Expand Up @@ -195,21 +196,43 @@ fn ast_path_substs<AC:AstConv,RS:RegionScope>(
};

// Convert the type parameters supplied by the user.
let supplied_type_parameter_count =
path.segments.iter().flat_map(|s| s.types.iter()).len();
if decl_generics.type_param_defs.len() != supplied_type_parameter_count {
this.tcx().sess.span_fatal(
path.span,
format!("wrong number of type arguments: expected {} but found {}",
decl_generics.type_param_defs.len(),
supplied_type_parameter_count));
let supplied_ty_param_count = path.segments.iter().flat_map(|s| s.types.iter()).len();
let formal_ty_param_count = decl_generics.type_param_defs.len();
let required_ty_param_count = decl_generics.type_param_defs.iter()
.take_while(|x| x.default.is_none())
.len();
if supplied_ty_param_count < required_ty_param_count {
let expected = if required_ty_param_count < formal_ty_param_count {
"expected at least"
} else {
"expected"
};
this.tcx().sess.span_fatal(path.span,
format!("wrong number of type arguments: {} {} but found {}",
expected, required_ty_param_count, supplied_ty_param_count));
} else if supplied_ty_param_count > formal_ty_param_count {
let expected = if required_ty_param_count < formal_ty_param_count {
"expected at most"
} else {
"expected"
};
this.tcx().sess.span_fatal(path.span,
format!("wrong number of type arguments: {} {} but found {}",
expected, formal_ty_param_count, supplied_ty_param_count));
}

if supplied_ty_param_count > required_ty_param_count {
let id = path.segments.iter().flat_map(|s| s.types.iter())
.nth(required_ty_param_count).unwrap().id;
this.tcx().sess.add_lint(lint::DefaultTypeParamUsage, id, path.span,
~"provided type arguments with defaults");
}
let tps = path.segments
.iter()
.flat_map(|s| s.types.iter())
.map(|&a_t| ast_ty_to_ty(this, rscope, a_t))
.collect();

let defaults = decl_generics.type_param_defs.slice_from(supplied_ty_param_count)
.iter().map(|&x| x.default.unwrap());
let tps = path.segments.iter().flat_map(|s| s.types.iter())
.map(|&a_t| ast_ty_to_ty(this, rscope, a_t))
.chain(defaults).collect();
substs {
regions: ty::NonerasedRegions(regions),
self_ty: self_ty,
Expand Down
127 changes: 91 additions & 36 deletions src/librustc/middle/typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ use middle::const_eval;
use middle::lang_items::{ExchangeHeapLangItem, GcLangItem};
use middle::lang_items::{ManagedHeapLangItem};
use middle::lint::UnreachableCode;
use middle::lint;
use middle::pat_util::pat_id_map;
use middle::pat_util;
use middle::subst::Subst;
Expand Down Expand Up @@ -1500,32 +1501,55 @@ fn check_type_parameter_positions_in_path(function_context: @FnCtxt,
// Make sure the number of type parameters supplied on the trait
// or implementation segment equals the number of type parameters
// on the trait or implementation definition.
let trait_type_parameter_count = generics.type_param_defs.len();
let supplied_type_parameter_count = trait_segment.types.len();
if trait_type_parameter_count != supplied_type_parameter_count {
let trait_count_suffix = if trait_type_parameter_count == 1 {
let formal_ty_param_count = generics.type_param_defs.len();
let required_ty_param_count = generics.type_param_defs.iter()
.take_while(|x| x.default.is_none())
.len();
let supplied_ty_param_count = trait_segment.types.len();
if supplied_ty_param_count < required_ty_param_count {
let trait_count_suffix = if required_ty_param_count == 1 {
""
} else {
"s"
};
let supplied_count_suffix =
if supplied_type_parameter_count == 1 {
""
} else {
"s"
};
function_context.tcx()
.sess
.span_err(path.span,
format!("the {} referenced by this \
path has {} type \
parameter{}, but {} type \
parameter{} were supplied",
name,
trait_type_parameter_count,
trait_count_suffix,
supplied_type_parameter_count,
supplied_count_suffix))
let supplied_count_suffix = if supplied_ty_param_count == 1 {
""
} else {
"s"
};
let needs = if required_ty_param_count < generics.type_param_defs.len() {
"needs at least"
} else {
"needs"
};
function_context.tcx().sess.span_err(path.span,
format!("the {} referenced by this path {} {} type \
parameter{}, but {} type parameter{} were supplied",
name, needs,
required_ty_param_count, trait_count_suffix,
supplied_ty_param_count, supplied_count_suffix))
} else if supplied_ty_param_count > formal_ty_param_count {
let trait_count_suffix = if formal_ty_param_count == 1 {
""
} else {
"s"
};
let supplied_count_suffix = if supplied_ty_param_count == 1 {
""
} else {
"s"
};
let needs = if required_ty_param_count < generics.type_param_defs.len() {
"needs at most"
} else {
"needs"
};
function_context.tcx().sess.span_err(path.span,
format!("the {} referenced by this path {} {} type \
parameter{}, but {} type parameter{} were supplied",
name, needs,
formal_ty_param_count, trait_count_suffix,
supplied_ty_param_count, supplied_count_suffix))
}
}
_ => {
Expand Down Expand Up @@ -3683,6 +3707,9 @@ pub fn instantiate_path(fcx: @FnCtxt,
debug!(">>> instantiate_path");

let ty_param_count = tpt.generics.type_param_defs.len();
let ty_param_req = tpt.generics.type_param_defs.iter()
.take_while(|x| x.default.is_none())
.len();
let mut ty_substs_len = 0;
for segment in pth.segments.iter() {
ty_substs_len += segment.types.len()
Expand Down Expand Up @@ -3720,13 +3747,13 @@ pub fn instantiate_path(fcx: @FnCtxt,
// Here we calculate the "user type parameter count", which is the number
// of type parameters actually manifest in the AST. This will differ from
// the internal type parameter count when there are self types involved.
let (user_type_parameter_count, self_parameter_index) = match def {
let (user_ty_param_count, user_ty_param_req, self_parameter_index) = match def {
ast::DefStaticMethod(_, provenance @ ast::FromTrait(_), _) => {
let generics = generics_of_static_method_container(fcx.ccx.tcx,
provenance);
(ty_param_count - 1, Some(generics.type_param_defs.len()))
(ty_param_count - 1, ty_param_req - 1, Some(generics.type_param_defs.len()))
}
_ => (ty_param_count, None),
_ => (ty_param_count, ty_param_req, None),
};

// determine values for type parameters, using the values given by
Expand All @@ -3737,35 +3764,63 @@ pub fn instantiate_path(fcx: @FnCtxt,
fcx.ccx.tcx.sess.span_err
(span, "this item does not take type parameters");
fcx.infcx().next_ty_vars(ty_param_count)
} else if ty_substs_len > user_type_parameter_count {
} else if ty_substs_len > user_ty_param_count {
let expected = if user_ty_param_req < user_ty_param_count {
"expected at most"
} else {
"expected"
};
fcx.ccx.tcx.sess.span_err
(span,
format!("too many type parameters provided: expected {}, found {}",
user_type_parameter_count, ty_substs_len));
format!("too many type parameters provided: {} {}, found {}",
expected, user_ty_param_count, ty_substs_len));
fcx.infcx().next_ty_vars(ty_param_count)
} else if ty_substs_len < user_type_parameter_count {
} else if ty_substs_len < user_ty_param_req {
let expected = if user_ty_param_req < user_ty_param_count {
"expected at least"
} else {
"expected"
};
fcx.ccx.tcx.sess.span_err
(span,
format!("not enough type parameters provided: expected {}, found {}",
user_type_parameter_count, ty_substs_len));
format!("not enough type parameters provided: {} {}, found {}",
expected, user_ty_param_req, ty_substs_len));
fcx.infcx().next_ty_vars(ty_param_count)
} else {
if ty_substs_len > user_ty_param_req {
fcx.tcx().sess.add_lint(lint::DefaultTypeParamUsage, node_id, pth.span,
~"provided type arguments with defaults");
}

// Build up the list of type parameters, inserting the self parameter
// at the appropriate position.
let mut result = ~[];
let mut pushed = false;
for (i, &ast_type) in pth.segments
.iter()
.flat_map(|segment| segment.types.iter())
.enumerate() {
let defaults = tpt.generics.type_param_defs.iter()
.enumerate().filter_map(|(i, x)| {
match self_parameter_index {
Some(index) if index == i => None,
_ => Some(x.default)
}
}).skip(ty_substs_len).map(|x| match x {
Some(default) => default,
None => {
fcx.tcx().sess.span_bug(span,
"missing default for a not explicitely provided type param")
}
});
for (i, ty) in pth.segments.iter()
.flat_map(|segment| segment.types.iter())
.map(|&ast_type| fcx.to_ty(ast_type))
.chain(defaults).enumerate() {
match self_parameter_index {
Some(index) if index == i => {
result.push(fcx.infcx().next_ty_vars(1)[0]);
pushed = true;
}
_ => {}
}
result.push(fcx.to_ty(ast_type))
result.push(ty)
}

// If the self parameter goes at the end, insert it there.
Expand Down
Loading