("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
}
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) {
}
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 {
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));
}
AttributeUsage,
UnknownFeatures,
UnknownCrateType,
+ DefaultTypeParamUsage,
ManagedHeapMemory,
OwnedHeapMemory,
desc: "unknown features found in crate-level #[feature] directives",
default: deny,
}),
+
("unknown_crate_type",
LintSpec {
lint: UnknownCrateType,
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,
+ }),
];
/*
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 => {}
+ }
}
}
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))
}
}
}
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);
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 {
pub struct TypeParameterDef {
ident: ast::Ident,
def_id: ast::DefId,
- bounds: @ParamBounds
+ bounds: @ParamBounds,
+ default: Option<ty::t>
}
#[deriving(Encodable, Decodable, Clone)]
use middle::const_eval;
+use middle::lint;
use middle::ty::{substs};
use middle::ty::{ty_param_substs_and_ty};
use middle::ty;
};
// 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,
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;
// 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))
}
}
_ => {
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()
// 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
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]);
}
_ => {}
}
- result.push(fcx.to_ty(ast_type))
+ result.push(ty)
}
// If the self parameter goes at the end, insert it there.
bounds: @ty::ParamBounds {
builtin_bounds: ty::EmptyBuiltinBounds(),
trait_bounds: ~[self_trait_ref]
- }
+ },
+ default: None
});
// add in the type parameters from the method
let param_ty = ty::param_ty {idx: base_index + offset,
def_id: local_def(param.id)};
let bounds = @compute_bounds(ccx, param_ty, ¶m.bounds);
+ let default = param.default.map(|x| ast_ty_to_ty(ccx, &ExplicitRscope, x));
let def = ty::TypeParameterDef {
ident: param.ident,
def_id: local_def(param.id),
- bounds: bounds
+ bounds: bounds,
+ default: default
};
debug!("def for param: {}", def.repr(ccx.tcx));
ty_enum(did, ref substs) | ty_struct(did, ref substs) => {
let path = ty::item_path(cx, did);
let base = ast_map::path_to_str(path, cx.sess.intr());
- parameterized(cx, base, &substs.regions, substs.tps)
+ parameterized(cx, base, &substs.regions, substs.tps, did, false)
}
ty_trait(did, ref substs, s, mutbl, ref bounds) => {
let path = ty::item_path(cx, did);
let base = ast_map::path_to_str(path, cx.sess.intr());
- let ty = parameterized(cx, base, &substs.regions, substs.tps);
+ let ty = parameterized(cx, base, &substs.regions,
+ substs.tps, did, true);
let bound_sep = if bounds.is_empty() { "" } else { ":" };
let bound_str = bounds.repr(cx);
format!("{}{}{}{}{}", trait_store_to_str(cx, s), mutability_to_str(mutbl), ty,
pub fn parameterized(cx: ctxt,
base: &str,
regions: &ty::RegionSubsts,
- tps: &[ty::t]) -> ~str {
+ tps: &[ty::t],
+ did: ast::DefId,
+ is_trait: bool) -> ~str {
let mut strs = ~[];
match *regions {
}
}
- for t in tps.iter() {
+ let generics = if is_trait {
+ ty::lookup_trait_def(cx, did).generics
+ } else {
+ ty::lookup_item_type(cx, did).generics
+ };
+ let ty_params = generics.type_param_defs.iter();
+ let num_defaults = ty_params.zip(tps.iter()).rev().take_while(|&(def, &actual)| {
+ match def.default {
+ Some(default) => default == actual,
+ None => false
+ }
+ }).len();
+
+ for t in tps.slice_to(tps.len() - num_defaults).iter() {
strs.push(ty_to_str(cx, *t))
}
if tcx.sess.verbose() && self.substs.self_ty.is_some() {
let mut all_tps = self.substs.tps.clone();
for &t in self.substs.self_ty.iter() { all_tps.push(t); }
- parameterized(tcx, base, &self.substs.regions, all_tps)
+ parameterized(tcx, base, &self.substs.regions,
+ all_tps, self.def_id, true)
} else {
- parameterized(tcx, base, &self.substs.regions, self.substs.tps)
+ parameterized(tcx, base, &self.substs.regions,
+ self.substs.tps, self.def_id, true)
}
}
}
pub struct TyParam {
ident: Ident,
id: NodeId,
- bounds: OptVec<TyParamBound>
+ bounds: OptVec<TyParamBound>,
+ default: Option<P<Ty>>
}
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
fn ty_field_imm(&self, span: Span, name: Ident, ty: P<ast::Ty>) -> ast::TypeField;
fn strip_bounds(&self, bounds: &Generics) -> Generics;
- fn typaram(&self, id: ast::Ident, bounds: OptVec<ast::TyParamBound>) -> ast::TyParam;
+ fn typaram(&self,
+ id: ast::Ident,
+ bounds: OptVec<ast::TyParamBound>,
+ default: Option<P<ast::Ty>>) -> ast::TyParam;
fn trait_ref(&self, path: ast::Path) -> ast::TraitRef;
fn typarambound(&self, path: ast::Path) -> ast::TyParamBound;
})
}
- fn typaram(&self, id: ast::Ident, bounds: OptVec<ast::TyParamBound>) -> ast::TyParam {
- ast::TyParam { ident: id, id: ast::DUMMY_NODE_ID, bounds: bounds }
+ fn typaram(&self,
+ id: ast::Ident,
+ bounds: OptVec<ast::TyParamBound>,
+ default: Option<P<ast::Ty>>) -> ast::TyParam {
+ ast::TyParam {
+ ident: id,
+ id: ast::DUMMY_NODE_ID,
+ bounds: bounds,
+ default: default
+ }
}
// these are strange, and probably shouldn't be used outside of
// require the current trait
bounds.push(cx.typarambound(trait_path.clone()));
- trait_generics.ty_params.push(cx.typaram(ty_param.ident, bounds));
+ trait_generics.ty_params.push(cx.typaram(ty_param.ident, bounds, None));
}
// Create the reference to the trait.
let path = b.to_path(cx, span, self_ident, self_generics);
cx.typarambound(path)
}));
- cx.typaram(cx.ident_of(name), bounds)
+ cx.typaram(cx.ident_of(name), bounds, None)
}
fn mk_generics(lifetimes: ~[ast::Lifetime], ty_params: ~[ast::TyParam]) -> Generics {
ident: tp.ident,
id: fld.new_id(tp.id),
bounds: tp.bounds.map(|x| fold_ty_param_bound(x, fld)),
+ default: tp.default.map(|x| fld.fold_ty(x))
}
}
return Some(result);
}
- // matches typaram = IDENT optbounds
+ // matches typaram = IDENT optbounds ( EQ ty )?
fn parse_ty_param(&mut self) -> TyParam {
let ident = self.parse_ident();
let opt_bounds = self.parse_optional_ty_param_bounds();
// For typarams we don't care about the difference b/w "<T>" and "<T:>".
let bounds = opt_bounds.unwrap_or_default();
- ast::TyParam { ident: ident, id: ast::DUMMY_NODE_ID, bounds: bounds }
+
+ let default = if self.token == token::EQ {
+ self.bump();
+ Some(self.parse_ty(false))
+ }
+ else { None };
+
+ TyParam {
+ ident: ident,
+ id: ast::DUMMY_NODE_ID,
+ bounds: bounds,
+ default: default
+ }
}
// parse a set of optional generic type parameter declarations
pub fn parse_generics(&mut self) -> ast::Generics {
if self.eat(&token::LT) {
let lifetimes = self.parse_lifetimes();
- let ty_params = self.parse_seq_to_gt(
- Some(token::COMMA),
- |p| p.parse_ty_param());
+ let mut seen_default = false;
+ let ty_params = self.parse_seq_to_gt(Some(token::COMMA), |p| {
+ let ty_param = p.parse_ty_param();
+ if ty_param.default.is_some() {
+ seen_default = true;
+ } else if seen_default {
+ p.span_err(p.last_span,
+ "type parameters with a default must be trailing");
+ }
+ ty_param
+ });
ast::Generics { lifetimes: lifetimes, ty_params: ty_params }
} else {
ast_util::empty_generics()
let param = generics.ty_params.get(idx);
print_ident(s, param.ident);
print_bounds(s, ¶m.bounds, false);
+ match param.default {
+ Some(default) => {
+ space(&mut s.s);
+ word_space(s, "=");
+ print_type(s, default);
+ }
+ _ => {}
+ }
}
}
generics: &Generics,
env: E) {
for type_parameter in generics.ty_params.iter() {
- walk_ty_param_bounds(visitor, &type_parameter.bounds, env.clone())
+ walk_ty_param_bounds(visitor, &type_parameter.bounds, env.clone());
+ match type_parameter.default {
+ Some(ty) => visitor.visit_ty(ty, env.clone()),
+ None => {}
+ }
}
walk_lifetime_decls(visitor, &generics.lifetimes, env);
}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[feature(default_type_params)];
+
+pub struct Heap;
+
+pub struct FakeHeap;
+
+pub struct FakeVec<T, A = FakeHeap>;
}
fn foo<'a>() {
- let _ = S::new::<int,f64>(1, 1.0); //~ ERROR the impl referenced by this path has 1 type parameter, but 0 type parameters were supplied
+ let _ = S::new::<int,f64>(1, 1.0); //~ ERROR the impl referenced by this path needs 1 type parameter, but 0 type parameters were supplied
let _ = S::<'a,int>::new::<f64>(1, 1.0); //~ ERROR expected 0 lifetime parameter(s)
- let _: S2 = Trait::new::<int,f64>(1, 1.0); //~ ERROR the trait referenced by this path has 1 type parameter, but 0 type parameters were supplied
+ let _: S2 = Trait::new::<int,f64>(1, 1.0); //~ ERROR the trait referenced by this path needs 1 type parameter, but 0 type parameters were supplied
let _: S2 = Trait::<'a,int>::new::<f64>(1, 1.0); //~ ERROR expected 0 lifetime parameter(s)
}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Heap;
+
+struct Vec<T, A = Heap>; //~ ERROR: default type parameters are experimental
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[feature(default_type_params)];
+
+struct Foo<A, B, C = (A, B)>;
+
+impl<A, B, C = (A, B)> Foo<A, B, C> {
+ fn new() -> Foo<A, B, C> {Foo}
+}
+
+fn main() {
+ Foo::<int>::new(); //~ ERROR the impl referenced by this path needs at least 2 type parameters, but 1 type parameter were supplied
+ //~^ ERROR not enough type parameters provided: expected at least 2, found 1
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[feature(default_type_params)];
+
+struct Heap;
+
+struct Vec<T, A = Heap>;
+
+impl<T, A = Heap> Vec<T, A> {
+ fn new() -> Vec<T, A> {Vec}
+}
+
+fn main() {
+ Vec::<int, Heap, bool>::new(); //~ ERROR the impl referenced by this path needs at most 2 type parameters, but 3 type parameters were supplied
+ //~^ ERROR too many type parameters provided: expected at most 2, found 3
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[feature(default_type_params)];
+
+struct Heap;
+
+struct Vec<A = Heap, T>; //~ ERROR type parameters with a default must be trailing
+
+struct Foo<A, B = Vec<C>, C>; //~ ERROR type parameters with a default must be trailing
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[feature(default_type_params)];
+
+struct Heap;
+
+struct Vec<T, A = Heap>;
+
+fn main() {
+ let _: Vec; //~ ERROR wrong number of type arguments: expected at least 1 but found 0
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[feature(default_type_params)];
+
+struct Heap;
+
+struct Vec<T, A = Heap>;
+
+fn main() {
+ let _: Vec<int, Heap, bool>; //~ ERROR wrong number of type arguments: expected at most 2 but found 3
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[feature(default_type_params)];
+
+struct A;
+struct B;
+struct C;
+struct Foo<T = A, U = B, V = C>;
+
+fn main() {
+ // Ensure that the printed type doesn't include the default type params...
+ let _: Foo<int> = ();
+ //~^ ERROR mismatched types: expected `Foo<int>` but found `()`
+
+ // ...even when they're present, but the same types as the defaults.
+ let _: Foo<int, B, C> = ();
+ //~^ ERROR mismatched types: expected `Foo<int>` but found `()`
+
+ // But not when there's a different type in between.
+ let _: Foo<A, int, C> = ();
+ //~^ ERROR mismatched types: expected `Foo<A,int>` but found `()`
+
+ // And don't print <> at all when there's just defaults.
+ let _: Foo<A, B, C> = ();
+ //~^ ERROR mismatched types: expected `Foo` but found `()`
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[feature(default_type_params)];
+
+#[deny(default_type_param_usage)];
+
+pub struct Heap;
+
+pub struct Vec<T, A = Heap>;
+
+pub struct FooAlloc;
+
+pub type VecFoo<T> = Vec<T, FooAlloc>; //~ ERROR provided type arguments with defaults
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:default_type_params_xc.rs
+
+// xfail-fast #[feature] doesn't work with check-fast
+#[feature(default_type_params)];
+
+#[allow(default_type_param_usage)];
+
+extern mod default_type_params_xc;
+
+struct Vec<T, A = default_type_params_xc::Heap>;
+
+struct Foo;
+
+fn main() {
+ let _a = Vec::<int>;
+ let _b = Vec::<int, default_type_params_xc::FakeHeap>;
+ let _c = default_type_params_xc::FakeVec::<int>;
+ let _d = default_type_params_xc::FakeVec::<int, Foo>;
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// xfail-fast #[feature] doesn't work with check-fast
+#[feature(default_type_params)];
+
+#[allow(default_type_param_usage)];
+
+struct Foo<A = (int, char)> {
+ a: A
+}
+
+impl Foo<int> {
+ fn bar_int(&self) -> int {
+ self.a
+ }
+}
+
+impl Foo<char> {
+ fn bar_char(&self) -> char {
+ self.a
+ }
+}
+
+impl Foo {
+ fn bar(&self) {
+ let (i, c): (int, char) = self.a;
+ assert_eq!(Foo { a: i }.bar_int(), i);
+ assert_eq!(Foo { a: c }.bar_char(), c);
+ }
+}
+
+impl<A: Clone> Foo<A> {
+ fn baz(&self) -> A {
+ self.a.clone()
+ }
+}
+
+fn default_foo(x: Foo) {
+ let (i, c): (int, char) = x.a;
+ assert_eq!(i, 1);
+ assert_eq!(c, 'a');
+
+ x.bar();
+ assert_eq!(x.baz(), (1, 'a'));
+}
+
+fn main() {
+ default_foo(Foo { a: (1, 'a') });
+}