diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index c4e213790880f894c7269dd3190f03204e339326..d5e9c1ef99f111f160310b936b5713de02a886d0 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -57,7 +57,6 @@ E0044, E0045, E0046, - E0047, E0049, E0050, E0051, @@ -111,7 +110,6 @@ E0108, E0109, E0110, - E0113, E0116, E0117, E0118, @@ -145,5 +143,6 @@ E0163, E0164, E0165, - E0166 + E0166, + E0167 ) diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index 6cf1a93b40b7b85d52eeb276653c1d1ce019646a..2838456630367e53b5d76f4459582dde9a509ecd 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -138,7 +138,7 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &Expr) -> bool { // to handle on-demand instantiation of functions via // foo:: in a const. Currently that is only done on // 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, "paths in constants may only refer to items without \ type parameters"); diff --git a/src/librustc/middle/pat_util.rs b/src/librustc/middle/pat_util.rs index 357f4cdf0ebcf464799a589d58539d5dd224f095..f1d8c550d04fa9d5ab859e6edf5e8d93fac07bcd 100644 --- a/src/librustc/middle/pat_util.rs +++ b/src/librustc/middle/pat_util.rs @@ -16,7 +16,6 @@ use syntax::ast::*; use syntax::ast_util::{walk_pat}; use syntax::codemap::{Span, DUMMY_SP}; -use syntax::owned_slice::OwnedSlice; pub type PatIdMap = HashMap; @@ -133,8 +132,7 @@ pub fn def_to_path(tcx: &ty::ctxt, id: DefId) -> Path { global: false, segments: path.last().map(|elem| PathSegment { identifier: Ident::new(elem.name()), - lifetimes: vec!(), - types: OwnedSlice::empty() + parameters: PathParameters::none(), }).into_iter().collect(), span: DUMMY_SP, }) diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 4fbffa2a819d55f9b4a74b751d05f73293d6d3c2..7124488f7c1661033b7eadb011616d5dfe2f2a2f 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -27,7 +27,6 @@ use syntax::ast_util::{is_local, local_def, PostExpansionMethod}; use syntax::codemap::Span; use syntax::parse::token; -use syntax::owned_slice::OwnedSlice; use syntax::visit; use syntax::visit::Visitor; @@ -945,8 +944,7 @@ fn visit_view_item(&mut self, a: &ast::ViewItem) { debug!("privacy - ident item {}", id); let seg = ast::PathSegment { identifier: name, - lifetimes: Vec::new(), - types: OwnedSlice::empty(), + parameters: ast::PathParameters::none(), }; let segs = vec![seg]; let path = ast::Path { diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index ed7d9296c701d2db5773998767ba2c3727a32677..34f0cb7c19823f26e87e0f4ef453ff24e0deb39b 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -4951,12 +4951,12 @@ fn resolve_type(&mut self, ty: &Ty) { if path.segments .iter() - .any(|s| !s.lifetimes.is_empty()) { + .any(|s| s.parameters.has_lifetimes()) { span_err!(self.session, path.span, E0157, "lifetime parameters are not allowed on this type"); } else if path.segments .iter() - .any(|s| s.types.len() > 0) { + .any(|s| !s.parameters.is_empty()) { span_err!(self.session, path.span, E0153, "type parameters are not allowed on this type"); } @@ -5234,7 +5234,7 @@ struct or enum variant", // Check the types in the path pattern. for ty in path.segments .iter() - .flat_map(|s| s.types.iter()) { + .flat_map(|s| s.parameters.types().into_iter()) { self.resolve_type(&**ty); } } @@ -5340,7 +5340,7 @@ fn resolve_path(&mut self, namespace: Namespace, check_ribs: bool) -> Option<(Def, LastPrivate)> { // 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); } diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index b80425e7ac85568be16c1d7a96a4338418b59b45..c73268317bdc1c5aa01cba87b4fc1d431f914475 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -1836,11 +1836,7 @@ pub fn trans_closure(ccx: &CrateContext, NotUnboxedClosure => monomorphized_arg_types, // Tuple up closure argument types for the "rust-call" ABI. - IsUnboxedClosure => vec![if monomorphized_arg_types.is_empty() { - ty::mk_nil() - } else { - ty::mk_tup(ccx.tcx(), monomorphized_arg_types) - }] + IsUnboxedClosure => vec![ty::mk_tup_or_nil(ccx.tcx(), monomorphized_arg_types)] }; for monomorphized_arg_type in monomorphized_arg_types.iter() { debug!("trans_closure: monomorphized_arg_type: {}", diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index 6ba6ff6fb2113ea4023d1d2037f82372159ab50d..bd43aa47906e6d35fd1e71b64a5092c3056f43c8 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -625,7 +625,7 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr) -> ValueRef { } ast::ExprPath(ref pth) => { // 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); match opt_def { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 76caa42b850230ef07a398c1fd8bda8d9161a54a..9c717b98f35de4a50ad9a1d5e8fe023c06fd87cf 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1838,6 +1838,14 @@ pub fn mk_slice(cx: &ctxt, r: Region, tm: mt) -> t { pub fn mk_tup(cx: &ctxt, ts: Vec) -> t { mk_t(cx, ty_tup(ts)) } +pub fn mk_tup_or_nil(cx: &ctxt, ts: Vec) -> t { + if ts.len() == 0 { + ty::mk_nil() + } else { + mk_t(cx, ty_tup(ts)) + } +} + pub fn mk_closure(cx: &ctxt, fty: ClosureTy) -> t { mk_t(cx, ty_closure(box fty)) } diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 7c8d9309df3b823898f5328117a5991fb06cb9a1..f2cc3bfd29b9f5a2ec93bf990b5f25196bcc254d 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -59,7 +59,7 @@ use middle::ty; use middle::typeck::lookup_def_tcx; 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::TypeAndSubsts; use middle::typeck; @@ -207,15 +207,16 @@ pub fn opt_ast_region_to_region<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( } fn ast_path_substs<'tcx,AC,RS>( - this: &AC, - rscope: &RS, - decl_def_id: ast::DefId, - decl_generics: &ty::Generics, - self_ty: Option, - associated_ty: Option, - path: &ast::Path) - -> Substs - where AC: AstConv<'tcx>, RS: RegionScope + this: &AC, + rscope: &RS, + decl_def_id: ast::DefId, + decl_generics: &ty::Generics, + self_ty: Option, + associated_ty: Option, + path: &ast::Path, + binder_id: ast::NodeId) + -> Substs + where AC: AstConv<'tcx>, RS: RegionScope { /*! * Given a path `path` that refers to an item `I` with the @@ -236,45 +237,51 @@ fn ast_path_substs<'tcx,AC,RS>( assert!(decl_generics.regions.all(|d| d.space == TypeSpace)); 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 // region with the current anon region binding (in other words, // whatever & would get replaced with). 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 { - path.segments.last().unwrap().lifetimes.iter().map( - |l| ast_region_to_region(this.tcx(), l)).collect::>() + regions } else { let anon_regions = rscope.anon_regions(path.span, expected_num_region_params); if supplied_num_region_params != 0 || anon_regions.is_err() { span_err!(tcx.sess, path.span, E0107, - "wrong number of lifetime parameters: expected {}, found {}", - expected_num_region_params, supplied_num_region_params); + "wrong number of lifetime parameters: expected {}, found {}", + expected_num_region_params, supplied_num_region_params); } match anon_regions { Ok(v) => v.into_iter().collect(), Err(_) => Vec::from_fn(expected_num_region_params, - |_| ty::ReStatic) // hokey + |_| ty::ReStatic) // hokey } }; // Convert the type parameters supplied by the user. 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 = ty_param_defs.iter() - .take_while(|x| !ty::is_associated_type(tcx, x.def_id)) - .count(); + .take_while(|x| !ty::is_associated_type(tcx, x.def_id)) + .count(); let required_ty_param_count = ty_param_defs.iter() - .take_while(|x| { - x.default.is_none() && - !ty::is_associated_type(tcx, x.def_id) - }) - .count(); + .take_while(|x| { + x.default.is_none() && + !ty::is_associated_type(tcx, x.def_id) + }) + .count(); if supplied_ty_param_count < required_ty_param_count { let expected = if required_ty_param_count < formal_ty_param_count { "expected at least" @@ -282,10 +289,10 @@ fn ast_path_substs<'tcx,AC,RS>( "expected" }; this.tcx().sess.span_fatal(path.span, - format!("wrong number of type arguments: {} {}, found {}", - expected, - required_ty_param_count, - supplied_ty_param_count).as_slice()); + format!("wrong number of type arguments: {} {}, found {}", + expected, + required_ty_param_count, + supplied_ty_param_count).as_slice()); } else if supplied_ty_param_count > formal_ty_param_count { let expected = if required_ty_param_count < formal_ty_param_count { "expected at most" @@ -293,10 +300,10 @@ fn ast_path_substs<'tcx,AC,RS>( "expected" }; this.tcx().sess.span_fatal(path.span, - format!("wrong number of type arguments: {} {}, found {}", - expected, - formal_ty_param_count, - supplied_ty_param_count).as_slice()); + format!("wrong number of type arguments: {} {}, found {}", + expected, + formal_ty_param_count, + supplied_ty_param_count).as_slice()); } if supplied_ty_param_count > required_ty_param_count @@ -307,13 +314,7 @@ fn ast_path_substs<'tcx,AC,RS>( "add #![feature(default_type_params)] to the crate attributes to enable"); } - let tps = path.segments - .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); + let mut substs = Substs::new_type(types, regions); match self_ty { None => { @@ -354,7 +355,47 @@ fn ast_path_substs<'tcx,AC,RS>( param.def_id)) } - substs + return substs; + + fn angle_bracketed_parameters<'tcx, AC, RS>(this: &AC, + rscope: &RS, + data: &ast::AngleBracketedParameterData) + -> (Vec, Vec) + 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, Vec) + 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, @@ -362,7 +403,8 @@ pub fn ast_path_to_trait_ref<'tcx,AC,RS>(this: &AC, trait_def_id: ast::DefId, self_ty: Option, associated_type: Option, - path: &ast::Path) + path: &ast::Path, + binder_id: ast::NodeId) -> Rc where AC: AstConv<'tcx>, RS: RegionScope { @@ -375,7 +417,8 @@ pub fn ast_path_to_trait_ref<'tcx,AC,RS>(this: &AC, &trait_def.generics, self_ty, associated_type, - path) + path, + binder_id) }) } @@ -383,8 +426,10 @@ pub fn ast_path_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( this: &AC, rscope: &RS, did: ast::DefId, - path: &ast::Path) - -> TypeAndSubsts { + path: &ast::Path, + binder_id: ast::NodeId) + -> TypeAndSubsts +{ let tcx = this.tcx(); let ty::Polytype { generics, @@ -397,7 +442,8 @@ pub fn ast_path_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( &generics, None, None, - path); + path, + binder_id); let ty = decl_ty.subst(tcx, &substs); TypeAndSubsts { substs: substs, ty: ty } } @@ -407,24 +453,29 @@ pub fn ast_path_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( /// and/or region variables are substituted. /// /// This is used when checking the constructor in struct literals. -pub fn ast_path_to_ty_relaxed<'tcx, AC: AstConv<'tcx>, - RS:RegionScope>( - this: &AC, - rscope: &RS, - did: ast::DefId, - path: &ast::Path) - -> TypeAndSubsts { +pub fn ast_path_to_ty_relaxed<'tcx,AC,RS>( + this: &AC, + rscope: &RS, + did: ast::DefId, + path: &ast::Path, + binder_id: ast::NodeId) + -> TypeAndSubsts + where AC : AstConv<'tcx>, RS : RegionScope +{ let tcx = this.tcx(); let ty::Polytype { generics, ty: decl_ty } = this.get_item_ty(did); - let substs = if (generics.has_type_params(TypeSpace) || - generics.has_region_params(TypeSpace)) && - path.segments.iter().all(|s| { - s.lifetimes.len() == 0 && s.types.len() == 0 - }) { + let wants_params = + generics.has_type_params(TypeSpace) || generics.has_region_params(TypeSpace); + + 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), |_| this.ty_infer(path.span)); let region_params = @@ -433,7 +484,7 @@ pub fn ast_path_to_ty_relaxed<'tcx, AC: AstConv<'tcx>, Substs::new(VecPerParamSpace::params_from_type(type_params), VecPerParamSpace::params_from_type(region_params)) } 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); @@ -450,14 +501,14 @@ fn check_path_args(tcx: &ty::ctxt, path: &ast::Path, flags: uint) { 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, "type parameters are not allowed on this type"); } } 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, "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>( // FIXME(#12938): This is a hack until we have full support for // DST. match a_def { - def::DefTy(did, _) | def::DefStruct(did) - if Some(did) == this.tcx().lang_items.owned_box() => { - if path.segments - .iter() - .flat_map(|s| s.types.iter()) - .count() > 1 { - span_err!(this.tcx().sess, path.span, E0047, - "`Box` has only one type parameter"); - } - - for inner_ast_type in path.segments - .iter() - .flat_map(|s| s.types.iter()) { - return Some(mk_pointer(this, - rscope, - ast::MutImmutable, - &**inner_ast_type, - Uniq, - |typ| ty::mk_uniq(this.tcx(), typ))); + def::DefTy(did, _) | + def::DefStruct(did) if Some(did) == this.tcx().lang_items.owned_box() => { + let ty = ast_path_to_ty(this, rscope, did, path, id).ty; + match ty::get(ty).sty { + ty::ty_struct(struct_def_id, ref substs) => { + assert_eq!(struct_def_id, did); + assert_eq!(substs.types.len(TypeSpace), 1); + let referent_ty = *substs.types.get(TypeSpace, 0); + Some(ty::mk_uniq(this.tcx(), referent_ty)) + } + _ => { + this.tcx().sess.span_bug( + path.span, + format!("converting `Box` to `{}`", + ty.repr(this.tcx()))[]); + } } - span_err!(this.tcx().sess, path.span, E0113, - "not enough type parameters supplied to `Box`"); - Some(ty::mk_err()) } _ => None } @@ -603,11 +648,7 @@ pub fn trait_ref_for_unboxed_function<'tcx, AC: AstConv<'tcx>, .map(|input| { ast_ty_to_ty(this, rscope, &*input.ty) }).collect::>(); - let input_tuple = if input_types.len() == 0 { - ty::mk_nil() - } else { - ty::mk_tup(this.tcx(), input_types) - }; + let input_tuple = ty::mk_tup_or_nil(this.tcx(), input_types); let output_type = ast_ty_to_ty(this, rscope, &*decl.output); let mut substs = Substs::new_type(vec!(input_tuple, output_type), Vec::new()); @@ -693,7 +734,8 @@ fn mk_pointer<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( trait_def_id, None, None, - path); + path, + id); let bounds = match *opt_bounds { None => { conv_existential_bounds(this, @@ -771,7 +813,12 @@ fn associated_ty_to_ty<'tcx,AC,RS>(this: &AC, trait_did, None, 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={})", trait_ref.repr(this.tcx())); @@ -925,7 +972,8 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( trait_def_id, None, None, - path); + path, + id); let empty_bounds: &[ast::TyParamBound] = &[]; let ast_bounds = match *bounds { Some(ref b) => b.as_slice(), @@ -942,7 +990,7 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( bounds) } 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) => { check_path_args(tcx, path, NO_TPS | NO_REGIONS); diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index bcb875a6aa830de52350c615ddf051b11c8858cf..322275218e1bae80cc3978f61ced9e129891d229 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -3481,11 +3481,7 @@ fn check_unboxed_closure(fcx: &FnCtxt, // Tuple up the arguments and insert the resulting function type into // the `unboxed_closures` table. - fn_ty.sig.inputs = if fn_ty.sig.inputs.len() == 0 { - vec![ty::mk_nil()] - } else { - vec![ty::mk_tup(fcx.tcx(), fn_ty.sig.inputs)] - }; + fn_ty.sig.inputs = vec![ty::mk_tup_or_nil(fcx.tcx(), fn_ty.sig.inputs)]; let kind = match kind { ast::FnUnboxedClosureKind => ty::FnUnboxedClosureKind, @@ -4478,7 +4474,8 @@ fn check_struct_fields_on_error(fcx: &FnCtxt, let type_and_substs = astconv::ast_path_to_ty_relaxed(fcx, fcx.infcx(), struct_id, - path); + path, + expr.id); match fcx.mk_subty(false, infer::Misc(path.span), actual_structure_type, @@ -5339,6 +5336,7 @@ pub fn instantiate_path(fcx: &FnCtxt, Some(space) => { push_explicit_parameters_from_segment_to_substs(fcx, space, + path.span, type_defs, region_defs, segment, @@ -5374,13 +5372,13 @@ fn report_error_if_segment_contains_type_parameters( fcx: &FnCtxt, segment: &ast::PathSegment) { - for typ in segment.types.iter() { + for typ in segment.parameters.types().iter() { span_err!(fcx.tcx().sess, typ.span, E0085, "type parameters may not appear here"); break; } - for lifetime in segment.lifetimes.iter() { + for lifetime in segment.parameters.lifetimes().iter() { span_err!(fcx.tcx().sess, lifetime.span, E0086, "lifetime parameters may not appear here"); break; @@ -5390,6 +5388,7 @@ fn report_error_if_segment_contains_type_parameters( fn push_explicit_parameters_from_segment_to_substs( fcx: &FnCtxt, space: subst::ParamSpace, + span: Span, type_defs: &VecPerParamSpace, region_defs: &VecPerParamSpace, segment: &ast::PathSegment, @@ -5412,10 +5411,31 @@ fn push_explicit_parameters_from_segment_to_substs( * 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, + region_defs: &VecPerParamSpace, + data: &ast::AngleBracketedParameterData, + substs: &mut Substs) + { { let type_count = type_defs.len(space); 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); if i < type_count { substs.types.push(space, t); @@ -5424,7 +5444,7 @@ fn push_explicit_parameters_from_segment_to_substs( "too many type parameters provided: \ expected at most {} parameter(s), \ found {} parameter(s)", - type_count, segment.types.len()); + type_count, data.types.len()); substs.types.truncate(space, 0); } } @@ -5433,7 +5453,7 @@ fn push_explicit_parameters_from_segment_to_substs( { let region_count = region_defs.len(space); 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); if i < region_count { substs.mut_regions().push(space, r); @@ -5442,13 +5462,59 @@ fn push_explicit_parameters_from_segment_to_substs( "too many lifetime parameters provided: \ expected {} parameter(s), found {} parameter(s)", region_count, - segment.lifetimes.len()); + data.lifetimes.len()); 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, + 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 = + 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 = + 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( fcx: &FnCtxt, span: Span, diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 0374a64261f02b4bee370e730d42f65350039502..7a26cc51114540b538152f7114992014aa1e08f0 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -1340,7 +1340,8 @@ pub fn instantiate_trait_ref<'tcx,AC>(this: &AC, trait_did, Some(self_ty), 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, trait_ref.clone()); diff --git a/src/librustc/middle/typeck/infer/error_reporting.rs b/src/librustc/middle/typeck/infer/error_reporting.rs index bfa0f94a74751d466da59005e3294b4afcedcf4c..64efae486b7e9733fc6a67f02759ad9e941b7240 100644 --- a/src/librustc/middle/typeck/infer/error_reporting.rs +++ b/src/librustc/middle/typeck/infer/error_reporting.rs @@ -1108,7 +1108,8 @@ fn rebuild_ty_param_bounds(&self, &ast::TraitTyParamBound(ref tr) => { let last_seg = tr.path.segments.last().unwrap(); 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(<.name) { insert.push(i); } @@ -1116,7 +1117,7 @@ fn rebuild_ty_param_bounds(&self, let rebuild_info = RebuildPathInfo { path: &tr.path, indexes: insert, - expected: last_seg.lifetimes.len(), + expected: lifetimes.len(), anon_nums: &HashSet::new(), region_names: region_names }; @@ -1257,7 +1258,7 @@ fn rebuild_arg_ty_or_output(&self, let expected = generics.regions.len(subst::TypeSpace); let lifetimes = - &path.segments.last().unwrap().lifetimes; + path.segments.last().unwrap().parameters.lifetimes(); let mut insert = Vec::new(); if lifetimes.len() == 0 { let anon = self.cur_anon.get(); @@ -1357,7 +1358,8 @@ fn build_to(from: P, fn rebuild_path(&self, rebuild_info: RebuildPathInfo, lifetime: ast::Lifetime) - -> ast::Path { + -> ast::Path + { let RebuildPathInfo { path, indexes, @@ -1367,37 +1369,48 @@ fn rebuild_path(&self, } = rebuild_info; let last_seg = path.segments.last().unwrap(); - let mut new_lts = Vec::new(); - if last_seg.lifetimes.len() == 0 { - // traverse once to see if there's a need to insert lifetime - let need_insert = range(0, expected).any(|i| { - indexes.contains(&i) - }); - 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()); + let new_parameters = match last_seg.parameters { + ast::ParenthesizedParameters(..) => { + last_seg.parameters.clone() + } + + ast::AngleBracketedParameters(ref data) => { + let mut new_lts = Vec::new(); + if data.lifetimes.len() == 0 { + // traverse once to see if there's a need to insert lifetime + let need_insert = range(0, expected).any(|i| { + indexes.contains(&i) + }); + 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 { - 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 { identifier: last_seg.identifier, - lifetimes: new_lts, - types: new_types, + parameters: new_parameters }; let mut new_segs = Vec::new(); new_segs.push_all(path.segments.init()); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index f96b3916f06dee31cdf5a2f6ae16b2f4a680ac8f..cfd183b4c453b4a1c2354e752d200e3fbb29ba57 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1641,10 +1641,23 @@ pub struct PathSegment { impl Clean for ast::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 { name: self.identifier.clean(cx), - lifetimes: self.lifetimes.clean(cx), - types: self.types.clean(cx), + lifetimes: lifetimes, + types: types, } } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 078e393eb28ed2293041cc0beeb7191e8565ee25..a2089a3e2a35c2d0fd0227e14e77c00f27eec3e8 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -171,7 +171,7 @@ pub struct Path { /// module (like paths in an import). pub global: bool, /// The segments in the path: the things separated by `::`. - pub segments: Vec , + pub segments: Vec, } /// A segment of a path: an identifier, an optional lifetime, and a set of @@ -180,12 +180,107 @@ pub struct Path { pub struct PathSegment { /// The identifier portion of this path segment. pub identifier: Ident, + + /// Type/lifetime parameters attached to this path. They come in + /// two flavors: `Path` 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> { + /*! + * 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. pub lifetimes: Vec, /// The type parameters for this path segment, if present. pub types: OwnedSlice>, } +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>, + + /// `C` + pub output: Option>, +} + pub type CrateNum = u32; pub type NodeId = u32; diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 3aa60236d709a6f7f7822ab6f3a6e1a23fa097ba..2e3a15bfd4b4b1826a8cdb654718d04faf380779 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -171,8 +171,10 @@ pub fn ident_to_path(s: Span, identifier: Ident) -> Path { segments: vec!( ast::PathSegment { identifier: identifier, - lifetimes: Vec::new(), - types: OwnedSlice::empty(), + parameters: ast::AngleBracketedParameters(ast::AngleBracketedParameterData { + lifetimes: Vec::new(), + types: OwnedSlice::empty(), + }) } ), } @@ -681,11 +683,11 @@ pub fn segments_name_eq(a : &[ast::PathSegment], b : &[ast::PathSegment]) -> boo false } else { 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? - || (seg.lifetimes != b[idx].lifetimes) // can types contain idents? - || (seg.types != b[idx].types) { + || seg.parameters != b[idx].parameters + { return false; } } @@ -747,12 +749,10 @@ impl PostExpansionMethod for Method { mod test { use ast::*; use super::*; - use owned_slice::OwnedSlice; fn ident_to_segment(id : &Ident) -> PathSegment { - PathSegment {identifier:id.clone(), - lifetimes: Vec::new(), - types: OwnedSlice::empty()} + PathSegment {identifier: id.clone(), + parameters: PathParameters::none()} } #[test] fn idents_name_eq_test() { diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index dc4eaf7d7adebfbfa297d03bc582401f6da45e0e..5921d630b8979c6a44e9f850c6b1bbb2878aa3ce 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -313,14 +313,15 @@ fn path_all(&self, .map(|ident| { ast::PathSegment { identifier: ident, - lifetimes: Vec::new(), - types: OwnedSlice::empty(), + parameters: ast::PathParameters::none(), } }).collect(); segments.push(ast::PathSegment { identifier: last_identifier, - lifetimes: lifetimes, - types: OwnedSlice::from_vec(types), + parameters: ast::AngleBracketedParameters(ast::AngleBracketedParameterData { + lifetimes: lifetimes, + types: OwnedSlice::from_vec(types), + }) }); ast::Path { span: sp, diff --git a/src/libsyntax/ext/concat_idents.rs b/src/libsyntax/ext/concat_idents.rs index e5e93a7d8b3bb3c761e2e7ddf643fb9aaf266859..aa18b1be31acc46e9b6615e509e43704efbaa9fd 100644 --- a/src/libsyntax/ext/concat_idents.rs +++ b/src/libsyntax/ext/concat_idents.rs @@ -12,7 +12,6 @@ use codemap::Span; use ext::base::*; use ext::base; -use owned_slice::OwnedSlice; use parse::token; use parse::token::{str_to_ident}; use ptr::P; @@ -52,8 +51,7 @@ pub fn expand_syntax_ext<'cx>(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree] segments: vec!( ast::PathSegment { identifier: res, - lifetimes: Vec::new(), - types: OwnedSlice::empty(), + parameters: ast::PathParameters::none(), } ) } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 6535c8e89fd4e79c22a2ca7d5265169982fb505a..79e2c656e41f4a8796a63a03275df25a366c2eb8 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -166,6 +166,22 @@ fn fold_path(&mut self, p: Path) -> Path { 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) -> P { noop_fold_local(l, self) } @@ -480,15 +496,43 @@ pub fn noop_fold_uint(i: uint, _: &mut T) -> uint { pub fn noop_fold_path(Path {global, segments, span}: Path, fld: &mut T) -> Path { Path { global: global, - segments: segments.move_map(|PathSegment {identifier, lifetimes, types}| PathSegment { + segments: segments.move_map(|PathSegment {identifier, parameters}| PathSegment { identifier: fld.fold_ident(identifier), - lifetimes: fld.fold_lifetimes(lifetimes), - types: types.move_map(|typ| fld.fold_ty(typ)), + parameters: fld.fold_path_parameters(parameters), }), span: fld.new_span(span) } } +pub fn noop_fold_path_parameters(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(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(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(l: P, fld: &mut T) -> P { l.map(|Local {id, pat, ty, init, source, span}| Local { id: fld.new_id(id), diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 83499ec54c6766cf4e71cfa1f5c476ba86b245ea..996708b217426d186a5d7b44f39ca3c3850a9252 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -749,8 +749,7 @@ fn sp(a: u32, b: u32) -> Span { segments: vec!( ast::PathSegment { identifier: str_to_ident("a"), - lifetimes: Vec::new(), - types: OwnedSlice::empty(), + parameters: ast::PathParameters::none(), } ), }), @@ -768,13 +767,11 @@ fn sp(a: u32, b: u32) -> Span { segments: vec!( ast::PathSegment { identifier: str_to_ident("a"), - lifetimes: Vec::new(), - types: OwnedSlice::empty(), + parameters: ast::PathParameters::none(), }, ast::PathSegment { identifier: str_to_ident("b"), - lifetimes: Vec::new(), - types: OwnedSlice::empty(), + parameters: ast::PathParameters::none(), } ) }), @@ -952,8 +949,7 @@ fn string_to_tts_1 () { segments: vec!( ast::PathSegment { identifier: str_to_ident("d"), - lifetimes: Vec::new(), - types: OwnedSlice::empty(), + parameters: ast::PathParameters::none(), } ), }), @@ -974,8 +970,7 @@ fn string_to_tts_1 () { segments: vec!( ast::PathSegment { identifier: str_to_ident("b"), - lifetimes: Vec::new(), - types: OwnedSlice::empty(), + parameters: ast::PathParameters::none(), } ), }), @@ -1022,8 +1017,7 @@ fn parser_done(p: Parser){ ast::PathSegment { identifier: str_to_ident("int"), - lifetimes: Vec::new(), - types: OwnedSlice::empty(), + parameters: ast::PathParameters::none(), } ), }, None, ast::DUMMY_NODE_ID), @@ -1072,10 +1066,8 @@ fn parser_done(p: Parser){ identifier: str_to_ident( "b"), - lifetimes: - Vec::new(), - types: - OwnedSlice::empty() + parameters: + ast::PathParameters::none(), } ), }), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index fd244a443a8a009e258c4e014d65ae6498f8c2f0..1c65a47350ea827cb20dd6b15321f848a12628a5 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1487,9 +1487,9 @@ pub fn parse_ty(&mut self, plus_allowed: bool) -> P { trait_name: trait_name.path, item_name: item_name, })) - } else if self.token == token::ModSep - || self.token.is_ident() - || self.token.is_path() { + } else if self.token == token::ModSep || + self.token.is_ident() || + self.token.is_path() { // NAMED TYPE let mode = if plus_allowed { LifetimeAndTypesAndBounds @@ -1771,27 +1771,36 @@ pub fn parse_path_segments_without_colons(&mut self) -> Vec { let identifier = self.parse_ident(); // Parse types, optionally. - let (lifetimes, types) = if self.eat_lt(false) { - self.parse_generic_values_after_lt() - } else if false && self.eat(&token::LParen) { - let mut types = self.parse_seq_to_end( - &token::RParen, + let parameters = if self.eat_lt(false) { + let (lifetimes, types) = self.parse_generic_values_after_lt(); + + ast::AngleBracketedParameters(ast::AngleBracketedParameterData { + 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), |p| p.parse_ty(true)); - if self.eat(&token::RArrow) { - types.push(self.parse_ty(true)) - } + let output_ty = if self.eat(&token::RArrow) { + Some(self.parse_ty(true)) + } else { + None + }; - (Vec::new(), types) + ast::ParenthesizedParameters(ast::ParenthesizedParameterData { + inputs: inputs, + output: output_ty + }) } else { - (Vec::new(), Vec::new()) + ast::PathParameters::none() }; // Assemble and push the result. segments.push(ast::PathSegment { identifier: identifier, - lifetimes: lifetimes, - types: OwnedSlice::from_vec(types), }); + parameters: parameters }); // Continue only if we see a `::` if !self.eat(&token::ModSep) { @@ -1810,9 +1819,13 @@ pub fn parse_path_segments_with_colons(&mut self) -> Vec { // If we do not see a `::`, stop. if !self.eat(&token::ModSep) { - segments.push(ast::PathSegment { identifier: identifier, - lifetimes: Vec::new(), - types: OwnedSlice::empty() }); + segments.push(ast::PathSegment { + identifier: identifier, + parameters: ast::AngleBracketedParameters(ast::AngleBracketedParameterData { + lifetimes: Vec::new(), + types: OwnedSlice::empty(), + }) + }); return segments; } @@ -1820,9 +1833,13 @@ pub fn parse_path_segments_with_colons(&mut self) -> Vec { if self.eat_lt(false) { // Consumed `a::b::<`, go look for types let (lifetimes, types) = self.parse_generic_values_after_lt(); - segments.push(ast::PathSegment { identifier: identifier, - lifetimes: lifetimes, - types: OwnedSlice::from_vec(types) }); + segments.push(ast::PathSegment { + identifier: identifier, + parameters: ast::AngleBracketedParameters(ast::AngleBracketedParameterData { + lifetimes: lifetimes, + types: OwnedSlice::from_vec(types), + }), + }); // Consumed `a::b::`, check for `::` before proceeding if !self.eat(&token::ModSep) { @@ -1830,9 +1847,10 @@ pub fn parse_path_segments_with_colons(&mut self) -> Vec { } } else { // Consumed `a::`, go look for `b` - segments.push(ast::PathSegment { identifier: identifier, - lifetimes: Vec::new(), - types: OwnedSlice::empty() }); + segments.push(ast::PathSegment { + identifier: identifier, + parameters: ast::PathParameters::none(), + }); } } } @@ -1847,9 +1865,10 @@ pub fn parse_path_segments_without_types(&mut self) -> Vec { let identifier = self.parse_ident(); // Assemble and push the result. - segments.push(ast::PathSegment { identifier: identifier, - lifetimes: Vec::new(), - types: OwnedSlice::empty(), }); + segments.push(ast::PathSegment { + identifier: identifier, + parameters: ast::PathParameters::none() + }); // If we do not see a `::`, stop. if !self.eat(&token::ModSep) { @@ -3455,13 +3474,9 @@ pub fn parse_pat(&mut self) -> P { }, _ => { if !enum_path.global && - enum_path.segments.len() == 1 && - enum_path.segments[0] - .lifetimes - .len() == 0 && - enum_path.segments[0] - .types - .len() == 0 { + enum_path.segments.len() == 1 && + enum_path.segments[0].parameters.is_empty() + { // it could still be either an enum // or an identifier pattern, resolve // will sort it out: @@ -3960,8 +3975,7 @@ fn parse_ty_param_bounds(&mut self) fn trait_ref_from_ident(ident: Ident, span: Span) -> ast::TraitRef { let segment = ast::PathSegment { identifier: ident, - lifetimes: Vec::new(), - types: OwnedSlice::empty(), + parameters: ast::PathParameters::none() }; let path = ast::Path { span: span, @@ -5677,8 +5691,7 @@ fn parse_view_path(&mut self) -> P { segments: path.into_iter().map(|identifier| { ast::PathSegment { identifier: identifier, - lifetimes: Vec::new(), - types: OwnedSlice::empty(), + parameters: ast::PathParameters::none(), } }).collect() }; @@ -5712,8 +5725,7 @@ fn parse_view_path(&mut self) -> P { segments: path.into_iter().map(|identifier| { ast::PathSegment { identifier: identifier, - lifetimes: Vec::new(), - types: OwnedSlice::empty(), + parameters: ast::PathParameters::none(), } }).collect() }; @@ -5730,8 +5742,7 @@ fn parse_view_path(&mut self) -> P { segments: path.into_iter().map(|identifier| { ast::PathSegment { identifier: identifier, - lifetimes: Vec::new(), - types: OwnedSlice::empty(), + parameters: ast::PathParameters::none(), } }).collect() }; @@ -5752,8 +5763,7 @@ fn parse_view_path(&mut self) -> P { segments: path.into_iter().map(|identifier| { ast::PathSegment { identifier: identifier, - lifetimes: Vec::new(), - types: OwnedSlice::empty(), + parameters: ast::PathParameters::none(), } }).collect() }; diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 106e3f1faae89e8b803bd8941ebf187fe71d1f30..d83ea5f76b1fc0f48246aec351bdebb2b736daa5 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1995,14 +1995,34 @@ fn print_path_(&mut self, try!(self.print_ident(segment.identifier)); - if !segment.lifetimes.is_empty() || !segment.types.is_empty() { - if colons_before_params { - try!(word(&mut self.s, "::")) - } + try!(self.print_path_parameters(&segment.parameters, colons_before_params)); + } + + 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, "<")); let mut comma = false; - for lifetime in segment.lifetimes.iter() { + for lifetime in data.lifetimes.iter() { if comma { try!(self.word_space(",")) } @@ -2010,24 +2030,38 @@ fn print_path_(&mut self, comma = true; } - if !segment.types.is_empty() { + if !data.types.is_empty() { if comma { try!(self.word_space(",")) } try!(self.commasep( Inconsistent, - segment.types.as_slice(), + data.types.as_slice(), |s, ty| s.print_type(&**ty))); } try!(word(&mut self.s, ">")) } - } - match *opt_bounds { - None => Ok(()), - Some(ref bounds) => self.print_bounds("+", bounds) + ast::ParenthesizedParameters(ref data) => { + try!(word(&mut self.s, "(")); + 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, diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index 0f86fb751dae45771bd7394340065db8e8a2f3e3..6a4ab365a50b2930c9870ada96f8d23c2cfe72b3 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -14,7 +14,6 @@ use codemap; use fold::Folder; use fold; -use owned_slice::OwnedSlice; use parse::token::InternedString; use parse::token::special_idents; use parse::token; @@ -181,13 +180,11 @@ fn fold_mod(&mut self, ast::Mod {inner, view_items, items}: ast::Mod) -> ast::Mo segments: vec!( ast::PathSegment { identifier: token::str_to_ident("std"), - lifetimes: Vec::new(), - types: OwnedSlice::empty(), + parameters: ast::PathParameters::none(), }, ast::PathSegment { identifier: token::str_to_ident("prelude"), - lifetimes: Vec::new(), - types: OwnedSlice::empty(), + parameters: ast::PathParameters::none(), }), }; diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 37586f6abd7d47526564f8f923a5b154be325baf..a7db8e800a9d0e54503d2b86bc7fca21cc2b1af1 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -453,8 +453,7 @@ fn path_node(ids: Vec ) -> ast::Path { global: false, segments: ids.into_iter().map(|identifier| ast::PathSegment { identifier: identifier, - lifetimes: Vec::new(), - types: OwnedSlice::empty(), + parameters: ast::PathParameters::none(), }).collect() } } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 86ee23d71a6b22dbc733098b8cd9b6e3eac850cf..b4141af07336a3d912ec6f5e39136200858c2835 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -407,11 +407,23 @@ pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path) { for segment in path.segments.iter() { visitor.visit_ident(path.span, segment.identifier); - for typ in segment.types.iter() { - visitor.visit_ty(&**typ); - } - for lifetime in segment.lifetimes.iter() { - visitor.visit_lifetime_ref(lifetime); + match segment.parameters { + ast::AngleBracketedParameters(ref data) => { + for typ in data.types.iter() { + visitor.visit_ty(&**typ); + } + 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); + } + } } } } diff --git a/src/test/compile-fail/issue-14092.rs b/src/test/compile-fail/issue-14092.rs index 4d663d00fb291d7c2e37bdfc48a37b68d19ed1ef..0ab37a888267f44eed1c158dc69f0ff1d3a3d038 100644 --- a/src/test/compile-fail/issue-14092.rs +++ b/src/test/compile-fail/issue-14092.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn fn1(0: Box) {} //~ ERROR: not enough type parameters supplied to `Box` +fn fn1(0: Box) {} //~ ERROR: wrong number of type arguments: expected 1, found 0 fn main() {} diff --git a/src/test/compile-fail/issue-18423.rs b/src/test/compile-fail/issue-18423.rs new file mode 100644 index 0000000000000000000000000000000000000000..63b110b5579344901453bcbbbc00bf6b1e182c8d --- /dev/null +++ b/src/test/compile-fail/issue-18423.rs @@ -0,0 +1,18 @@ +// 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 or the MIT license +// , 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() { +} diff --git a/src/test/compile-fail/unboxed-closure-sugar-default.rs b/src/test/compile-fail/unboxed-closure-sugar-default.rs new file mode 100644 index 0000000000000000000000000000000000000000..9866a20004527f0520063f680bab36af044057f7 --- /dev/null +++ b/src/test/compile-fail/unboxed-closure-sugar-default.rs @@ -0,0 +1,37 @@ +// 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 or the MIT license +// , 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: T, u: U +} + +trait Eq { } +impl Eq for X { } +fn eq>() { } + +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() { } diff --git a/src/test/compile-fail/unboxed-closure-sugar-equiv.rs b/src/test/compile-fail/unboxed-closure-sugar-equiv.rs new file mode 100644 index 0000000000000000000000000000000000000000..c38010c1ee260a9bb5fcd610bf63d1dd2edc89b9 --- /dev/null +++ b/src/test/compile-fail/unboxed-closure-sugar-equiv.rs @@ -0,0 +1,39 @@ +// 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 or the MIT license +// , 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: T, u: U +} + +trait Eq { } +impl Eq for X { } +fn eq>() { } + +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() { } diff --git a/src/test/compile-fail/unboxed-closure-sugar-nonexistent-trait.rs b/src/test/compile-fail/unboxed-closure-sugar-nonexistent-trait.rs index f51160a1b233d3bc86d11fdf5d3861d7d0a3a2f0..d89c3802508c593c653330580acb96d7635ee745 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-nonexistent-trait.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-nonexistent-trait.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn f int>(x: F) {} //~ ERROR unresolved trait +fn f int>(x: F) {} //~ ERROR nonexistent trait `Nonexist` type Typedef = int; diff --git a/src/test/compile-fail/unboxed-closure-sugar-region.rs b/src/test/compile-fail/unboxed-closure-sugar-region.rs new file mode 100644 index 0000000000000000000000000000000000000000..962e233dea696651ee56bb33753ffc3d02db6423 --- /dev/null +++ b/src/test/compile-fail/unboxed-closure-sugar-region.rs @@ -0,0 +1,45 @@ +// 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 or the MIT license +// , 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 { } +impl Eq for X { } +fn eq>() { } +fn same_type>(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() { } diff --git a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs new file mode 100644 index 0000000000000000000000000000000000000000..e122b87b1e0f04c9b4094d6a764ecb7434b1a9ca --- /dev/null +++ b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs @@ -0,0 +1,16 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct One; + +fn foo(_: One()) //~ ERROR wrong number of type arguments +{} + +fn main() { } diff --git a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs new file mode 100644 index 0000000000000000000000000000000000000000..7a66abb39df58e1e01da72422c651e1ba6c86291 --- /dev/null +++ b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs @@ -0,0 +1,16 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Three; + +fn foo(_: Three()) //~ ERROR wrong number of type arguments +{} + +fn main() { } diff --git a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters.rs b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters.rs new file mode 100644 index 0000000000000000000000000000000000000000..e265a3d56b871cc56af5f340fbe1b9c7b10d8b62 --- /dev/null +++ b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters.rs @@ -0,0 +1,16 @@ +// 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 or the MIT license +// , 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() { } diff --git a/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs b/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs index a751ae1c518ea9bee7a19a0db18f090199728d62..1394f8fa65fccb9cd0d07f08b4a0de2dd824d89b 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs @@ -11,7 +11,7 @@ trait Trait {} fn f 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() {} diff --git a/src/test/run-pass/unboxed-closures-prelude.rs b/src/test/run-pass/unboxed-closures-prelude.rs index 4226ed427e720e1f6efd7fc215eef3fcf386bbb5..f9d2ba02123c464775abab2ca5f52acd0a3b96fa 100644 --- a/src/test/run-pass/unboxed-closures-prelude.rs +++ b/src/test/run-pass/unboxed-closures-prelude.rs @@ -13,7 +13,7 @@ #![feature(unboxed_closures, unboxed_closure_sugar)] fn main() { - let task: Box<|: int| -> int> = box |: x| x; + let task: Box int> = box |: x| x; task.call_once((0i, )); } diff --git a/src/test/run-pass/unboxed-closures-sugar-1.rs b/src/test/run-pass/unboxed-closures-sugar-1.rs new file mode 100644 index 0000000000000000000000000000000000000000..b358e7ce288339f26a6a727dadeb85ac4666d1ad --- /dev/null +++ b/src/test/run-pass/unboxed-closures-sugar-1.rs @@ -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 or the MIT license +// , 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: T, u: U +} + +trait Eq { } +impl Eq for X { } +fn eq>() { } + +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() { } diff --git a/src/test/run-pass/unboxed-closures-sugar-object.rs b/src/test/run-pass/unboxed-closures-sugar-object.rs new file mode 100644 index 0000000000000000000000000000000000000000..3b38f72432f179c32e9a5320b2396afb5c19f2e7 --- /dev/null +++ b/src/test/run-pass/unboxed-closures-sugar-object.rs @@ -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 or the MIT license +// , 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: T, u: U +} + +trait Getter { + fn get(&self, arg: A) -> R; +} + +struct Identity; +impl Getter 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); +} diff --git a/src/test/run-pass/unboxed-closures-unboxing-shim.rs b/src/test/run-pass/unboxed-closures-unboxing-shim.rs index 0a7baa3ba369d21d16ba36d3a803953e19da5247..426352cadd87fbcf05e312d65a439032a07c28dc 100644 --- a/src/test/run-pass/unboxed-closures-unboxing-shim.rs +++ b/src/test/run-pass/unboxed-closures-unboxing-shim.rs @@ -13,7 +13,7 @@ use std::ops::FnOnce; fn main() { - let task: Box<|: int| -> int> = box |: x| x; + let task: Box int> = box |: x| x; assert!(task.call_once((1234i,)) == 1234i); }