Skip to content

Commit 3427137

Browse files
committed
auto merge of #11217 : eddyb/rust/generic-default-type-params, r=cmr
2 parents 30e9bba + 7d96774 commit 3427137

33 files changed

+536
-78
lines changed

src/librustc/front/feature_gate.rs

+15
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
4848
("log_syntax", Active),
4949
("trace_macros", Active),
5050
("simd", Active),
51+
("default_type_params", Active),
5152

5253
// These are used to test this portion of the compiler, they don't actually
5354
// mean anything
@@ -234,6 +235,20 @@ impl Visitor<()> for Context {
234235
}
235236
visit::walk_expr(self, e, ());
236237
}
238+
239+
fn visit_generics(&mut self, generics: &ast::Generics, _: ()) {
240+
for type_parameter in generics.ty_params.iter() {
241+
match type_parameter.default {
242+
Some(ty) => {
243+
self.gate_feature("default_type_params", ty.span,
244+
"default type parameters are \
245+
experimental and possibly buggy");
246+
}
247+
None => {}
248+
}
249+
}
250+
visit::walk_generics(self, generics, ());
251+
}
237252
}
238253

239254
pub fn check_crate(sess: Session, crate: &ast::Crate) {

src/librustc/metadata/tydecode.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -573,9 +573,12 @@ pub fn parse_type_param_def_data(data: &[u8], start: uint,
573573
}
574574

575575
fn parse_type_param_def(st: &mut PState, conv: conv_did) -> ty::TypeParameterDef {
576-
ty::TypeParameterDef {ident: parse_ident(st, ':'),
577-
def_id: parse_def(st, NominalType, |x,y| conv(x,y)),
578-
bounds: @parse_bounds(st, |x,y| conv(x,y))}
576+
ty::TypeParameterDef {
577+
ident: parse_ident(st, ':'),
578+
def_id: parse_def(st, NominalType, |x,y| conv(x,y)),
579+
bounds: @parse_bounds(st, |x,y| conv(x,y)),
580+
default: parse_opt(st, |st| parse_ty(st, |x,y| conv(x,y)))
581+
}
579582
}
580583

581584
fn parse_bounds(st: &mut PState, conv: conv_did) -> ty::ParamBounds {

src/librustc/metadata/tyencode.rs

+1
Original file line numberDiff line numberDiff line change
@@ -421,4 +421,5 @@ fn enc_bounds(w: &mut MemWriter, cx: @ctxt, bs: &ty::ParamBounds) {
421421
pub fn enc_type_param_def(w: &mut MemWriter, cx: @ctxt, v: &ty::TypeParameterDef) {
422422
mywrite!(w, "{}:{}|", cx.tcx.sess.str_of(v.ident), (cx.ds)(v.def_id));
423423
enc_bounds(w, cx, v.bounds);
424+
enc_opt(w, v.default, |w, t| enc_ty(w, cx, t));
424425
}

src/librustc/middle/lint.rs

+9
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ pub enum Lint {
8686
AttributeUsage,
8787
UnknownFeatures,
8888
UnknownCrateType,
89+
DefaultTypeParamUsage,
8990

9091
ManagedHeapMemory,
9192
OwnedHeapMemory,
@@ -359,6 +360,7 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[
359360
desc: "unknown features found in crate-level #[feature] directives",
360361
default: deny,
361362
}),
363+
362364
("unknown_crate_type",
363365
LintSpec {
364366
lint: UnknownCrateType,
@@ -379,6 +381,13 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[
379381
desc: "unused result of an expression in a statement",
380382
default: allow,
381383
}),
384+
385+
("default_type_param_usage",
386+
LintSpec {
387+
lint: DefaultTypeParamUsage,
388+
desc: "prevents explicitly setting a type parameter with a default",
389+
default: deny,
390+
}),
382391
];
383392

384393
/*

src/librustc/middle/resolve.rs

+4
Original file line numberDiff line numberDiff line change
@@ -3931,6 +3931,10 @@ impl Resolver {
39313931
for bound in type_parameter.bounds.iter() {
39323932
self.resolve_type_parameter_bound(type_parameter.id, bound);
39333933
}
3934+
match type_parameter.default {
3935+
Some(ty) => self.resolve_type(ty),
3936+
None => {}
3937+
}
39343938
}
39353939
}
39363940

src/librustc/middle/subst.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,8 @@ impl Subst for ty::TypeParameterDef {
164164
ty::TypeParameterDef {
165165
ident: self.ident,
166166
def_id: self.def_id,
167-
bounds: self.bounds.subst(tcx, substs)
167+
bounds: self.bounds.subst(tcx, substs),
168+
default: self.default.map(|x| x.subst(tcx, substs))
168169
}
169170
}
170171
}

src/librustc/middle/trans/debuginfo.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -2000,7 +2000,8 @@ fn trait_metadata(cx: &CrateContext,
20002000
ppaux::mutability_to_str(mutability) +
20012001
token::ident_to_str(&ident);
20022002
// Add type and region parameters
2003-
let name = ppaux::parameterized(cx.tcx, name, &substs.regions, substs.tps);
2003+
let name = ppaux::parameterized(cx.tcx, name, &substs.regions,
2004+
substs.tps, def_id, true);
20042005

20052006
let (containing_scope, definition_span) =
20062007
get_namespace_and_span_for_item(cx, def_id, usage_site_span);

src/librustc/middle/trans/type_of.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,8 @@ pub fn llvm_type_name(cx: &CrateContext,
330330
an_enum => { "enum" }
331331
};
332332
let tstr = ppaux::parameterized(cx.tcx, ty::item_path_str(cx.tcx, did),
333-
&ty::NonerasedRegions(opt_vec::Empty), tps);
333+
&ty::NonerasedRegions(opt_vec::Empty),
334+
tps, did, false);
334335
if did.crate == 0 {
335336
format!("{}.{}", name, tstr)
336337
} else {

src/librustc/middle/ty.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -855,7 +855,8 @@ impl ToStr for IntVarValue {
855855
pub struct TypeParameterDef {
856856
ident: ast::Ident,
857857
def_id: ast::DefId,
858-
bounds: @ParamBounds
858+
bounds: @ParamBounds,
859+
default: Option<ty::t>
859860
}
860861

861862
#[deriving(Encodable, Decodable, Clone)]

src/librustc/middle/typeck/astconv.rs

+36-13
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151

5252

5353
use middle::const_eval;
54+
use middle::lint;
5455
use middle::ty::{substs};
5556
use middle::ty::{ty_param_substs_and_ty};
5657
use middle::ty;
@@ -195,21 +196,43 @@ fn ast_path_substs<AC:AstConv,RS:RegionScope>(
195196
};
196197

197198
// Convert the type parameters supplied by the user.
198-
let supplied_type_parameter_count =
199-
path.segments.iter().flat_map(|s| s.types.iter()).len();
200-
if decl_generics.type_param_defs.len() != supplied_type_parameter_count {
201-
this.tcx().sess.span_fatal(
202-
path.span,
203-
format!("wrong number of type arguments: expected {} but found {}",
204-
decl_generics.type_param_defs.len(),
205-
supplied_type_parameter_count));
199+
let supplied_ty_param_count = path.segments.iter().flat_map(|s| s.types.iter()).len();
200+
let formal_ty_param_count = decl_generics.type_param_defs.len();
201+
let required_ty_param_count = decl_generics.type_param_defs.iter()
202+
.take_while(|x| x.default.is_none())
203+
.len();
204+
if supplied_ty_param_count < required_ty_param_count {
205+
let expected = if required_ty_param_count < formal_ty_param_count {
206+
"expected at least"
207+
} else {
208+
"expected"
209+
};
210+
this.tcx().sess.span_fatal(path.span,
211+
format!("wrong number of type arguments: {} {} but found {}",
212+
expected, required_ty_param_count, supplied_ty_param_count));
213+
} else if supplied_ty_param_count > formal_ty_param_count {
214+
let expected = if required_ty_param_count < formal_ty_param_count {
215+
"expected at most"
216+
} else {
217+
"expected"
218+
};
219+
this.tcx().sess.span_fatal(path.span,
220+
format!("wrong number of type arguments: {} {} but found {}",
221+
expected, formal_ty_param_count, supplied_ty_param_count));
222+
}
223+
224+
if supplied_ty_param_count > required_ty_param_count {
225+
let id = path.segments.iter().flat_map(|s| s.types.iter())
226+
.nth(required_ty_param_count).unwrap().id;
227+
this.tcx().sess.add_lint(lint::DefaultTypeParamUsage, id, path.span,
228+
~"provided type arguments with defaults");
206229
}
207-
let tps = path.segments
208-
.iter()
209-
.flat_map(|s| s.types.iter())
210-
.map(|&a_t| ast_ty_to_ty(this, rscope, a_t))
211-
.collect();
212230

231+
let defaults = decl_generics.type_param_defs.slice_from(supplied_ty_param_count)
232+
.iter().map(|&x| x.default.unwrap());
233+
let tps = path.segments.iter().flat_map(|s| s.types.iter())
234+
.map(|&a_t| ast_ty_to_ty(this, rscope, a_t))
235+
.chain(defaults).collect();
213236
substs {
214237
regions: ty::NonerasedRegions(regions),
215238
self_ty: self_ty,

src/librustc/middle/typeck/check/mod.rs

+91-36
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ use middle::const_eval;
8181
use middle::lang_items::{ExchangeHeapLangItem, GcLangItem};
8282
use middle::lang_items::{ManagedHeapLangItem};
8383
use middle::lint::UnreachableCode;
84+
use middle::lint;
8485
use middle::pat_util::pat_id_map;
8586
use middle::pat_util;
8687
use middle::subst::Subst;
@@ -1500,32 +1501,55 @@ fn check_type_parameter_positions_in_path(function_context: @FnCtxt,
15001501
// Make sure the number of type parameters supplied on the trait
15011502
// or implementation segment equals the number of type parameters
15021503
// on the trait or implementation definition.
1503-
let trait_type_parameter_count = generics.type_param_defs.len();
1504-
let supplied_type_parameter_count = trait_segment.types.len();
1505-
if trait_type_parameter_count != supplied_type_parameter_count {
1506-
let trait_count_suffix = if trait_type_parameter_count == 1 {
1504+
let formal_ty_param_count = generics.type_param_defs.len();
1505+
let required_ty_param_count = generics.type_param_defs.iter()
1506+
.take_while(|x| x.default.is_none())
1507+
.len();
1508+
let supplied_ty_param_count = trait_segment.types.len();
1509+
if supplied_ty_param_count < required_ty_param_count {
1510+
let trait_count_suffix = if required_ty_param_count == 1 {
15071511
""
15081512
} else {
15091513
"s"
15101514
};
1511-
let supplied_count_suffix =
1512-
if supplied_type_parameter_count == 1 {
1513-
""
1514-
} else {
1515-
"s"
1516-
};
1517-
function_context.tcx()
1518-
.sess
1519-
.span_err(path.span,
1520-
format!("the {} referenced by this \
1521-
path has {} type \
1522-
parameter{}, but {} type \
1523-
parameter{} were supplied",
1524-
name,
1525-
trait_type_parameter_count,
1526-
trait_count_suffix,
1527-
supplied_type_parameter_count,
1528-
supplied_count_suffix))
1515+
let supplied_count_suffix = if supplied_ty_param_count == 1 {
1516+
""
1517+
} else {
1518+
"s"
1519+
};
1520+
let needs = if required_ty_param_count < generics.type_param_defs.len() {
1521+
"needs at least"
1522+
} else {
1523+
"needs"
1524+
};
1525+
function_context.tcx().sess.span_err(path.span,
1526+
format!("the {} referenced by this path {} {} type \
1527+
parameter{}, but {} type parameter{} were supplied",
1528+
name, needs,
1529+
required_ty_param_count, trait_count_suffix,
1530+
supplied_ty_param_count, supplied_count_suffix))
1531+
} else if supplied_ty_param_count > formal_ty_param_count {
1532+
let trait_count_suffix = if formal_ty_param_count == 1 {
1533+
""
1534+
} else {
1535+
"s"
1536+
};
1537+
let supplied_count_suffix = if supplied_ty_param_count == 1 {
1538+
""
1539+
} else {
1540+
"s"
1541+
};
1542+
let needs = if required_ty_param_count < generics.type_param_defs.len() {
1543+
"needs at most"
1544+
} else {
1545+
"needs"
1546+
};
1547+
function_context.tcx().sess.span_err(path.span,
1548+
format!("the {} referenced by this path {} {} type \
1549+
parameter{}, but {} type parameter{} were supplied",
1550+
name, needs,
1551+
formal_ty_param_count, trait_count_suffix,
1552+
supplied_ty_param_count, supplied_count_suffix))
15291553
}
15301554
}
15311555
_ => {
@@ -3683,6 +3707,9 @@ pub fn instantiate_path(fcx: @FnCtxt,
36833707
debug!(">>> instantiate_path");
36843708

36853709
let ty_param_count = tpt.generics.type_param_defs.len();
3710+
let ty_param_req = tpt.generics.type_param_defs.iter()
3711+
.take_while(|x| x.default.is_none())
3712+
.len();
36863713
let mut ty_substs_len = 0;
36873714
for segment in pth.segments.iter() {
36883715
ty_substs_len += segment.types.len()
@@ -3720,13 +3747,13 @@ pub fn instantiate_path(fcx: @FnCtxt,
37203747
// Here we calculate the "user type parameter count", which is the number
37213748
// of type parameters actually manifest in the AST. This will differ from
37223749
// the internal type parameter count when there are self types involved.
3723-
let (user_type_parameter_count, self_parameter_index) = match def {
3750+
let (user_ty_param_count, user_ty_param_req, self_parameter_index) = match def {
37243751
ast::DefStaticMethod(_, provenance @ ast::FromTrait(_), _) => {
37253752
let generics = generics_of_static_method_container(fcx.ccx.tcx,
37263753
provenance);
3727-
(ty_param_count - 1, Some(generics.type_param_defs.len()))
3754+
(ty_param_count - 1, ty_param_req - 1, Some(generics.type_param_defs.len()))
37283755
}
3729-
_ => (ty_param_count, None),
3756+
_ => (ty_param_count, ty_param_req, None),
37303757
};
37313758

37323759
// determine values for type parameters, using the values given by
@@ -3737,35 +3764,63 @@ pub fn instantiate_path(fcx: @FnCtxt,
37373764
fcx.ccx.tcx.sess.span_err
37383765
(span, "this item does not take type parameters");
37393766
fcx.infcx().next_ty_vars(ty_param_count)
3740-
} else if ty_substs_len > user_type_parameter_count {
3767+
} else if ty_substs_len > user_ty_param_count {
3768+
let expected = if user_ty_param_req < user_ty_param_count {
3769+
"expected at most"
3770+
} else {
3771+
"expected"
3772+
};
37413773
fcx.ccx.tcx.sess.span_err
37423774
(span,
3743-
format!("too many type parameters provided: expected {}, found {}",
3744-
user_type_parameter_count, ty_substs_len));
3775+
format!("too many type parameters provided: {} {}, found {}",
3776+
expected, user_ty_param_count, ty_substs_len));
37453777
fcx.infcx().next_ty_vars(ty_param_count)
3746-
} else if ty_substs_len < user_type_parameter_count {
3778+
} else if ty_substs_len < user_ty_param_req {
3779+
let expected = if user_ty_param_req < user_ty_param_count {
3780+
"expected at least"
3781+
} else {
3782+
"expected"
3783+
};
37473784
fcx.ccx.tcx.sess.span_err
37483785
(span,
3749-
format!("not enough type parameters provided: expected {}, found {}",
3750-
user_type_parameter_count, ty_substs_len));
3786+
format!("not enough type parameters provided: {} {}, found {}",
3787+
expected, user_ty_param_req, ty_substs_len));
37513788
fcx.infcx().next_ty_vars(ty_param_count)
37523789
} else {
3790+
if ty_substs_len > user_ty_param_req {
3791+
fcx.tcx().sess.add_lint(lint::DefaultTypeParamUsage, node_id, pth.span,
3792+
~"provided type arguments with defaults");
3793+
}
3794+
37533795
// Build up the list of type parameters, inserting the self parameter
37543796
// at the appropriate position.
37553797
let mut result = ~[];
37563798
let mut pushed = false;
3757-
for (i, &ast_type) in pth.segments
3758-
.iter()
3759-
.flat_map(|segment| segment.types.iter())
3760-
.enumerate() {
3799+
let defaults = tpt.generics.type_param_defs.iter()
3800+
.enumerate().filter_map(|(i, x)| {
3801+
match self_parameter_index {
3802+
Some(index) if index == i => None,
3803+
_ => Some(x.default)
3804+
}
3805+
}).skip(ty_substs_len).map(|x| match x {
3806+
Some(default) => default,
3807+
None => {
3808+
fcx.tcx().sess.span_bug(span,
3809+
"missing default for a not explicitely provided type param")
3810+
}
3811+
});
3812+
for (i, ty) in pth.segments.iter()
3813+
.flat_map(|segment| segment.types.iter())
3814+
.map(|&ast_type| fcx.to_ty(ast_type))
3815+
.chain(defaults).enumerate() {
37613816
match self_parameter_index {
37623817
Some(index) if index == i => {
37633818
result.push(fcx.infcx().next_ty_vars(1)[0]);
37643819
pushed = true;
37653820
}
37663821
_ => {}
37673822
}
3768-
result.push(fcx.to_ty(ast_type))
3823+
result.push(ty)
37693824
}
37703825

37713826
// If the self parameter goes at the end, insert it there.

0 commit comments

Comments
 (0)