auto merge of #11217 : eddyb/rust/generic-default-type-params, r=cmr

This commit is contained in:
bors 2014-01-30 10:41:47 -08:00
commit 3427137f66
33 changed files with 536 additions and 78 deletions

View file

@ -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
@ -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) {

View file

@ -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 {

View file

@ -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));
}

View file

@ -86,6 +86,7 @@ pub enum Lint {
AttributeUsage,
UnknownFeatures,
UnknownCrateType,
DefaultTypeParamUsage,
ManagedHeapMemory,
OwnedHeapMemory,
@ -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,
@ -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,
}),
];
/*

View file

@ -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 => {}
}
}
}

View file

@ -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))
}
}
}

View file

@ -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);

View file

@ -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 {

View file

@ -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)]

View file

@ -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;
@ -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));
}
let tps = path.segments
.iter()
.flat_map(|s| s.types.iter())
.map(|&a_t| ast_ty_to_ty(this, rscope, a_t))
.collect();
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 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,

View file

@ -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;
@ -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))
}
}
_ => {
@ -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()
@ -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
@ -3737,27 +3764,55 @@ 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]);
@ -3765,7 +3820,7 @@ pub fn instantiate_path(fcx: @FnCtxt,
}
_ => {}
}
result.push(fcx.to_ty(ast_type))
result.push(ty)
}
// If the self parameter goes at the end, insert it there.

View file

@ -345,7 +345,8 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, trait_id: ast::NodeId) {
bounds: @ty::ParamBounds {
builtin_bounds: ty::EmptyBuiltinBounds(),
trait_bounds: ~[self_trait_ref]
}
},
default: None
});
// add in the type parameters from the method
@ -952,10 +953,12 @@ pub fn ty_generics(ccx: &CrateCtxt,
let param_ty = ty::param_ty {idx: base_index + offset,
def_id: local_def(param.id)};
let bounds = @compute_bounds(ccx, param_ty, &param.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));

View file

@ -485,12 +485,13 @@ pub fn ty_to_str(cx: ctxt, typ: t) -> ~str {
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,
@ -506,7 +507,9 @@ pub fn ty_to_str(cx: ctxt, typ: t) -> ~str {
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 {
@ -518,7 +521,20 @@ pub fn parameterized(cx: ctxt,
}
}
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))
}
@ -969,9 +985,11 @@ impl UserString for ty::TraitRef {
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)
}
}
}

View file

@ -206,7 +206,8 @@ pub enum TyParamBound {
pub struct TyParam {
ident: Ident,
id: NodeId,
bounds: OptVec<TyParamBound>
bounds: OptVec<TyParamBound>,
default: Option<P<Ty>>
}
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]

View file

@ -66,7 +66,10 @@ pub trait AstBuilder {
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;
@ -354,8 +357,16 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
})
}
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

View file

@ -375,7 +375,7 @@ impl<'a> TraitDef<'a> {
// 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.

View file

@ -196,7 +196,7 @@ fn mk_ty_param(cx: &ExtCtxt, span: Span, name: &str, bounds: &[Path],
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 {

View file

@ -406,6 +406,7 @@ pub fn fold_ty_param<T: Folder>(tp: &TyParam, fld: &mut T) -> TyParam {
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))
}
}

View file

@ -3452,13 +3452,25 @@ impl Parser {
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
@ -3468,9 +3480,17 @@ impl Parser {
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()

View file

@ -1905,6 +1905,14 @@ pub fn print_generics(s: &mut State, generics: &ast::Generics) {
let param = generics.ty_params.get(idx);
print_ident(s, param.ident);
print_bounds(s, &param.bounds, false);
match param.default {
Some(default) => {
space(&mut s.s);
word_space(s, "=");
print_type(s, default);
}
_ => {}
}
}
}

View file

@ -470,7 +470,11 @@ pub fn walk_generics<E: Clone, V: Visitor<E>>(visitor: &mut V,
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);
}

View file

@ -0,0 +1,17 @@
// 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>;

View file

@ -29,9 +29,9 @@ impl Trait<int> for S2 {
}
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)
}

View file

@ -0,0 +1,15 @@
// 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() {}

View file

@ -0,0 +1,22 @@
// 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
}

View file

@ -0,0 +1,24 @@
// 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
}

View file

@ -0,0 +1,19 @@
// 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() {}

View file

@ -0,0 +1,19 @@
// 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
}

View file

@ -0,0 +1,19 @@
// 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
}

View file

@ -0,0 +1,34 @@
// 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 `()`
}

View file

@ -0,0 +1,23 @@
// 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() {}

View file

@ -0,0 +1,29 @@
// 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>;
}

View file

@ -0,0 +1,57 @@
// 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') });
}