auto merge of #11217 : eddyb/rust/generic-default-type-params, r=cmr
This commit is contained in:
commit
3427137f66
33 changed files with 536 additions and 78 deletions
|
@ -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) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}),
|
||||
];
|
||||
|
||||
/*
|
||||
|
|
|
@ -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 => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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, ¶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));
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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, ¶m.bounds, false);
|
||||
match param.default {
|
||||
Some(default) => {
|
||||
space(&mut s.s);
|
||||
word_space(s, "=");
|
||||
print_type(s, default);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
17
src/test/auxiliary/default_type_params_xc.rs
Normal file
17
src/test/auxiliary/default_type_params_xc.rs
Normal 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>;
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
15
src/test/compile-fail/gated-default-type-params.rs
Normal file
15
src/test/compile-fail/gated-default-type-params.rs
Normal 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() {}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
19
src/test/compile-fail/generic-non-trailing-defaults.rs
Normal file
19
src/test/compile-fail/generic-non-trailing-defaults.rs
Normal 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() {}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
34
src/test/compile-fail/generic-type-params-name-repr.rs
Normal file
34
src/test/compile-fail/generic-type-params-name-repr.rs
Normal 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 `()`
|
||||
}
|
23
src/test/compile-fail/lint-default-type-param-usage.rs
Normal file
23
src/test/compile-fail/lint-default-type-param-usage.rs
Normal 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() {}
|
29
src/test/run-pass/generic-default-type-params-cross-crate.rs
Normal file
29
src/test/run-pass/generic-default-type-params-cross-crate.rs
Normal 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>;
|
||||
}
|
57
src/test/run-pass/generic-default-type-params.rs
Normal file
57
src/test/run-pass/generic-default-type-params.rs
Normal 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') });
|
||||
}
|
Loading…
Add table
Reference in a new issue