提交 221edbae 编写于 作者: N Niko Matsakis

Support parenthesized paths `Foo(A,B) -> C` that expand to `Foo<(A,B),C>`....

Support parenthesized paths `Foo(A,B) -> C` that expand to `Foo<(A,B),C>`. These paths also bind anonymous regions (or will, once HRTB is fully working).

Fixes #18423.
上级 4e352892
...@@ -57,7 +57,6 @@ ...@@ -57,7 +57,6 @@
E0044, E0044,
E0045, E0045,
E0046, E0046,
E0047,
E0049, E0049,
E0050, E0050,
E0051, E0051,
...@@ -111,7 +110,6 @@ ...@@ -111,7 +110,6 @@
E0108, E0108,
E0109, E0109,
E0110, E0110,
E0113,
E0116, E0116,
E0117, E0117,
E0118, E0118,
...@@ -145,5 +143,6 @@ ...@@ -145,5 +143,6 @@
E0163, E0163,
E0164, E0164,
E0165, E0165,
E0166 E0166,
E0167
) )
...@@ -138,7 +138,7 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &Expr) -> bool { ...@@ -138,7 +138,7 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &Expr) -> bool {
// to handle on-demand instantiation of functions via // to handle on-demand instantiation of functions via
// foo::<bar> in a const. Currently that is only done on // foo::<bar> in a const. Currently that is only done on
// a path in trans::callee that only works in block contexts. // a path in trans::callee that only works in block contexts.
if !pth.segments.iter().all(|segment| segment.types.is_empty()) { if !pth.segments.iter().all(|segment| segment.parameters.is_empty()) {
span_err!(v.tcx.sess, e.span, E0013, span_err!(v.tcx.sess, e.span, E0013,
"paths in constants may only refer to items without \ "paths in constants may only refer to items without \
type parameters"); type parameters");
......
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
use syntax::ast::*; use syntax::ast::*;
use syntax::ast_util::{walk_pat}; use syntax::ast_util::{walk_pat};
use syntax::codemap::{Span, DUMMY_SP}; use syntax::codemap::{Span, DUMMY_SP};
use syntax::owned_slice::OwnedSlice;
pub type PatIdMap = HashMap<Ident, NodeId>; pub type PatIdMap = HashMap<Ident, NodeId>;
...@@ -133,8 +132,7 @@ pub fn def_to_path(tcx: &ty::ctxt, id: DefId) -> Path { ...@@ -133,8 +132,7 @@ pub fn def_to_path(tcx: &ty::ctxt, id: DefId) -> Path {
global: false, global: false,
segments: path.last().map(|elem| PathSegment { segments: path.last().map(|elem| PathSegment {
identifier: Ident::new(elem.name()), identifier: Ident::new(elem.name()),
lifetimes: vec!(), parameters: PathParameters::none(),
types: OwnedSlice::empty()
}).into_iter().collect(), }).into_iter().collect(),
span: DUMMY_SP, span: DUMMY_SP,
}) })
......
...@@ -27,7 +27,6 @@ ...@@ -27,7 +27,6 @@
use syntax::ast_util::{is_local, local_def, PostExpansionMethod}; use syntax::ast_util::{is_local, local_def, PostExpansionMethod};
use syntax::codemap::Span; use syntax::codemap::Span;
use syntax::parse::token; use syntax::parse::token;
use syntax::owned_slice::OwnedSlice;
use syntax::visit; use syntax::visit;
use syntax::visit::Visitor; use syntax::visit::Visitor;
...@@ -945,8 +944,7 @@ fn visit_view_item(&mut self, a: &ast::ViewItem) { ...@@ -945,8 +944,7 @@ fn visit_view_item(&mut self, a: &ast::ViewItem) {
debug!("privacy - ident item {}", id); debug!("privacy - ident item {}", id);
let seg = ast::PathSegment { let seg = ast::PathSegment {
identifier: name, identifier: name,
lifetimes: Vec::new(), parameters: ast::PathParameters::none(),
types: OwnedSlice::empty(),
}; };
let segs = vec![seg]; let segs = vec![seg];
let path = ast::Path { let path = ast::Path {
......
...@@ -4951,12 +4951,12 @@ fn resolve_type(&mut self, ty: &Ty) { ...@@ -4951,12 +4951,12 @@ fn resolve_type(&mut self, ty: &Ty) {
if path.segments if path.segments
.iter() .iter()
.any(|s| !s.lifetimes.is_empty()) { .any(|s| s.parameters.has_lifetimes()) {
span_err!(self.session, path.span, E0157, span_err!(self.session, path.span, E0157,
"lifetime parameters are not allowed on this type"); "lifetime parameters are not allowed on this type");
} else if path.segments } else if path.segments
.iter() .iter()
.any(|s| s.types.len() > 0) { .any(|s| !s.parameters.is_empty()) {
span_err!(self.session, path.span, E0153, span_err!(self.session, path.span, E0153,
"type parameters are not allowed on this type"); "type parameters are not allowed on this type");
} }
...@@ -5234,7 +5234,7 @@ struct or enum variant", ...@@ -5234,7 +5234,7 @@ struct or enum variant",
// Check the types in the path pattern. // Check the types in the path pattern.
for ty in path.segments for ty in path.segments
.iter() .iter()
.flat_map(|s| s.types.iter()) { .flat_map(|s| s.parameters.types().into_iter()) {
self.resolve_type(&**ty); self.resolve_type(&**ty);
} }
} }
...@@ -5340,7 +5340,7 @@ fn resolve_path(&mut self, ...@@ -5340,7 +5340,7 @@ fn resolve_path(&mut self,
namespace: Namespace, namespace: Namespace,
check_ribs: bool) -> Option<(Def, LastPrivate)> { check_ribs: bool) -> Option<(Def, LastPrivate)> {
// First, resolve the types. // First, resolve the types.
for ty in path.segments.iter().flat_map(|s| s.types.iter()) { for ty in path.segments.iter().flat_map(|s| s.parameters.types().into_iter()) {
self.resolve_type(&**ty); self.resolve_type(&**ty);
} }
......
...@@ -1836,11 +1836,7 @@ pub fn trans_closure(ccx: &CrateContext, ...@@ -1836,11 +1836,7 @@ pub fn trans_closure(ccx: &CrateContext,
NotUnboxedClosure => monomorphized_arg_types, NotUnboxedClosure => monomorphized_arg_types,
// Tuple up closure argument types for the "rust-call" ABI. // Tuple up closure argument types for the "rust-call" ABI.
IsUnboxedClosure => vec![if monomorphized_arg_types.is_empty() { IsUnboxedClosure => vec![ty::mk_tup_or_nil(ccx.tcx(), monomorphized_arg_types)]
ty::mk_nil()
} else {
ty::mk_tup(ccx.tcx(), monomorphized_arg_types)
}]
}; };
for monomorphized_arg_type in monomorphized_arg_types.iter() { for monomorphized_arg_type in monomorphized_arg_types.iter() {
debug!("trans_closure: monomorphized_arg_type: {}", debug!("trans_closure: monomorphized_arg_type: {}",
......
...@@ -625,7 +625,7 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr) -> ValueRef { ...@@ -625,7 +625,7 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr) -> ValueRef {
} }
ast::ExprPath(ref pth) => { ast::ExprPath(ref pth) => {
// Assert that there are no type parameters in this path. // Assert that there are no type parameters in this path.
assert!(pth.segments.iter().all(|seg| seg.types.is_empty())); assert!(pth.segments.iter().all(|seg| !seg.parameters.has_types()));
let opt_def = cx.tcx().def_map.borrow().find_copy(&e.id); let opt_def = cx.tcx().def_map.borrow().find_copy(&e.id);
match opt_def { match opt_def {
......
...@@ -1838,6 +1838,14 @@ pub fn mk_slice(cx: &ctxt, r: Region, tm: mt) -> t { ...@@ -1838,6 +1838,14 @@ pub fn mk_slice(cx: &ctxt, r: Region, tm: mt) -> t {
pub fn mk_tup(cx: &ctxt, ts: Vec<t>) -> t { mk_t(cx, ty_tup(ts)) } pub fn mk_tup(cx: &ctxt, ts: Vec<t>) -> t { mk_t(cx, ty_tup(ts)) }
pub fn mk_tup_or_nil(cx: &ctxt, ts: Vec<t>) -> t {
if ts.len() == 0 {
ty::mk_nil()
} else {
mk_t(cx, ty_tup(ts))
}
}
pub fn mk_closure(cx: &ctxt, fty: ClosureTy) -> t { pub fn mk_closure(cx: &ctxt, fty: ClosureTy) -> t {
mk_t(cx, ty_closure(box fty)) mk_t(cx, ty_closure(box fty))
} }
......
...@@ -59,7 +59,7 @@ ...@@ -59,7 +59,7 @@
use middle::ty; use middle::ty;
use middle::typeck::lookup_def_tcx; use middle::typeck::lookup_def_tcx;
use middle::typeck::infer; use middle::typeck::infer;
use middle::typeck::rscope::{UnelidableRscope, RegionScope, SpecificRscope}; use middle::typeck::rscope::{UnelidableRscope, RegionScope, SpecificRscope, BindingRscope};
use middle::typeck::rscope; use middle::typeck::rscope;
use middle::typeck::TypeAndSubsts; use middle::typeck::TypeAndSubsts;
use middle::typeck; use middle::typeck;
...@@ -207,15 +207,16 @@ pub fn opt_ast_region_to_region<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( ...@@ -207,15 +207,16 @@ pub fn opt_ast_region_to_region<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
} }
fn ast_path_substs<'tcx,AC,RS>( fn ast_path_substs<'tcx,AC,RS>(
this: &AC, this: &AC,
rscope: &RS, rscope: &RS,
decl_def_id: ast::DefId, decl_def_id: ast::DefId,
decl_generics: &ty::Generics, decl_generics: &ty::Generics,
self_ty: Option<ty::t>, self_ty: Option<ty::t>,
associated_ty: Option<ty::t>, associated_ty: Option<ty::t>,
path: &ast::Path) path: &ast::Path,
-> Substs binder_id: ast::NodeId)
where AC: AstConv<'tcx>, RS: RegionScope -> Substs
where AC: AstConv<'tcx>, RS: RegionScope
{ {
/*! /*!
* Given a path `path` that refers to an item `I` with the * Given a path `path` that refers to an item `I` with the
...@@ -236,45 +237,51 @@ fn ast_path_substs<'tcx,AC,RS>( ...@@ -236,45 +237,51 @@ fn ast_path_substs<'tcx,AC,RS>(
assert!(decl_generics.regions.all(|d| d.space == TypeSpace)); assert!(decl_generics.regions.all(|d| d.space == TypeSpace));
assert!(decl_generics.types.all(|d| d.space != FnSpace)); assert!(decl_generics.types.all(|d| d.space != FnSpace));
let (regions, types) = match path.segments.last().unwrap().parameters {
ast::AngleBracketedParameters(ref data) =>
angle_bracketed_parameters(this, rscope, data),
ast::ParenthesizedParameters(ref data) =>
parenthesized_parameters(this, binder_id, data),
};
// If the type is parameterized by the this region, then replace this // If the type is parameterized by the this region, then replace this
// region with the current anon region binding (in other words, // region with the current anon region binding (in other words,
// whatever & would get replaced with). // whatever & would get replaced with).
let expected_num_region_params = decl_generics.regions.len(TypeSpace); let expected_num_region_params = decl_generics.regions.len(TypeSpace);
let supplied_num_region_params = path.segments.last().unwrap().lifetimes.len(); let supplied_num_region_params = regions.len();
let regions = if expected_num_region_params == supplied_num_region_params { let regions = if expected_num_region_params == supplied_num_region_params {
path.segments.last().unwrap().lifetimes.iter().map( regions
|l| ast_region_to_region(this.tcx(), l)).collect::<Vec<_>>()
} else { } else {
let anon_regions = let anon_regions =
rscope.anon_regions(path.span, expected_num_region_params); rscope.anon_regions(path.span, expected_num_region_params);
if supplied_num_region_params != 0 || anon_regions.is_err() { if supplied_num_region_params != 0 || anon_regions.is_err() {
span_err!(tcx.sess, path.span, E0107, span_err!(tcx.sess, path.span, E0107,
"wrong number of lifetime parameters: expected {}, found {}", "wrong number of lifetime parameters: expected {}, found {}",
expected_num_region_params, supplied_num_region_params); expected_num_region_params, supplied_num_region_params);
} }
match anon_regions { match anon_regions {
Ok(v) => v.into_iter().collect(), Ok(v) => v.into_iter().collect(),
Err(_) => Vec::from_fn(expected_num_region_params, Err(_) => Vec::from_fn(expected_num_region_params,
|_| ty::ReStatic) // hokey |_| ty::ReStatic) // hokey
} }
}; };
// Convert the type parameters supplied by the user. // Convert the type parameters supplied by the user.
let ty_param_defs = decl_generics.types.get_slice(TypeSpace); let ty_param_defs = decl_generics.types.get_slice(TypeSpace);
let supplied_ty_param_count = path.segments.iter().flat_map(|s| s.types.iter()).count(); let supplied_ty_param_count = types.len();
let formal_ty_param_count = let formal_ty_param_count =
ty_param_defs.iter() ty_param_defs.iter()
.take_while(|x| !ty::is_associated_type(tcx, x.def_id)) .take_while(|x| !ty::is_associated_type(tcx, x.def_id))
.count(); .count();
let required_ty_param_count = let required_ty_param_count =
ty_param_defs.iter() ty_param_defs.iter()
.take_while(|x| { .take_while(|x| {
x.default.is_none() && x.default.is_none() &&
!ty::is_associated_type(tcx, x.def_id) !ty::is_associated_type(tcx, x.def_id)
}) })
.count(); .count();
if supplied_ty_param_count < required_ty_param_count { if supplied_ty_param_count < required_ty_param_count {
let expected = if required_ty_param_count < formal_ty_param_count { let expected = if required_ty_param_count < formal_ty_param_count {
"expected at least" "expected at least"
...@@ -282,10 +289,10 @@ fn ast_path_substs<'tcx,AC,RS>( ...@@ -282,10 +289,10 @@ fn ast_path_substs<'tcx,AC,RS>(
"expected" "expected"
}; };
this.tcx().sess.span_fatal(path.span, this.tcx().sess.span_fatal(path.span,
format!("wrong number of type arguments: {} {}, found {}", format!("wrong number of type arguments: {} {}, found {}",
expected, expected,
required_ty_param_count, required_ty_param_count,
supplied_ty_param_count).as_slice()); supplied_ty_param_count).as_slice());
} else if supplied_ty_param_count > formal_ty_param_count { } else if supplied_ty_param_count > formal_ty_param_count {
let expected = if required_ty_param_count < formal_ty_param_count { let expected = if required_ty_param_count < formal_ty_param_count {
"expected at most" "expected at most"
...@@ -293,10 +300,10 @@ fn ast_path_substs<'tcx,AC,RS>( ...@@ -293,10 +300,10 @@ fn ast_path_substs<'tcx,AC,RS>(
"expected" "expected"
}; };
this.tcx().sess.span_fatal(path.span, this.tcx().sess.span_fatal(path.span,
format!("wrong number of type arguments: {} {}, found {}", format!("wrong number of type arguments: {} {}, found {}",
expected, expected,
formal_ty_param_count, formal_ty_param_count,
supplied_ty_param_count).as_slice()); supplied_ty_param_count).as_slice());
} }
if supplied_ty_param_count > required_ty_param_count if supplied_ty_param_count > required_ty_param_count
...@@ -307,13 +314,7 @@ fn ast_path_substs<'tcx,AC,RS>( ...@@ -307,13 +314,7 @@ fn ast_path_substs<'tcx,AC,RS>(
"add #![feature(default_type_params)] to the crate attributes to enable"); "add #![feature(default_type_params)] to the crate attributes to enable");
} }
let tps = path.segments let mut substs = Substs::new_type(types, regions);
.iter()
.flat_map(|s| s.types.iter())
.map(|a_t| ast_ty_to_ty(this, rscope, &**a_t))
.collect();
let mut substs = Substs::new_type(tps, regions);
match self_ty { match self_ty {
None => { None => {
...@@ -354,7 +355,47 @@ fn ast_path_substs<'tcx,AC,RS>( ...@@ -354,7 +355,47 @@ fn ast_path_substs<'tcx,AC,RS>(
param.def_id)) param.def_id))
} }
substs return substs;
fn angle_bracketed_parameters<'tcx, AC, RS>(this: &AC,
rscope: &RS,
data: &ast::AngleBracketedParameterData)
-> (Vec<ty::Region>, Vec<ty::t>)
where AC: AstConv<'tcx>, RS: RegionScope
{
let regions: Vec<_> =
data.lifetimes.iter()
.map(|l| ast_region_to_region(this.tcx(), l))
.collect();
let types: Vec<_> =
data.types.iter()
.map(|t| ast_ty_to_ty(this, rscope, &**t))
.collect();
(regions, types)
}
fn parenthesized_parameters<'tcx,AC>(this: &AC,
binder_id: ast::NodeId,
data: &ast::ParenthesizedParameterData)
-> (Vec<ty::Region>, Vec<ty::t>)
where AC: AstConv<'tcx>
{
let binding_rscope = BindingRscope::new(binder_id);
let inputs = data.inputs.iter()
.map(|a_t| ast_ty_to_ty(this, &binding_rscope, &**a_t))
.collect();
let input_ty = ty::mk_tup_or_nil(this.tcx(), inputs);
let output = match data.output {
Some(ref output_ty) => ast_ty_to_ty(this, &binding_rscope, &**output_ty),
None => ty::mk_nil()
};
(Vec::new(), vec![input_ty, output])
}
} }
pub fn ast_path_to_trait_ref<'tcx,AC,RS>(this: &AC, pub fn ast_path_to_trait_ref<'tcx,AC,RS>(this: &AC,
...@@ -362,7 +403,8 @@ pub fn ast_path_to_trait_ref<'tcx,AC,RS>(this: &AC, ...@@ -362,7 +403,8 @@ pub fn ast_path_to_trait_ref<'tcx,AC,RS>(this: &AC,
trait_def_id: ast::DefId, trait_def_id: ast::DefId,
self_ty: Option<ty::t>, self_ty: Option<ty::t>,
associated_type: Option<ty::t>, associated_type: Option<ty::t>,
path: &ast::Path) path: &ast::Path,
binder_id: ast::NodeId)
-> Rc<ty::TraitRef> -> Rc<ty::TraitRef>
where AC: AstConv<'tcx>, where AC: AstConv<'tcx>,
RS: RegionScope { RS: RegionScope {
...@@ -375,7 +417,8 @@ pub fn ast_path_to_trait_ref<'tcx,AC,RS>(this: &AC, ...@@ -375,7 +417,8 @@ pub fn ast_path_to_trait_ref<'tcx,AC,RS>(this: &AC,
&trait_def.generics, &trait_def.generics,
self_ty, self_ty,
associated_type, associated_type,
path) path,
binder_id)
}) })
} }
...@@ -383,8 +426,10 @@ pub fn ast_path_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( ...@@ -383,8 +426,10 @@ pub fn ast_path_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
this: &AC, this: &AC,
rscope: &RS, rscope: &RS,
did: ast::DefId, did: ast::DefId,
path: &ast::Path) path: &ast::Path,
-> TypeAndSubsts { binder_id: ast::NodeId)
-> TypeAndSubsts
{
let tcx = this.tcx(); let tcx = this.tcx();
let ty::Polytype { let ty::Polytype {
generics, generics,
...@@ -397,7 +442,8 @@ pub fn ast_path_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( ...@@ -397,7 +442,8 @@ pub fn ast_path_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
&generics, &generics,
None, None,
None, None,
path); path,
binder_id);
let ty = decl_ty.subst(tcx, &substs); let ty = decl_ty.subst(tcx, &substs);
TypeAndSubsts { substs: substs, ty: ty } TypeAndSubsts { substs: substs, ty: ty }
} }
...@@ -407,24 +453,29 @@ pub fn ast_path_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( ...@@ -407,24 +453,29 @@ pub fn ast_path_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
/// and/or region variables are substituted. /// and/or region variables are substituted.
/// ///
/// This is used when checking the constructor in struct literals. /// This is used when checking the constructor in struct literals.
pub fn ast_path_to_ty_relaxed<'tcx, AC: AstConv<'tcx>, pub fn ast_path_to_ty_relaxed<'tcx,AC,RS>(
RS:RegionScope>( this: &AC,
this: &AC, rscope: &RS,
rscope: &RS, did: ast::DefId,
did: ast::DefId, path: &ast::Path,
path: &ast::Path) binder_id: ast::NodeId)
-> TypeAndSubsts { -> TypeAndSubsts
where AC : AstConv<'tcx>, RS : RegionScope
{
let tcx = this.tcx(); let tcx = this.tcx();
let ty::Polytype { let ty::Polytype {
generics, generics,
ty: decl_ty ty: decl_ty
} = this.get_item_ty(did); } = this.get_item_ty(did);
let substs = if (generics.has_type_params(TypeSpace) || let wants_params =
generics.has_region_params(TypeSpace)) && generics.has_type_params(TypeSpace) || generics.has_region_params(TypeSpace);
path.segments.iter().all(|s| {
s.lifetimes.len() == 0 && s.types.len() == 0 let needs_defaults =
}) { wants_params &&
path.segments.iter().all(|s| s.parameters.is_empty());
let substs = if needs_defaults {
let type_params = Vec::from_fn(generics.types.len(TypeSpace), let type_params = Vec::from_fn(generics.types.len(TypeSpace),
|_| this.ty_infer(path.span)); |_| this.ty_infer(path.span));
let region_params = let region_params =
...@@ -433,7 +484,7 @@ pub fn ast_path_to_ty_relaxed<'tcx, AC: AstConv<'tcx>, ...@@ -433,7 +484,7 @@ pub fn ast_path_to_ty_relaxed<'tcx, AC: AstConv<'tcx>,
Substs::new(VecPerParamSpace::params_from_type(type_params), Substs::new(VecPerParamSpace::params_from_type(type_params),
VecPerParamSpace::params_from_type(region_params)) VecPerParamSpace::params_from_type(region_params))
} else { } else {
ast_path_substs(this, rscope, did, &generics, None, None, path) ast_path_substs(this, rscope, did, &generics, None, None, path, binder_id)
}; };
let ty = decl_ty.subst(tcx, &substs); let ty = decl_ty.subst(tcx, &substs);
...@@ -450,14 +501,14 @@ fn check_path_args(tcx: &ty::ctxt, ...@@ -450,14 +501,14 @@ fn check_path_args(tcx: &ty::ctxt,
path: &ast::Path, path: &ast::Path,
flags: uint) { flags: uint) {
if (flags & NO_TPS) != 0u { if (flags & NO_TPS) != 0u {
if !path.segments.iter().all(|s| s.types.is_empty()) { if path.segments.iter().any(|s| s.parameters.has_types()) {
span_err!(tcx.sess, path.span, E0109, span_err!(tcx.sess, path.span, E0109,
"type parameters are not allowed on this type"); "type parameters are not allowed on this type");
} }
} }
if (flags & NO_REGIONS) != 0u { if (flags & NO_REGIONS) != 0u {
if !path.segments.last().unwrap().lifetimes.is_empty() { if path.segments.iter().any(|s| s.parameters.has_lifetimes()) {
span_err!(tcx.sess, path.span, E0110, span_err!(tcx.sess, path.span, E0110,
"region parameters are not allowed on this type"); "region parameters are not allowed on this type");
} }
...@@ -538,29 +589,23 @@ pub fn ast_ty_to_builtin_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( ...@@ -538,29 +589,23 @@ pub fn ast_ty_to_builtin_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
// FIXME(#12938): This is a hack until we have full support for // FIXME(#12938): This is a hack until we have full support for
// DST. // DST.
match a_def { match a_def {
def::DefTy(did, _) | def::DefStruct(did) def::DefTy(did, _) |
if Some(did) == this.tcx().lang_items.owned_box() => { def::DefStruct(did) if Some(did) == this.tcx().lang_items.owned_box() => {
if path.segments let ty = ast_path_to_ty(this, rscope, did, path, id).ty;
.iter() match ty::get(ty).sty {
.flat_map(|s| s.types.iter()) ty::ty_struct(struct_def_id, ref substs) => {
.count() > 1 { assert_eq!(struct_def_id, did);
span_err!(this.tcx().sess, path.span, E0047, assert_eq!(substs.types.len(TypeSpace), 1);
"`Box` has only one type parameter"); let referent_ty = *substs.types.get(TypeSpace, 0);
} Some(ty::mk_uniq(this.tcx(), referent_ty))
}
for inner_ast_type in path.segments _ => {
.iter() this.tcx().sess.span_bug(
.flat_map(|s| s.types.iter()) { path.span,
return Some(mk_pointer(this, format!("converting `Box` to `{}`",
rscope, ty.repr(this.tcx()))[]);
ast::MutImmutable, }
&**inner_ast_type,
Uniq,
|typ| ty::mk_uniq(this.tcx(), typ)));
} }
span_err!(this.tcx().sess, path.span, E0113,
"not enough type parameters supplied to `Box<T>`");
Some(ty::mk_err())
} }
_ => None _ => None
} }
...@@ -603,11 +648,7 @@ pub fn trait_ref_for_unboxed_function<'tcx, AC: AstConv<'tcx>, ...@@ -603,11 +648,7 @@ pub fn trait_ref_for_unboxed_function<'tcx, AC: AstConv<'tcx>,
.map(|input| { .map(|input| {
ast_ty_to_ty(this, rscope, &*input.ty) ast_ty_to_ty(this, rscope, &*input.ty)
}).collect::<Vec<_>>(); }).collect::<Vec<_>>();
let input_tuple = if input_types.len() == 0 { let input_tuple = ty::mk_tup_or_nil(this.tcx(), input_types);
ty::mk_nil()
} else {
ty::mk_tup(this.tcx(), input_types)
};
let output_type = ast_ty_to_ty(this, rscope, &*decl.output); let output_type = ast_ty_to_ty(this, rscope, &*decl.output);
let mut substs = Substs::new_type(vec!(input_tuple, output_type), let mut substs = Substs::new_type(vec!(input_tuple, output_type),
Vec::new()); Vec::new());
...@@ -693,7 +734,8 @@ fn mk_pointer<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( ...@@ -693,7 +734,8 @@ fn mk_pointer<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
trait_def_id, trait_def_id,
None, None,
None, None,
path); path,
id);
let bounds = match *opt_bounds { let bounds = match *opt_bounds {
None => { None => {
conv_existential_bounds(this, conv_existential_bounds(this,
...@@ -771,7 +813,12 @@ fn associated_ty_to_ty<'tcx,AC,RS>(this: &AC, ...@@ -771,7 +813,12 @@ fn associated_ty_to_ty<'tcx,AC,RS>(this: &AC,
trait_did, trait_did,
None, None,
Some(for_type), Some(for_type),
trait_path); trait_path,
ast::DUMMY_NODE_ID); // *see below
// * The trait in a qualified path cannot be "higher-ranked" and
// hence cannot use the parenthetical sugar, so the binder-id is
// irrelevant.
debug!("associated_ty_to_ty(trait_ref={})", debug!("associated_ty_to_ty(trait_ref={})",
trait_ref.repr(this.tcx())); trait_ref.repr(this.tcx()));
...@@ -925,7 +972,8 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( ...@@ -925,7 +972,8 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
trait_def_id, trait_def_id,
None, None,
None, None,
path); path,
id);
let empty_bounds: &[ast::TyParamBound] = &[]; let empty_bounds: &[ast::TyParamBound] = &[];
let ast_bounds = match *bounds { let ast_bounds = match *bounds {
Some(ref b) => b.as_slice(), Some(ref b) => b.as_slice(),
...@@ -942,7 +990,7 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( ...@@ -942,7 +990,7 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
bounds) bounds)
} }
def::DefTy(did, _) | def::DefStruct(did) => { def::DefTy(did, _) | def::DefStruct(did) => {
ast_path_to_ty(this, rscope, did, path).ty ast_path_to_ty(this, rscope, did, path, id).ty
} }
def::DefTyParam(space, id, n) => { def::DefTyParam(space, id, n) => {
check_path_args(tcx, path, NO_TPS | NO_REGIONS); check_path_args(tcx, path, NO_TPS | NO_REGIONS);
......
...@@ -3481,11 +3481,7 @@ fn check_unboxed_closure(fcx: &FnCtxt, ...@@ -3481,11 +3481,7 @@ fn check_unboxed_closure(fcx: &FnCtxt,
// Tuple up the arguments and insert the resulting function type into // Tuple up the arguments and insert the resulting function type into
// the `unboxed_closures` table. // the `unboxed_closures` table.
fn_ty.sig.inputs = if fn_ty.sig.inputs.len() == 0 { fn_ty.sig.inputs = vec![ty::mk_tup_or_nil(fcx.tcx(), fn_ty.sig.inputs)];
vec![ty::mk_nil()]
} else {
vec![ty::mk_tup(fcx.tcx(), fn_ty.sig.inputs)]
};
let kind = match kind { let kind = match kind {
ast::FnUnboxedClosureKind => ty::FnUnboxedClosureKind, ast::FnUnboxedClosureKind => ty::FnUnboxedClosureKind,
...@@ -4478,7 +4474,8 @@ fn check_struct_fields_on_error(fcx: &FnCtxt, ...@@ -4478,7 +4474,8 @@ fn check_struct_fields_on_error(fcx: &FnCtxt,
let type_and_substs = astconv::ast_path_to_ty_relaxed(fcx, let type_and_substs = astconv::ast_path_to_ty_relaxed(fcx,
fcx.infcx(), fcx.infcx(),
struct_id, struct_id,
path); path,
expr.id);
match fcx.mk_subty(false, match fcx.mk_subty(false,
infer::Misc(path.span), infer::Misc(path.span),
actual_structure_type, actual_structure_type,
...@@ -5339,6 +5336,7 @@ pub fn instantiate_path(fcx: &FnCtxt, ...@@ -5339,6 +5336,7 @@ pub fn instantiate_path(fcx: &FnCtxt,
Some(space) => { Some(space) => {
push_explicit_parameters_from_segment_to_substs(fcx, push_explicit_parameters_from_segment_to_substs(fcx,
space, space,
path.span,
type_defs, type_defs,
region_defs, region_defs,
segment, segment,
...@@ -5374,13 +5372,13 @@ fn report_error_if_segment_contains_type_parameters( ...@@ -5374,13 +5372,13 @@ fn report_error_if_segment_contains_type_parameters(
fcx: &FnCtxt, fcx: &FnCtxt,
segment: &ast::PathSegment) segment: &ast::PathSegment)
{ {
for typ in segment.types.iter() { for typ in segment.parameters.types().iter() {
span_err!(fcx.tcx().sess, typ.span, E0085, span_err!(fcx.tcx().sess, typ.span, E0085,
"type parameters may not appear here"); "type parameters may not appear here");
break; break;
} }
for lifetime in segment.lifetimes.iter() { for lifetime in segment.parameters.lifetimes().iter() {
span_err!(fcx.tcx().sess, lifetime.span, E0086, span_err!(fcx.tcx().sess, lifetime.span, E0086,
"lifetime parameters may not appear here"); "lifetime parameters may not appear here");
break; break;
...@@ -5390,6 +5388,7 @@ fn report_error_if_segment_contains_type_parameters( ...@@ -5390,6 +5388,7 @@ fn report_error_if_segment_contains_type_parameters(
fn push_explicit_parameters_from_segment_to_substs( fn push_explicit_parameters_from_segment_to_substs(
fcx: &FnCtxt, fcx: &FnCtxt,
space: subst::ParamSpace, space: subst::ParamSpace,
span: Span,
type_defs: &VecPerParamSpace<ty::TypeParameterDef>, type_defs: &VecPerParamSpace<ty::TypeParameterDef>,
region_defs: &VecPerParamSpace<ty::RegionParameterDef>, region_defs: &VecPerParamSpace<ty::RegionParameterDef>,
segment: &ast::PathSegment, segment: &ast::PathSegment,
...@@ -5412,10 +5411,31 @@ fn push_explicit_parameters_from_segment_to_substs( ...@@ -5412,10 +5411,31 @@ fn push_explicit_parameters_from_segment_to_substs(
* span of the N+1'th parameter. * span of the N+1'th parameter.
*/ */
match segment.parameters {
ast::AngleBracketedParameters(ref data) => {
push_explicit_angle_bracketed_parameters_from_segment_to_substs(
fcx, space, type_defs, region_defs, data, substs);
}
ast::ParenthesizedParameters(ref data) => {
push_explicit_parenthesized_parameters_from_segment_to_substs(
fcx, space, span, type_defs, data, substs);
}
}
}
fn push_explicit_angle_bracketed_parameters_from_segment_to_substs(
fcx: &FnCtxt,
space: subst::ParamSpace,
type_defs: &VecPerParamSpace<ty::TypeParameterDef>,
region_defs: &VecPerParamSpace<ty::RegionParameterDef>,
data: &ast::AngleBracketedParameterData,
substs: &mut Substs)
{
{ {
let type_count = type_defs.len(space); let type_count = type_defs.len(space);
assert_eq!(substs.types.len(space), 0); assert_eq!(substs.types.len(space), 0);
for (i, typ) in segment.types.iter().enumerate() { for (i, typ) in data.types.iter().enumerate() {
let t = fcx.to_ty(&**typ); let t = fcx.to_ty(&**typ);
if i < type_count { if i < type_count {
substs.types.push(space, t); substs.types.push(space, t);
...@@ -5424,7 +5444,7 @@ fn push_explicit_parameters_from_segment_to_substs( ...@@ -5424,7 +5444,7 @@ fn push_explicit_parameters_from_segment_to_substs(
"too many type parameters provided: \ "too many type parameters provided: \
expected at most {} parameter(s), \ expected at most {} parameter(s), \
found {} parameter(s)", found {} parameter(s)",
type_count, segment.types.len()); type_count, data.types.len());
substs.types.truncate(space, 0); substs.types.truncate(space, 0);
} }
} }
...@@ -5433,7 +5453,7 @@ fn push_explicit_parameters_from_segment_to_substs( ...@@ -5433,7 +5453,7 @@ fn push_explicit_parameters_from_segment_to_substs(
{ {
let region_count = region_defs.len(space); let region_count = region_defs.len(space);
assert_eq!(substs.regions().len(space), 0); assert_eq!(substs.regions().len(space), 0);
for (i, lifetime) in segment.lifetimes.iter().enumerate() { for (i, lifetime) in data.lifetimes.iter().enumerate() {
let r = ast_region_to_region(fcx.tcx(), lifetime); let r = ast_region_to_region(fcx.tcx(), lifetime);
if i < region_count { if i < region_count {
substs.mut_regions().push(space, r); substs.mut_regions().push(space, r);
...@@ -5442,13 +5462,59 @@ fn push_explicit_parameters_from_segment_to_substs( ...@@ -5442,13 +5462,59 @@ fn push_explicit_parameters_from_segment_to_substs(
"too many lifetime parameters provided: \ "too many lifetime parameters provided: \
expected {} parameter(s), found {} parameter(s)", expected {} parameter(s), found {} parameter(s)",
region_count, region_count,
segment.lifetimes.len()); data.lifetimes.len());
substs.mut_regions().truncate(space, 0); substs.mut_regions().truncate(space, 0);
} }
} }
} }
} }
fn push_explicit_parenthesized_parameters_from_segment_to_substs(
fcx: &FnCtxt,
space: subst::ParamSpace,
span: Span,
type_defs: &VecPerParamSpace<ty::TypeParameterDef>,
data: &ast::ParenthesizedParameterData,
substs: &mut Substs)
{
/*!
* As with
* `push_explicit_angle_bracketed_parameters_from_segment_to_substs`,
* but intended for `Foo(A,B) -> C` form. This expands to
* roughly the same thing as `Foo<(A,B),C>`. One important
* difference has to do with the treatment of anonymous
* regions, which are translated into bound regions (NYI).
*/
let type_count = type_defs.len(space);
if type_count < 2 {
span_err!(fcx.tcx().sess, span, E0167,
"parenthesized form always supplies 2 type parameters, \
but only {} parameter(s) were expected",
type_count);
}
let input_tys: Vec<ty::t> =
data.inputs.iter().map(|ty| fcx.to_ty(&**ty)).collect();
let tuple_ty =
ty::mk_tup_or_nil(fcx.tcx(), input_tys);
if type_count >= 1 {
substs.types.push(space, tuple_ty);
}
let output_ty: Option<ty::t> =
data.output.as_ref().map(|ty| fcx.to_ty(&**ty));
let output_ty =
output_ty.unwrap_or(ty::mk_nil());
if type_count >= 2 {
substs.types.push(space, output_ty);
}
}
fn adjust_type_parameters( fn adjust_type_parameters(
fcx: &FnCtxt, fcx: &FnCtxt,
span: Span, span: Span,
......
...@@ -1340,7 +1340,8 @@ pub fn instantiate_trait_ref<'tcx,AC>(this: &AC, ...@@ -1340,7 +1340,8 @@ pub fn instantiate_trait_ref<'tcx,AC>(this: &AC,
trait_did, trait_did,
Some(self_ty), Some(self_ty),
associated_type, associated_type,
&ast_trait_ref.path); &ast_trait_ref.path,
ast_trait_ref.ref_id);
this.tcx().trait_refs.borrow_mut().insert(ast_trait_ref.ref_id, this.tcx().trait_refs.borrow_mut().insert(ast_trait_ref.ref_id,
trait_ref.clone()); trait_ref.clone());
......
...@@ -1108,7 +1108,8 @@ fn rebuild_ty_param_bounds(&self, ...@@ -1108,7 +1108,8 @@ fn rebuild_ty_param_bounds(&self,
&ast::TraitTyParamBound(ref tr) => { &ast::TraitTyParamBound(ref tr) => {
let last_seg = tr.path.segments.last().unwrap(); let last_seg = tr.path.segments.last().unwrap();
let mut insert = Vec::new(); let mut insert = Vec::new();
for (i, lt) in last_seg.lifetimes.iter().enumerate() { let lifetimes = last_seg.parameters.lifetimes();
for (i, lt) in lifetimes.iter().enumerate() {
if region_names.contains(&lt.name) { if region_names.contains(&lt.name) {
insert.push(i); insert.push(i);
} }
...@@ -1116,7 +1117,7 @@ fn rebuild_ty_param_bounds(&self, ...@@ -1116,7 +1117,7 @@ fn rebuild_ty_param_bounds(&self,
let rebuild_info = RebuildPathInfo { let rebuild_info = RebuildPathInfo {
path: &tr.path, path: &tr.path,
indexes: insert, indexes: insert,
expected: last_seg.lifetimes.len(), expected: lifetimes.len(),
anon_nums: &HashSet::new(), anon_nums: &HashSet::new(),
region_names: region_names region_names: region_names
}; };
...@@ -1257,7 +1258,7 @@ fn rebuild_arg_ty_or_output(&self, ...@@ -1257,7 +1258,7 @@ fn rebuild_arg_ty_or_output(&self,
let expected = let expected =
generics.regions.len(subst::TypeSpace); generics.regions.len(subst::TypeSpace);
let lifetimes = let lifetimes =
&path.segments.last().unwrap().lifetimes; path.segments.last().unwrap().parameters.lifetimes();
let mut insert = Vec::new(); let mut insert = Vec::new();
if lifetimes.len() == 0 { if lifetimes.len() == 0 {
let anon = self.cur_anon.get(); let anon = self.cur_anon.get();
...@@ -1357,7 +1358,8 @@ fn build_to(from: P<ast::Ty>, ...@@ -1357,7 +1358,8 @@ fn build_to(from: P<ast::Ty>,
fn rebuild_path(&self, fn rebuild_path(&self,
rebuild_info: RebuildPathInfo, rebuild_info: RebuildPathInfo,
lifetime: ast::Lifetime) lifetime: ast::Lifetime)
-> ast::Path { -> ast::Path
{
let RebuildPathInfo { let RebuildPathInfo {
path, path,
indexes, indexes,
...@@ -1367,37 +1369,48 @@ fn rebuild_path(&self, ...@@ -1367,37 +1369,48 @@ fn rebuild_path(&self,
} = rebuild_info; } = rebuild_info;
let last_seg = path.segments.last().unwrap(); let last_seg = path.segments.last().unwrap();
let mut new_lts = Vec::new(); let new_parameters = match last_seg.parameters {
if last_seg.lifetimes.len() == 0 { ast::ParenthesizedParameters(..) => {
// traverse once to see if there's a need to insert lifetime last_seg.parameters.clone()
let need_insert = range(0, expected).any(|i| { }
indexes.contains(&i)
}); ast::AngleBracketedParameters(ref data) => {
if need_insert { let mut new_lts = Vec::new();
for i in range(0, expected) { if data.lifetimes.len() == 0 {
if indexes.contains(&i) { // traverse once to see if there's a need to insert lifetime
new_lts.push(lifetime); let need_insert = range(0, expected).any(|i| {
} else { indexes.contains(&i)
new_lts.push(self.life_giver.give_lifetime()); });
if need_insert {
for i in range(0, expected) {
if indexes.contains(&i) {
new_lts.push(lifetime);
} else {
new_lts.push(self.life_giver.give_lifetime());
}
}
} }
}
}
} else {
for (i, lt) in last_seg.lifetimes.iter().enumerate() {
if indexes.contains(&i) {
new_lts.push(lifetime);
} else { } else {
new_lts.push(*lt); for (i, lt) in data.lifetimes.iter().enumerate() {
if indexes.contains(&i) {
new_lts.push(lifetime);
} else {
new_lts.push(*lt);
}
}
} }
let new_types = data.types.map(|t| {
self.rebuild_arg_ty_or_output(&**t, lifetime, anon_nums, region_names)
});
ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
lifetimes: new_lts,
types: new_types
})
} }
} };
let new_types = last_seg.types.map(|t| {
self.rebuild_arg_ty_or_output(&**t, lifetime, anon_nums, region_names)
});
let new_seg = ast::PathSegment { let new_seg = ast::PathSegment {
identifier: last_seg.identifier, identifier: last_seg.identifier,
lifetimes: new_lts, parameters: new_parameters
types: new_types,
}; };
let mut new_segs = Vec::new(); let mut new_segs = Vec::new();
new_segs.push_all(path.segments.init()); new_segs.push_all(path.segments.init());
......
...@@ -1641,10 +1641,23 @@ pub struct PathSegment { ...@@ -1641,10 +1641,23 @@ pub struct PathSegment {
impl Clean<PathSegment> for ast::PathSegment { impl Clean<PathSegment> for ast::PathSegment {
fn clean(&self, cx: &DocContext) -> PathSegment { fn clean(&self, cx: &DocContext) -> PathSegment {
let (lifetimes, types) = match self.parameters {
ast::AngleBracketedParameters(ref data) => {
(data.lifetimes.clean(cx), data.types.clean(cx))
}
ast::ParenthesizedParameters(ref data) => {
// FIXME -- rustdoc should be taught about Foo() notation
let inputs = Tuple(data.inputs.clean(cx));
let output = data.output.as_ref().map(|t| t.clean(cx)).unwrap_or(Tuple(Vec::new()));
(Vec::new(), vec![inputs, output])
}
};
PathSegment { PathSegment {
name: self.identifier.clean(cx), name: self.identifier.clean(cx),
lifetimes: self.lifetimes.clean(cx), lifetimes: lifetimes,
types: self.types.clean(cx), types: types,
} }
} }
} }
......
...@@ -171,7 +171,7 @@ pub struct Path { ...@@ -171,7 +171,7 @@ pub struct Path {
/// module (like paths in an import). /// module (like paths in an import).
pub global: bool, pub global: bool,
/// The segments in the path: the things separated by `::`. /// The segments in the path: the things separated by `::`.
pub segments: Vec<PathSegment> , pub segments: Vec<PathSegment>,
} }
/// A segment of a path: an identifier, an optional lifetime, and a set of /// A segment of a path: an identifier, an optional lifetime, and a set of
...@@ -180,12 +180,107 @@ pub struct Path { ...@@ -180,12 +180,107 @@ pub struct Path {
pub struct PathSegment { pub struct PathSegment {
/// The identifier portion of this path segment. /// The identifier portion of this path segment.
pub identifier: Ident, pub identifier: Ident,
/// Type/lifetime parameters attached to this path. They come in
/// two flavors: `Path<A,B,C>` and `Path(A,B) -> C`. Note that
/// this is more than just simple syntactic sugar; the use of
/// parens affects the region binding rules, so we preserve the
/// distinction.
pub parameters: PathParameters,
}
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub enum PathParameters {
AngleBracketedParameters(AngleBracketedParameterData),
ParenthesizedParameters(ParenthesizedParameterData),
}
impl PathParameters {
pub fn none() -> PathParameters {
AngleBracketedParameters(AngleBracketedParameterData {
lifetimes: Vec::new(),
types: OwnedSlice::empty(),
})
}
pub fn is_empty(&self) -> bool {
match *self {
AngleBracketedParameters(ref data) => data.is_empty(),
// Even if the user supplied no types, something like
// `X()` is equivalent to `X<(),()>`.
ParenthesizedParameters(..) => false,
}
}
pub fn has_lifetimes(&self) -> bool {
match *self {
AngleBracketedParameters(ref data) => !data.lifetimes.is_empty(),
ParenthesizedParameters(_) => false,
}
}
pub fn has_types(&self) -> bool {
match *self {
AngleBracketedParameters(ref data) => !data.types.is_empty(),
ParenthesizedParameters(..) => true,
}
}
pub fn types(&self) -> Vec<&P<Ty>> {
/*!
* Returns the types that the user wrote. Note that these do not
* necessarily map to the type parameters in the parenthesized case.
*/
match *self {
AngleBracketedParameters(ref data) => {
data.types.iter().collect()
}
ParenthesizedParameters(ref data) => {
data.inputs.iter()
.chain(data.output.iter())
.collect()
}
}
}
pub fn lifetimes(&self) -> Vec<&Lifetime> {
match *self {
AngleBracketedParameters(ref data) => {
data.lifetimes.iter().collect()
}
ParenthesizedParameters(_) => {
Vec::new()
}
}
}
}
/// A path like `Foo<'a, T>`
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub struct AngleBracketedParameterData {
/// The lifetime parameters for this path segment. /// The lifetime parameters for this path segment.
pub lifetimes: Vec<Lifetime>, pub lifetimes: Vec<Lifetime>,
/// The type parameters for this path segment, if present. /// The type parameters for this path segment, if present.
pub types: OwnedSlice<P<Ty>>, pub types: OwnedSlice<P<Ty>>,
} }
impl AngleBracketedParameterData {
fn is_empty(&self) -> bool {
self.lifetimes.is_empty() && self.types.is_empty()
}
}
/// A path like `Foo(A,B) -> C`
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub struct ParenthesizedParameterData {
/// `(A,B)`
pub inputs: Vec<P<Ty>>,
/// `C`
pub output: Option<P<Ty>>,
}
pub type CrateNum = u32; pub type CrateNum = u32;
pub type NodeId = u32; pub type NodeId = u32;
......
...@@ -171,8 +171,10 @@ pub fn ident_to_path(s: Span, identifier: Ident) -> Path { ...@@ -171,8 +171,10 @@ pub fn ident_to_path(s: Span, identifier: Ident) -> Path {
segments: vec!( segments: vec!(
ast::PathSegment { ast::PathSegment {
identifier: identifier, identifier: identifier,
lifetimes: Vec::new(), parameters: ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
types: OwnedSlice::empty(), lifetimes: Vec::new(),
types: OwnedSlice::empty(),
})
} }
), ),
} }
...@@ -681,11 +683,11 @@ pub fn segments_name_eq(a : &[ast::PathSegment], b : &[ast::PathSegment]) -> boo ...@@ -681,11 +683,11 @@ pub fn segments_name_eq(a : &[ast::PathSegment], b : &[ast::PathSegment]) -> boo
false false
} else { } else {
for (idx,seg) in a.iter().enumerate() { for (idx,seg) in a.iter().enumerate() {
if (seg.identifier.name != b[idx].identifier.name) if seg.identifier.name != b[idx].identifier.name
// FIXME #7743: ident -> name problems in lifetime comparison? // FIXME #7743: ident -> name problems in lifetime comparison?
|| (seg.lifetimes != b[idx].lifetimes)
// can types contain idents? // can types contain idents?
|| (seg.types != b[idx].types) { || seg.parameters != b[idx].parameters
{
return false; return false;
} }
} }
...@@ -747,12 +749,10 @@ impl PostExpansionMethod for Method { ...@@ -747,12 +749,10 @@ impl PostExpansionMethod for Method {
mod test { mod test {
use ast::*; use ast::*;
use super::*; use super::*;
use owned_slice::OwnedSlice;
fn ident_to_segment(id : &Ident) -> PathSegment { fn ident_to_segment(id : &Ident) -> PathSegment {
PathSegment {identifier:id.clone(), PathSegment {identifier: id.clone(),
lifetimes: Vec::new(), parameters: PathParameters::none()}
types: OwnedSlice::empty()}
} }
#[test] fn idents_name_eq_test() { #[test] fn idents_name_eq_test() {
......
...@@ -313,14 +313,15 @@ fn path_all(&self, ...@@ -313,14 +313,15 @@ fn path_all(&self,
.map(|ident| { .map(|ident| {
ast::PathSegment { ast::PathSegment {
identifier: ident, identifier: ident,
lifetimes: Vec::new(), parameters: ast::PathParameters::none(),
types: OwnedSlice::empty(),
} }
}).collect(); }).collect();
segments.push(ast::PathSegment { segments.push(ast::PathSegment {
identifier: last_identifier, identifier: last_identifier,
lifetimes: lifetimes, parameters: ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
types: OwnedSlice::from_vec(types), lifetimes: lifetimes,
types: OwnedSlice::from_vec(types),
})
}); });
ast::Path { ast::Path {
span: sp, span: sp,
......
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
use codemap::Span; use codemap::Span;
use ext::base::*; use ext::base::*;
use ext::base; use ext::base;
use owned_slice::OwnedSlice;
use parse::token; use parse::token;
use parse::token::{str_to_ident}; use parse::token::{str_to_ident};
use ptr::P; use ptr::P;
...@@ -52,8 +51,7 @@ pub fn expand_syntax_ext<'cx>(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree] ...@@ -52,8 +51,7 @@ pub fn expand_syntax_ext<'cx>(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]
segments: vec!( segments: vec!(
ast::PathSegment { ast::PathSegment {
identifier: res, identifier: res,
lifetimes: Vec::new(), parameters: ast::PathParameters::none(),
types: OwnedSlice::empty(),
} }
) )
} }
......
...@@ -166,6 +166,22 @@ fn fold_path(&mut self, p: Path) -> Path { ...@@ -166,6 +166,22 @@ fn fold_path(&mut self, p: Path) -> Path {
noop_fold_path(p, self) noop_fold_path(p, self)
} }
fn fold_path_parameters(&mut self, p: PathParameters) -> PathParameters {
noop_fold_path_parameters(p, self)
}
fn fold_angle_bracketed_parameter_data(&mut self, p: AngleBracketedParameterData)
-> AngleBracketedParameterData
{
noop_fold_angle_bracketed_parameter_data(p, self)
}
fn fold_parenthesized_parameter_data(&mut self, p: ParenthesizedParameterData)
-> ParenthesizedParameterData
{
noop_fold_parenthesized_parameter_data(p, self)
}
fn fold_local(&mut self, l: P<Local>) -> P<Local> { fn fold_local(&mut self, l: P<Local>) -> P<Local> {
noop_fold_local(l, self) noop_fold_local(l, self)
} }
...@@ -480,15 +496,43 @@ pub fn noop_fold_uint<T: Folder>(i: uint, _: &mut T) -> uint { ...@@ -480,15 +496,43 @@ pub fn noop_fold_uint<T: Folder>(i: uint, _: &mut T) -> uint {
pub fn noop_fold_path<T: Folder>(Path {global, segments, span}: Path, fld: &mut T) -> Path { pub fn noop_fold_path<T: Folder>(Path {global, segments, span}: Path, fld: &mut T) -> Path {
Path { Path {
global: global, global: global,
segments: segments.move_map(|PathSegment {identifier, lifetimes, types}| PathSegment { segments: segments.move_map(|PathSegment {identifier, parameters}| PathSegment {
identifier: fld.fold_ident(identifier), identifier: fld.fold_ident(identifier),
lifetimes: fld.fold_lifetimes(lifetimes), parameters: fld.fold_path_parameters(parameters),
types: types.move_map(|typ| fld.fold_ty(typ)),
}), }),
span: fld.new_span(span) span: fld.new_span(span)
} }
} }
pub fn noop_fold_path_parameters<T: Folder>(path_parameters: PathParameters, fld: &mut T)
-> PathParameters
{
match path_parameters {
AngleBracketedParameters(data) =>
AngleBracketedParameters(fld.fold_angle_bracketed_parameter_data(data)),
ParenthesizedParameters(data) =>
ParenthesizedParameters(fld.fold_parenthesized_parameter_data(data)),
}
}
pub fn noop_fold_angle_bracketed_parameter_data<T: Folder>(data: AngleBracketedParameterData,
fld: &mut T)
-> AngleBracketedParameterData
{
let AngleBracketedParameterData { lifetimes, types } = data;
AngleBracketedParameterData { lifetimes: fld.fold_lifetimes(lifetimes),
types: types.move_map(|ty| fld.fold_ty(ty)) }
}
pub fn noop_fold_parenthesized_parameter_data<T: Folder>(data: ParenthesizedParameterData,
fld: &mut T)
-> ParenthesizedParameterData
{
let ParenthesizedParameterData { inputs, output } = data;
ParenthesizedParameterData { inputs: inputs.move_map(|ty| fld.fold_ty(ty)),
output: output.map(|ty| fld.fold_ty(ty)) }
}
pub fn noop_fold_local<T: Folder>(l: P<Local>, fld: &mut T) -> P<Local> { pub fn noop_fold_local<T: Folder>(l: P<Local>, fld: &mut T) -> P<Local> {
l.map(|Local {id, pat, ty, init, source, span}| Local { l.map(|Local {id, pat, ty, init, source, span}| Local {
id: fld.new_id(id), id: fld.new_id(id),
......
...@@ -749,8 +749,7 @@ fn sp(a: u32, b: u32) -> Span { ...@@ -749,8 +749,7 @@ fn sp(a: u32, b: u32) -> Span {
segments: vec!( segments: vec!(
ast::PathSegment { ast::PathSegment {
identifier: str_to_ident("a"), identifier: str_to_ident("a"),
lifetimes: Vec::new(), parameters: ast::PathParameters::none(),
types: OwnedSlice::empty(),
} }
), ),
}), }),
...@@ -768,13 +767,11 @@ fn sp(a: u32, b: u32) -> Span { ...@@ -768,13 +767,11 @@ fn sp(a: u32, b: u32) -> Span {
segments: vec!( segments: vec!(
ast::PathSegment { ast::PathSegment {
identifier: str_to_ident("a"), identifier: str_to_ident("a"),
lifetimes: Vec::new(), parameters: ast::PathParameters::none(),
types: OwnedSlice::empty(),
}, },
ast::PathSegment { ast::PathSegment {
identifier: str_to_ident("b"), identifier: str_to_ident("b"),
lifetimes: Vec::new(), parameters: ast::PathParameters::none(),
types: OwnedSlice::empty(),
} }
) )
}), }),
...@@ -952,8 +949,7 @@ fn string_to_tts_1 () { ...@@ -952,8 +949,7 @@ fn string_to_tts_1 () {
segments: vec!( segments: vec!(
ast::PathSegment { ast::PathSegment {
identifier: str_to_ident("d"), identifier: str_to_ident("d"),
lifetimes: Vec::new(), parameters: ast::PathParameters::none(),
types: OwnedSlice::empty(),
} }
), ),
}), }),
...@@ -974,8 +970,7 @@ fn string_to_tts_1 () { ...@@ -974,8 +970,7 @@ fn string_to_tts_1 () {
segments: vec!( segments: vec!(
ast::PathSegment { ast::PathSegment {
identifier: str_to_ident("b"), identifier: str_to_ident("b"),
lifetimes: Vec::new(), parameters: ast::PathParameters::none(),
types: OwnedSlice::empty(),
} }
), ),
}), }),
...@@ -1022,8 +1017,7 @@ fn parser_done(p: Parser){ ...@@ -1022,8 +1017,7 @@ fn parser_done(p: Parser){
ast::PathSegment { ast::PathSegment {
identifier: identifier:
str_to_ident("int"), str_to_ident("int"),
lifetimes: Vec::new(), parameters: ast::PathParameters::none(),
types: OwnedSlice::empty(),
} }
), ),
}, None, ast::DUMMY_NODE_ID), }, None, ast::DUMMY_NODE_ID),
...@@ -1072,10 +1066,8 @@ fn parser_done(p: Parser){ ...@@ -1072,10 +1066,8 @@ fn parser_done(p: Parser){
identifier: identifier:
str_to_ident( str_to_ident(
"b"), "b"),
lifetimes: parameters:
Vec::new(), ast::PathParameters::none(),
types:
OwnedSlice::empty()
} }
), ),
}), }),
......
...@@ -1487,9 +1487,9 @@ pub fn parse_ty(&mut self, plus_allowed: bool) -> P<Ty> { ...@@ -1487,9 +1487,9 @@ pub fn parse_ty(&mut self, plus_allowed: bool) -> P<Ty> {
trait_name: trait_name.path, trait_name: trait_name.path,
item_name: item_name, item_name: item_name,
})) }))
} else if self.token == token::ModSep } else if self.token == token::ModSep ||
|| self.token.is_ident() self.token.is_ident() ||
|| self.token.is_path() { self.token.is_path() {
// NAMED TYPE // NAMED TYPE
let mode = if plus_allowed { let mode = if plus_allowed {
LifetimeAndTypesAndBounds LifetimeAndTypesAndBounds
...@@ -1771,27 +1771,36 @@ pub fn parse_path_segments_without_colons(&mut self) -> Vec<ast::PathSegment> { ...@@ -1771,27 +1771,36 @@ pub fn parse_path_segments_without_colons(&mut self) -> Vec<ast::PathSegment> {
let identifier = self.parse_ident(); let identifier = self.parse_ident();
// Parse types, optionally. // Parse types, optionally.
let (lifetimes, types) = if self.eat_lt(false) { let parameters = if self.eat_lt(false) {
self.parse_generic_values_after_lt() let (lifetimes, types) = self.parse_generic_values_after_lt();
} else if false && self.eat(&token::LParen) {
let mut types = self.parse_seq_to_end( ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
&token::RParen, lifetimes: lifetimes,
types: OwnedSlice::from_vec(types),
})
} else if self.eat(&token::OpenDelim(token::Paren)) {
let inputs = self.parse_seq_to_end(
&token::CloseDelim(token::Paren),
seq_sep_trailing_allowed(token::Comma), seq_sep_trailing_allowed(token::Comma),
|p| p.parse_ty(true)); |p| p.parse_ty(true));
if self.eat(&token::RArrow) { let output_ty = if self.eat(&token::RArrow) {
types.push(self.parse_ty(true)) Some(self.parse_ty(true))
} } else {
None
};
(Vec::new(), types) ast::ParenthesizedParameters(ast::ParenthesizedParameterData {
inputs: inputs,
output: output_ty
})
} else { } else {
(Vec::new(), Vec::new()) ast::PathParameters::none()
}; };
// Assemble and push the result. // Assemble and push the result.
segments.push(ast::PathSegment { identifier: identifier, segments.push(ast::PathSegment { identifier: identifier,
lifetimes: lifetimes, parameters: parameters });
types: OwnedSlice::from_vec(types), });
// Continue only if we see a `::` // Continue only if we see a `::`
if !self.eat(&token::ModSep) { if !self.eat(&token::ModSep) {
...@@ -1810,9 +1819,13 @@ pub fn parse_path_segments_with_colons(&mut self) -> Vec<ast::PathSegment> { ...@@ -1810,9 +1819,13 @@ pub fn parse_path_segments_with_colons(&mut self) -> Vec<ast::PathSegment> {
// If we do not see a `::`, stop. // If we do not see a `::`, stop.
if !self.eat(&token::ModSep) { if !self.eat(&token::ModSep) {
segments.push(ast::PathSegment { identifier: identifier, segments.push(ast::PathSegment {
lifetimes: Vec::new(), identifier: identifier,
types: OwnedSlice::empty() }); parameters: ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
lifetimes: Vec::new(),
types: OwnedSlice::empty(),
})
});
return segments; return segments;
} }
...@@ -1820,9 +1833,13 @@ pub fn parse_path_segments_with_colons(&mut self) -> Vec<ast::PathSegment> { ...@@ -1820,9 +1833,13 @@ pub fn parse_path_segments_with_colons(&mut self) -> Vec<ast::PathSegment> {
if self.eat_lt(false) { if self.eat_lt(false) {
// Consumed `a::b::<`, go look for types // Consumed `a::b::<`, go look for types
let (lifetimes, types) = self.parse_generic_values_after_lt(); let (lifetimes, types) = self.parse_generic_values_after_lt();
segments.push(ast::PathSegment { identifier: identifier, segments.push(ast::PathSegment {
lifetimes: lifetimes, identifier: identifier,
types: OwnedSlice::from_vec(types) }); parameters: ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
lifetimes: lifetimes,
types: OwnedSlice::from_vec(types),
}),
});
// Consumed `a::b::<T,U>`, check for `::` before proceeding // Consumed `a::b::<T,U>`, check for `::` before proceeding
if !self.eat(&token::ModSep) { if !self.eat(&token::ModSep) {
...@@ -1830,9 +1847,10 @@ pub fn parse_path_segments_with_colons(&mut self) -> Vec<ast::PathSegment> { ...@@ -1830,9 +1847,10 @@ pub fn parse_path_segments_with_colons(&mut self) -> Vec<ast::PathSegment> {
} }
} else { } else {
// Consumed `a::`, go look for `b` // Consumed `a::`, go look for `b`
segments.push(ast::PathSegment { identifier: identifier, segments.push(ast::PathSegment {
lifetimes: Vec::new(), identifier: identifier,
types: OwnedSlice::empty() }); parameters: ast::PathParameters::none(),
});
} }
} }
} }
...@@ -1847,9 +1865,10 @@ pub fn parse_path_segments_without_types(&mut self) -> Vec<ast::PathSegment> { ...@@ -1847,9 +1865,10 @@ pub fn parse_path_segments_without_types(&mut self) -> Vec<ast::PathSegment> {
let identifier = self.parse_ident(); let identifier = self.parse_ident();
// Assemble and push the result. // Assemble and push the result.
segments.push(ast::PathSegment { identifier: identifier, segments.push(ast::PathSegment {
lifetimes: Vec::new(), identifier: identifier,
types: OwnedSlice::empty(), }); parameters: ast::PathParameters::none()
});
// If we do not see a `::`, stop. // If we do not see a `::`, stop.
if !self.eat(&token::ModSep) { if !self.eat(&token::ModSep) {
...@@ -3455,13 +3474,9 @@ pub fn parse_pat(&mut self) -> P<Pat> { ...@@ -3455,13 +3474,9 @@ pub fn parse_pat(&mut self) -> P<Pat> {
}, },
_ => { _ => {
if !enum_path.global && if !enum_path.global &&
enum_path.segments.len() == 1 && enum_path.segments.len() == 1 &&
enum_path.segments[0] enum_path.segments[0].parameters.is_empty()
.lifetimes {
.len() == 0 &&
enum_path.segments[0]
.types
.len() == 0 {
// it could still be either an enum // it could still be either an enum
// or an identifier pattern, resolve // or an identifier pattern, resolve
// will sort it out: // will sort it out:
...@@ -3960,8 +3975,7 @@ fn parse_ty_param_bounds(&mut self) ...@@ -3960,8 +3975,7 @@ fn parse_ty_param_bounds(&mut self)
fn trait_ref_from_ident(ident: Ident, span: Span) -> ast::TraitRef { fn trait_ref_from_ident(ident: Ident, span: Span) -> ast::TraitRef {
let segment = ast::PathSegment { let segment = ast::PathSegment {
identifier: ident, identifier: ident,
lifetimes: Vec::new(), parameters: ast::PathParameters::none()
types: OwnedSlice::empty(),
}; };
let path = ast::Path { let path = ast::Path {
span: span, span: span,
...@@ -5677,8 +5691,7 @@ fn parse_view_path(&mut self) -> P<ViewPath> { ...@@ -5677,8 +5691,7 @@ fn parse_view_path(&mut self) -> P<ViewPath> {
segments: path.into_iter().map(|identifier| { segments: path.into_iter().map(|identifier| {
ast::PathSegment { ast::PathSegment {
identifier: identifier, identifier: identifier,
lifetimes: Vec::new(), parameters: ast::PathParameters::none(),
types: OwnedSlice::empty(),
} }
}).collect() }).collect()
}; };
...@@ -5712,8 +5725,7 @@ fn parse_view_path(&mut self) -> P<ViewPath> { ...@@ -5712,8 +5725,7 @@ fn parse_view_path(&mut self) -> P<ViewPath> {
segments: path.into_iter().map(|identifier| { segments: path.into_iter().map(|identifier| {
ast::PathSegment { ast::PathSegment {
identifier: identifier, identifier: identifier,
lifetimes: Vec::new(), parameters: ast::PathParameters::none(),
types: OwnedSlice::empty(),
} }
}).collect() }).collect()
}; };
...@@ -5730,8 +5742,7 @@ fn parse_view_path(&mut self) -> P<ViewPath> { ...@@ -5730,8 +5742,7 @@ fn parse_view_path(&mut self) -> P<ViewPath> {
segments: path.into_iter().map(|identifier| { segments: path.into_iter().map(|identifier| {
ast::PathSegment { ast::PathSegment {
identifier: identifier, identifier: identifier,
lifetimes: Vec::new(), parameters: ast::PathParameters::none(),
types: OwnedSlice::empty(),
} }
}).collect() }).collect()
}; };
...@@ -5752,8 +5763,7 @@ fn parse_view_path(&mut self) -> P<ViewPath> { ...@@ -5752,8 +5763,7 @@ fn parse_view_path(&mut self) -> P<ViewPath> {
segments: path.into_iter().map(|identifier| { segments: path.into_iter().map(|identifier| {
ast::PathSegment { ast::PathSegment {
identifier: identifier, identifier: identifier,
lifetimes: Vec::new(), parameters: ast::PathParameters::none(),
types: OwnedSlice::empty(),
} }
}).collect() }).collect()
}; };
......
...@@ -1995,14 +1995,34 @@ fn print_path_(&mut self, ...@@ -1995,14 +1995,34 @@ fn print_path_(&mut self,
try!(self.print_ident(segment.identifier)); try!(self.print_ident(segment.identifier));
if !segment.lifetimes.is_empty() || !segment.types.is_empty() { try!(self.print_path_parameters(&segment.parameters, colons_before_params));
if colons_before_params { }
try!(word(&mut self.s, "::"))
} match *opt_bounds {
None => Ok(()),
Some(ref bounds) => self.print_bounds("+", bounds)
}
}
fn print_path_parameters(&mut self,
parameters: &ast::PathParameters,
colons_before_params: bool)
-> IoResult<()>
{
if parameters.is_empty() {
return Ok(());
}
if colons_before_params {
try!(word(&mut self.s, "::"))
}
match *parameters {
ast::AngleBracketedParameters(ref data) => {
try!(word(&mut self.s, "<")); try!(word(&mut self.s, "<"));
let mut comma = false; let mut comma = false;
for lifetime in segment.lifetimes.iter() { for lifetime in data.lifetimes.iter() {
if comma { if comma {
try!(self.word_space(",")) try!(self.word_space(","))
} }
...@@ -2010,24 +2030,38 @@ fn print_path_(&mut self, ...@@ -2010,24 +2030,38 @@ fn print_path_(&mut self,
comma = true; comma = true;
} }
if !segment.types.is_empty() { if !data.types.is_empty() {
if comma { if comma {
try!(self.word_space(",")) try!(self.word_space(","))
} }
try!(self.commasep( try!(self.commasep(
Inconsistent, Inconsistent,
segment.types.as_slice(), data.types.as_slice(),
|s, ty| s.print_type(&**ty))); |s, ty| s.print_type(&**ty)));
} }
try!(word(&mut self.s, ">")) try!(word(&mut self.s, ">"))
} }
}
match *opt_bounds { ast::ParenthesizedParameters(ref data) => {
None => Ok(()), try!(word(&mut self.s, "("));
Some(ref bounds) => self.print_bounds("+", bounds) try!(self.commasep(
Inconsistent,
data.inputs.as_slice(),
|s, ty| s.print_type(&**ty)));
try!(word(&mut self.s, ")"));
match data.output {
None => { }
Some(ref ty) => {
try!(self.word_space("->"));
try!(self.print_type(&**ty));
}
}
}
} }
Ok(())
} }
fn print_path(&mut self, path: &ast::Path, fn print_path(&mut self, path: &ast::Path,
......
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
use codemap; use codemap;
use fold::Folder; use fold::Folder;
use fold; use fold;
use owned_slice::OwnedSlice;
use parse::token::InternedString; use parse::token::InternedString;
use parse::token::special_idents; use parse::token::special_idents;
use parse::token; use parse::token;
...@@ -181,13 +180,11 @@ fn fold_mod(&mut self, ast::Mod {inner, view_items, items}: ast::Mod) -> ast::Mo ...@@ -181,13 +180,11 @@ fn fold_mod(&mut self, ast::Mod {inner, view_items, items}: ast::Mod) -> ast::Mo
segments: vec!( segments: vec!(
ast::PathSegment { ast::PathSegment {
identifier: token::str_to_ident("std"), identifier: token::str_to_ident("std"),
lifetimes: Vec::new(), parameters: ast::PathParameters::none(),
types: OwnedSlice::empty(),
}, },
ast::PathSegment { ast::PathSegment {
identifier: token::str_to_ident("prelude"), identifier: token::str_to_ident("prelude"),
lifetimes: Vec::new(), parameters: ast::PathParameters::none(),
types: OwnedSlice::empty(),
}), }),
}; };
......
...@@ -453,8 +453,7 @@ fn path_node(ids: Vec<ast::Ident> ) -> ast::Path { ...@@ -453,8 +453,7 @@ fn path_node(ids: Vec<ast::Ident> ) -> ast::Path {
global: false, global: false,
segments: ids.into_iter().map(|identifier| ast::PathSegment { segments: ids.into_iter().map(|identifier| ast::PathSegment {
identifier: identifier, identifier: identifier,
lifetimes: Vec::new(), parameters: ast::PathParameters::none(),
types: OwnedSlice::empty(),
}).collect() }).collect()
} }
} }
......
...@@ -407,11 +407,23 @@ pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path) { ...@@ -407,11 +407,23 @@ pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path) {
for segment in path.segments.iter() { for segment in path.segments.iter() {
visitor.visit_ident(path.span, segment.identifier); visitor.visit_ident(path.span, segment.identifier);
for typ in segment.types.iter() { match segment.parameters {
visitor.visit_ty(&**typ); ast::AngleBracketedParameters(ref data) => {
} for typ in data.types.iter() {
for lifetime in segment.lifetimes.iter() { visitor.visit_ty(&**typ);
visitor.visit_lifetime_ref(lifetime); }
for lifetime in data.lifetimes.iter() {
visitor.visit_lifetime_ref(lifetime);
}
}
ast::ParenthesizedParameters(ref data) => {
for typ in data.inputs.iter() {
visitor.visit_ty(&**typ);
}
for typ in data.output.iter() {
visitor.visit_ty(&**typ);
}
}
} }
} }
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
fn fn1(0: Box) {} //~ ERROR: not enough type parameters supplied to `Box<T>` fn fn1(0: Box) {} //~ ERROR: wrong number of type arguments: expected 1, found 0
fn main() {} fn main() {}
// 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.
// Test that `Box` cannot be used with a lifetime parameter.
struct Foo<'a> {
x: Box<'a, int> //~ ERROR wrong number of lifetime parameters
}
pub fn main() {
}
// 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.
// Test interaction between unboxed closure sugar and default type
// parameters (should be exactly as if angle brackets were used).
#![feature(default_type_params)]
#![allow(dead_code)]
struct Foo<T,U,V=T> {
t: T, u: U
}
trait Eq<X> { }
impl<X> Eq<X> for X { }
fn eq<A,B:Eq<A>>() { }
fn test<'a,'b>() {
// Parens are equivalent to omitting default in angle.
eq::< Foo<(int,),()>, Foo(int) >();
// In angle version, we supply something other than the default
eq::< Foo<(int,),(),int>, Foo(int) >();
//~^ ERROR not implemented
// Supply default explicitly.
eq::< Foo<(int,),(),(int,)>, Foo(int) >();
}
fn main() { }
// 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.
// Test that the unboxed closure sugar can be used with an arbitrary
// struct type and that it is equivalent to the same syntax using
// angle brackets. This test covers only simple types and in
// particular doesn't test bound regions.
#![allow(dead_code)]
struct Foo<T,U> {
t: T, u: U
}
trait Eq<X> { }
impl<X> Eq<X> for X { }
fn eq<A,B:Eq<A>>() { }
fn test<'a,'b>() {
// No errors expected:
eq::< Foo<(),()>, Foo() >();
eq::< Foo<(int,),()>, Foo(int) >();
eq::< Foo<(int,uint),()>, Foo(int,uint) >();
eq::< Foo<(int,uint),uint>, Foo(int,uint) -> uint >();
eq::< Foo<(&'a int,&'b uint),uint>, Foo(&'a int,&'b uint) -> uint >();
// Errors expected:
eq::< Foo<(),()>, Foo(char) >();
//~^ ERROR not implemented
}
fn main() { }
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
fn f<F:Nonexist(int) -> int>(x: F) {} //~ ERROR unresolved trait fn f<F:Nonexist(int) -> int>(x: F) {} //~ ERROR nonexistent trait `Nonexist`
type Typedef = int; type Typedef = int;
......
// 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.
// Test interaction between unboxed closure sugar and region
// parameters (should be exactly as if angle brackets were used
// and regions omitted).
#![feature(default_type_params)]
#![allow(dead_code)]
use std::kinds::marker;
struct Foo<'a,T,U> {
t: T,
u: U,
m: marker::InvariantLifetime<'a>
}
trait Eq<X> { }
impl<X> Eq<X> for X { }
fn eq<A,B:Eq<A>>() { }
fn same_type<A,B:Eq<A>>(a: A, b: B) { }
fn test<'a,'b>() {
// Parens are equivalent to omitting default in angle.
eq::< Foo<(int,),()>, Foo(int) >();
// Here we specify 'static explicitly in angle-bracket version.
// Parenthesized winds up getting inferred.
eq::< Foo<'static, (int,),()>, Foo(int) >();
}
fn test2(x: Foo<(int,),()>, y: Foo(int)) {
// Here, the omitted lifetimes are expanded to distinct things.
same_type(x, y) //~ ERROR cannot infer
}
fn main() { }
// 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 One<A>;
fn foo(_: One()) //~ ERROR wrong number of type arguments
{}
fn main() { }
// 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 Three<A,B,C>;
fn foo(_: Three()) //~ ERROR wrong number of type arguments
{}
fn main() { }
// 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 Zero;
fn foo(_: Zero()) //~ ERROR wrong number of type arguments
{}
fn main() { }
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
trait Trait {} trait Trait {}
fn f<F:Trait(int) -> int>(x: F) {} fn f<F:Trait(int) -> int>(x: F) {}
//~^ ERROR unboxed function trait must be one of `Fn`, `FnMut`, or `FnOnce` //~^ ERROR wrong number of type arguments: expected 0, found 2
fn main() {} fn main() {}
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
#![feature(unboxed_closures, unboxed_closure_sugar)] #![feature(unboxed_closures, unboxed_closure_sugar)]
fn main() { fn main() {
let task: Box<|: int| -> int> = box |: x| x; let task: Box<FnOnce(int) -> int> = box |: x| x;
task.call_once((0i, )); task.call_once((0i, ));
} }
// 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.
// Test that the unboxed closure sugar can be used with an arbitrary
// struct type and that it is equivalent to the same syntax using
// angle brackets. This test covers only simple types and in
// particular doesn't test bound regions.
#![allow(dead_code)]
struct Foo<T,U> {
t: T, u: U
}
trait Eq<X> { }
impl<X> Eq<X> for X { }
fn eq<A,B:Eq<A>>() { }
fn test<'a,'b>() {
eq::< Foo<(),()>, Foo() >();
eq::< Foo<(int,),()>, Foo(int) >();
eq::< Foo<(int,uint),()>, Foo(int,uint) >();
eq::< Foo<(int,uint),uint>, Foo(int,uint) -> uint >();
eq::< Foo<(&'a int,&'b uint),uint>, Foo(&'a int,&'b uint) -> uint >();
}
fn main() { }
// 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.
// Test unboxed closure sugar used in object types.
#![allow(dead_code)]
struct Foo<T,U> {
t: T, u: U
}
trait Getter<A,R> {
fn get(&self, arg: A) -> R;
}
struct Identity;
impl<X> Getter<X,X> for Identity {
fn get(&self, arg: X) -> X {
arg
}
}
fn main() {
let x: &Getter(int) -> (int,) = &Identity;
let (y,) = x.get((22,));
assert_eq!(y, 22);
}
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
use std::ops::FnOnce; use std::ops::FnOnce;
fn main() { fn main() {
let task: Box<|: int| -> int> = box |: x| x; let task: Box<FnOnce(int) -> int> = box |: x| x;
assert!(task.call_once((1234i,)) == 1234i); assert!(task.call_once((1234i,)) == 1234i);
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册