diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index e0f63a92987bc..0a55cceb132c6 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -1080,8 +1080,8 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_name(ecx, ebml_w, item.ident); encode_attributes(ebml_w, item.attrs); match ty.node { - ast::ty_path(ref path, ref bounds, _) if path.segments - .len() == 1 => { + ast::ty_path(_, ref path, ref bounds, _) if path.segments + .len() == 1 => { assert!(bounds.is_none()); encode_impl_type_basename(ecx, ebml_w, ast_util::path_to_ident(path)); diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 7a00afbc65234..0872a6ca8c25b 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -304,7 +304,10 @@ fn enc_sty(w: @mut MemWriter, cx: @ctxt, st: &ty::sty) { ty::ty_infer(_) => { cx.diag.handler().bug("Cannot encode inference variable types"); } - ty::ty_param(param_ty {idx: id, def_id: did}) => { + ty::ty_param(expand, param_ty {idx: id, def_id: did}) => { + if expand { + cx.tcx.sess.bug("found unexpanded ty_param in tyencode::enc_sty"); + } mywrite!(w, "p{}|{}", (cx.ds)(did), id); } ty::ty_self(did) => { diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 2327425c2ade0..767648b24f401 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -159,7 +159,7 @@ impl Visitor<()> for MarkSymbolVisitor { fn visit_ty(&mut self, typ: &ast::Ty, _: ()) { match typ.node { - ast::ty_path(_, _, ref id) => { + ast::ty_path(_, _, _, ref id) => { self.lookup_and_handle_definition(id, typ.span); } _ => visit::walk_ty(self, typ, ()), diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index 195f7798eb0f5..f34e9f0a08b0b 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -137,7 +137,7 @@ fn check_impl_of_trait(cx: &mut Context, it: @item, trait_ref: &trait_ref, self_ // If this is a destructor, check kinds. if cx.tcx.lang_items.drop_trait() == Some(trait_def_id) { match self_type.node { - ty_path(_, ref bounds, path_node_id) => { + ty_path(_, _, ref bounds, path_node_id) => { assert!(bounds.is_none()); let struct_def = cx.tcx.def_map.get_copy(&path_node_id); let struct_did = ast_util::def_id_of_def(struct_def); @@ -325,7 +325,7 @@ pub fn check_expr(cx: &mut Context, e: @Expr) { fn check_ty(cx: &mut Context, aty: &Ty) { match aty.node { - ty_path(_, _, id) => { + ty_path(_, _, _, id) => { let r = cx.tcx.node_type_substs.find(&id); for ts in r.iter() { let did = ast_util::def_id_of_def(cx.tcx.def_map.get_copy(&id)); @@ -554,7 +554,7 @@ pub fn check_cast_for_escaping_regions( |ty| { match ty::get(ty).sty { - ty::ty_param(source_param) => { + ty::ty_param(_, source_param) => { if target_params.iter().any(|x| x == &source_param) { /* case (2) */ } else { diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index 6d0816de433ee..6a3345897d23f 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -711,7 +711,7 @@ fn check_type_limits(cx: &Context, e: &ast::Expr) { fn check_item_ctypes(cx: &Context, it: &ast::item) { fn check_ty(cx: &Context, ty: &ast::Ty) { match ty.node { - ast::ty_path(_, _, id) => { + ast::ty_path(_, _, _, id) => { match cx.tcx.def_map.get_copy(&id) { ast::DefPrimTy(ast::ty_int(ast::ty_i)) => { cx.span_lint(ctypes, ty.span, diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index b5d0fad7f9588..c5cbbcb1abf77 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -219,7 +219,7 @@ impl<'self> Visitor<()> for EmbargoVisitor<'self> { // * Private trait impls for private types can be completely ignored ast::item_impl(_, _, ref ty, ref methods) => { let public_ty = match ty.node { - ast::ty_path(_, _, id) => { + ast::ty_path(_, _, _, id) => { match self.tcx.def_map.get_copy(&id) { ast::DefPrimTy(..) => true, def => { @@ -699,7 +699,7 @@ impl<'self> Visitor<()> for PrivacyVisitor<'self> { fn visit_ty(&mut self, t: &ast::Ty, _: ()) { match t.node { - ast::ty_path(ref path, _, id) => self.check_path(t.span, id, path), + ast::ty_path(_, ref path, _, id) => self.check_path(t.span, id, path), _ => {} } visit::walk_ty(self, t, ()); diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index d2454be4fa063..b5eeca67591f8 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -1236,7 +1236,7 @@ impl Resolver { // Create the module and add all methods. match ty.node { - ty_path(ref path, _, _) if path.segments.len() == 1 => { + ty_path(_, ref path, _, _) if path.segments.len() == 1 => { let name = path_to_ident(path); let new_parent = match parent.children.find(&name.name) { @@ -4129,7 +4129,7 @@ impl Resolver { // Like path expressions, the interpretation of path types depends // on whether the path has multiple elements in it or not. - ty_path(ref path, ref bounds, path_id) => { + ty_path(_, ref path, ref bounds, path_id) => { // This is a path in the type namespace. Walk through scopes // scopes looking for it. let mut result_def = None; diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index c9abf71e2b6ec..bc4610f3abd35 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -63,7 +63,7 @@ impl<'self> TypeFolder for SubstFolder<'self> { } match ty::get(t).sty { - ty::ty_param(p) => { + ty::ty_param(_, p) => { self.substs.tps[p.idx] } ty::ty_self(_) => { diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs index 5278ff1549543..452756d86568e 100644 --- a/src/librustc/middle/trans/reflect.rs +++ b/src/librustc/middle/trans/reflect.rs @@ -351,7 +351,12 @@ impl Reflector { // Miscellaneous extra types ty::ty_infer(_) => self.leaf("infer"), ty::ty_err => self.leaf("err"), - ty::ty_param(ref p) => { + ty::ty_param(expand, ref p) => { + if expand { + tcx.sess.bug(format!( + "found unexpanded ty_param `{}` in reflect::visit_ty", + ty_to_str(tcx, t))); + } let extra = ~[self.c_uint(p.idx)]; self.visit("param", extra) } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index c2003e0849f2f..ec15672ebbaa7 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -644,7 +644,7 @@ pub enum sty { ty_struct(DefId, substs), ty_tup(~[t]), - ty_param(param_ty), // type parameter + ty_param(bool /* expand */, param_ty), // type parameter ty_self(DefId), /* special, implicit `self` type parameter; * def_id is the id of the trait */ @@ -1088,7 +1088,7 @@ pub fn mk_t(cx: ctxt, st: sty) -> t { // so we're doing it this way. &ty_bot => flags |= has_ty_bot as uint, &ty_err => flags |= has_ty_err as uint, - &ty_param(_) => flags |= has_params as uint, + &ty_param(..) => flags |= has_params as uint, &ty_infer(_) => flags |= needs_infer as uint, &ty_self(_) => flags |= has_self as uint, &ty_enum(_, ref substs) | &ty_struct(_, ref substs) | @@ -1342,7 +1342,7 @@ pub fn mk_infer(cx: ctxt, it: InferTy) -> t { mk_t(cx, ty_infer(it)) } pub fn mk_self(cx: ctxt, did: ast::DefId) -> t { mk_t(cx, ty_self(did)) } pub fn mk_param(cx: ctxt, n: uint, k: DefId) -> t { - mk_t(cx, ty_param(param_ty { idx: n, def_id: k })) + mk_t(cx, ty_param(false, param_ty { idx: n, def_id: k })) } pub fn mk_type(cx: ctxt) -> t { mk_t(cx, ty_type) } @@ -1364,7 +1364,7 @@ pub fn maybe_walk_ty(ty: t, f: |t| -> bool) { match get(ty).sty { ty_nil | ty_bot | ty_bool | ty_char | ty_int(_) | ty_uint(_) | ty_float(_) | ty_estr(_) | ty_type | ty_opaque_box | ty_self(_) | - ty_opaque_closure_ptr(_) | ty_infer(_) | ty_param(_) | ty_err => { + ty_opaque_closure_ptr(_) | ty_infer(_) | ty_param(..) | ty_err => { } ty_box(ref tm) | ty_evec(ref tm, _) | ty_unboxed_vec(ref tm) | ty_ptr(ref tm) | ty_rptr(_, ref tm) | ty_uniq(ref tm) => { @@ -1428,7 +1428,7 @@ pub fn subst_tps(tcx: ctxt, tps: &[t], self_ty_opt: Option, typ: t) -> t { } match ty::get(t).sty { - ty_param(p) => { + ty_param(_, p) => { self.tps[p.idx] } @@ -2068,7 +2068,7 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { apply_attributes(cx, did, res) } - ty_param(p) => { + ty_param(_, p) => { // We only ever ask for the kind of types that are defined in // the current crate; therefore, the only type parameters that // could be in scope are those defined in the current crate. @@ -2281,7 +2281,7 @@ pub fn is_instantiable(cx: ctxt, r_ty: t) -> bool { ty_closure(_) | ty_infer(_) | ty_err | - ty_param(_) | + ty_param(..) | ty_self(_) | ty_type | ty_opaque_box | @@ -2486,7 +2486,7 @@ pub fn type_is_pod(cx: ctxt, ty: t) -> bool { ty_evec(ref mt, vstore_fixed(_)) | ty_unboxed_vec(ref mt) => { result = type_is_pod(cx, mt.ty); } - ty_param(_) => result = false, + ty_param(..) => result = false, ty_opaque_closure_ptr(_) => result = true, ty_struct(did, ref substs) => { let fields = lookup_struct_fields(cx, did); @@ -2520,7 +2520,7 @@ pub fn type_is_enum(ty: t) -> bool { pub fn type_is_sized(cx: ctxt, ty: ty::t) -> bool { match get(ty).sty { // FIXME(#6308) add trait, vec, str, etc here. - ty_param(p) => { + ty_param(_, p) => { let param_def = cx.ty_param_defs.get(&p.def_id.node); if param_def.bounds.builtin_bounds.contains_elem(BoundSized) { return true; @@ -2549,7 +2549,7 @@ pub fn type_is_c_like_enum(cx: ctxt, ty: t) -> bool { pub fn type_param(ty: t) -> Option { match get(ty).sty { - ty_param(p) => return Some(p.idx), + ty_param(_, p) => return Some(p.idx), _ => {/* fall through */ } } return None; @@ -3219,7 +3219,7 @@ pub fn param_tys_in_type(ty: t) -> ~[param_ty] { let mut rslt = ~[]; walk_ty(ty, |ty| { match get(ty).sty { - ty_param(p) => { + ty_param(_, p) => { rslt.push(p); } _ => () @@ -3282,7 +3282,7 @@ pub fn ty_sort_str(cx: ctxt, t: t) -> ~str { ty_infer(TyVar(_)) => ~"inferred type", ty_infer(IntVar(_)) => ~"integral variable", ty_infer(FloatVar(_)) => ~"floating-point variable", - ty_param(_) => ~"type parameter", + ty_param(..) => ~"type parameter", ty_self(_) => ~"self", ty_err => ~"type error" } @@ -4668,8 +4668,13 @@ pub fn hash_crate_independent(tcx: ctxt, t: t, local_hash: @str) -> u64 { hash.input([19]); iter(&mut hash, &inner.len()); } - ty_param(p) => { + ty_param(expand, p) => { hash.input([20]); + if expand { + tcx.sess.bug(format!( + "found unexpanded ty_param `{}` in ty::hash_crate_independent", + ty_to_str(tcx, t))); + } iter(&mut hash, &p.idx); did(&mut hash, p.def_id); } diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index d196956163bf5..420fc751948b0 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -11,7 +11,7 @@ // Generalized type folding mechanism. use middle::ty; -use util::ppaux::Repr; +use util::ppaux::{Repr, ty_to_str}; pub trait TypeFolder { fn tcx(&self) -> ty::ctxt; @@ -87,7 +87,24 @@ pub fn fold_opt_ty(this: &mut T, pub fn fold_ty_vec(this: &mut T, tys: &[ty::t]) -> ~[ty::t] { - tys.map(|t| this.fold_ty(*t)) + tys.flat_map(|&t| { + let folded = this.fold_ty(t); + + match ty::get(t).sty { + ty::ty_param(true, _) => { + match ty::get(folded).sty { + ty::ty_nil => ~[], // FIXME #10784 DRY. + ty::ty_tup(ref fields) => fields.clone(), + _ => { + this.tcx().sess.err(format!("cannot expand non-tuple type `{}`", + ty_to_str(this.tcx(), t))); + ~[] + } + } + } + _ => ~[folded] + } + }) } pub fn super_fold_ty(this: &mut T, diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 26b9a1b25d588..9320d83ba98b0 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -57,6 +57,7 @@ use middle::ty; use middle::typeck::rscope; use middle::typeck::rscope::{RegionScope}; use middle::typeck::lookup_def_tcx; +use util::ppaux::ty_to_str; use std::vec; use syntax::abi::AbiSet; @@ -196,20 +197,17 @@ fn ast_path_substs( }; // Convert the type parameters supplied by the user. - let supplied_type_parameter_count = - path.segments.iter().flat_map(|s| s.types.iter()).len(); - if decl_generics.type_param_defs.len() != supplied_type_parameter_count { + let tps = path.segments + .iter() + .flat_map(|s| s.types.iter().map(|&t| t)) + .to_owned_vec() + .flat_map(|&a_t| ast_ty_to_ty_list(this, rscope, a_t, true)); + if decl_generics.type_param_defs.len() != tps.len() { this.tcx().sess.span_fatal( path.span, format!("wrong number of type arguments: expected {} but found {}", - decl_generics.type_param_defs.len(), - supplied_type_parameter_count)); + decl_generics.type_param_defs.len(), tps.len())); } - let tps = path.segments - .iter() - .flat_map(|s| s.types.iter()) - .map(|&a_t| ast_ty_to_ty(this, rscope, a_t)) - .collect(); substs { regions: ty::NonerasedRegions(regions), @@ -311,7 +309,7 @@ pub fn ast_ty_to_ty( debug!("&[]: vst={:?}", vst); return ty::mk_evec(tcx, mt, vst); } - ast::ty_path(ref path, ref bounds, id) => { + ast::ty_path(_, ref path, ref bounds, id) => { // Note that the "bounds must be empty if path is not a trait" // restriction is enforced in the below case for ty_path, which // will run after this as long as the path isn't a trait. @@ -412,8 +410,8 @@ pub fn ast_ty_to_ty( mk_pointer(this, rscope, mt, ty::vstore_slice(r), |tmt| ty::mk_rptr(tcx, r, tmt)) } - ast::ty_tup(ref fields) => { - let flds = fields.map(|&t| ast_ty_to_ty(this, rscope, t)); + ast::ty_tup(_, ref fields) => { + let flds = fields.flat_map(|&t| ast_ty_to_ty_list(this, rscope, t, true)); ty::mk_tup(tcx, flds) } ast::ty_bare_fn(ref bf) => { @@ -449,7 +447,7 @@ pub fn ast_ty_to_ty( ast_ty.span); ty::mk_closure(tcx, fn_decl) } - ast::ty_path(ref path, ref bounds, id) => { + ast::ty_path(_, ref path, ref bounds, id) => { let a_def = match tcx.def_map.find(&id) { None => tcx.sess.span_fatal( ast_ty.span, format!("unbound path {}", @@ -573,6 +571,32 @@ pub fn ast_ty_to_ty( return typ; } +pub fn ast_ty_to_ty_list<'a, AC:AstConv, RS:RegionScope>( + this: &AC, rscope: &RS, ast_ty: &ast::Ty, allow_ty_param_expansion: bool) -> ~[ty::t] { + match ast_ty.node { + ast::ty_tup(true, ref fields) => { + fields.flat_map(|&t| ast_ty_to_ty_list(this, rscope, t, allow_ty_param_expansion)) + } + ast::ty_path(true, _, _, _) => { + let t = ast_ty_to_ty(this, rscope, ast_ty); + match ty::get(t).sty { + ty::ty_nil => ~[], // FIXME #10784 DRY. + ty::ty_tup(ref fields) => fields.clone(), + ty::ty_param(false, param_ty) if allow_ty_param_expansion => { + ~[ty::mk_t(this.tcx(), ty::ty_param(true, param_ty))] + } + _ => { + this.tcx().sess.span_err( + ast_ty.span, + format!("cannot expand non-tuple type `{}`", ty_to_str(this.tcx(), t))); + ~[] + } + } + } + _ => ~[ast_ty_to_ty(this, rscope, ast_ty)] + } +} + pub fn ty_of_arg( this: &AC, @@ -587,6 +611,19 @@ pub fn ty_of_arg( + this: &AC, + rscope: &RS, + a: &ast::arg, + expected_ty: Option) + -> ~[ty::t] { + match a.ty.node { + ast::ty_infer => ~[ty_of_arg(this, rscope, a, expected_ty)], + _ => ast_ty_to_ty_list(this, rscope, a.ty, false) + } +} + struct SelfInfo { untransformed_self_ty: ty::t, explicit_self: ast::explicit_self @@ -639,7 +676,7 @@ fn ty_of_method_or_bare_fn( transform_self_ty(this, &rb, self_info) }); - let input_tys = decl.inputs.map(|a| ty_of_arg(this, &rb, a, None)); + let input_tys = decl.inputs.flat_map(|a| arg_to_ty_list(this, &rb, a, None)); let output_ty = match decl.output.node { ast::ty_infer => this.ty_infer(decl.output.span), @@ -730,14 +767,14 @@ pub fn ty_of_closure( // that function type let rb = rscope::BindingRscope::new(id); - let input_tys = decl.inputs.iter().enumerate().map(|(i, a)| { + let input_tys = decl.inputs.iter().enumerate().to_owned_vec().flat_map(|&(i, a)| { let expected_arg_ty = expected_sig.as_ref().and_then(|e| { // no guarantee that the correct number of expected args // were supplied if i < e.inputs.len() {Some(e.inputs[i])} else {None} }); - ty_of_arg(this, &rb, a, expected_arg_ty) - }).collect(); + arg_to_ty_list(this, &rb, a, expected_arg_ty) + }); let expected_ret_ty = expected_sig.map(|e| e.output); let output_ty = match decl.output.node { diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 6467be93a8e14..3610f769ecff1 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -321,7 +321,7 @@ impl<'self> LookupContext<'self> { let mut self_ty = self_ty; loop { match get(self_ty).sty { - ty_param(p) => { + ty_param(_, p) => { self.push_inherent_candidates_from_param(self_ty, p); } ty_self(..) => { diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 0b6806f759839..184978973e179 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -3917,7 +3917,7 @@ pub fn check_bounds_are_used(ccx: @mut CrateCtxt, ty::walk_ty(ty, |t| { match ty::get(t).sty { - ty::ty_param(param_ty {idx, ..}) => { + ty::ty_param(_, param_ty {idx, ..}) => { debug!("Found use of ty param \\#{}", idx); tps_used[idx] = true; } diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 4a2ddf5f0f229..3a7842ab543c6 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -247,7 +247,7 @@ fn lookup_vtable(vcx: &VtableContext, // If the type is self or a param, we look at the trait/supertrait // bounds to see if they include the trait we are looking for. let vtable_opt = match ty::get(ty).sty { - ty::ty_param(param_ty {idx: n, ..}) => { + ty::ty_param(_, param_ty {idx: n, ..}) => { let type_param_bounds: &[@ty::TraitRef] = vcx.param_env.type_param_bounds[n].trait_bounds; lookup_vtable_from_bounds(vcx, diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index a0264848b4726..ac932e0a9f378 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -542,7 +542,7 @@ impl CoherenceChecker { pub fn ast_type_is_defined_in_local_crate(&self, original_type: &ast::Ty) -> bool { match original_type.node { - ty_path(_, _, path_id) => { + ty_path(_, _, _, path_id) => { match self.crate_context.tcx.def_map.get_copy(&path_id) { DefTy(def_id) | DefStruct(def_id) => { if def_id.crate != LOCAL_CRATE { diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 343808c2fa7af..3866a353eb967 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -37,7 +37,7 @@ use middle::ty::{ty_param_bounds_and_ty}; use middle::ty; use middle::subst::Subst; use middle::typeck::astconv::{AstConv, ty_of_arg}; -use middle::typeck::astconv::{ast_ty_to_ty}; +use middle::typeck::astconv::{ast_ty_to_ty, ast_ty_to_ty_list}; use middle::typeck::astconv; use middle::typeck::rscope::*; use middle::typeck::{CrateCtxt, lookup_def_tcx, no_params, write_ty_to_tcx}; @@ -146,7 +146,7 @@ pub fn get_enum_variant_types(ccx: &CrateCtxt, let result_ty = match variant.node.kind { ast::tuple_variant_kind(ref args) if args.len() > 0 => { let rs = ExplicitRscope; - let input_tys = args.map(|va| ccx.to_ty(&rs, va.ty)); + let input_tys = args.flat_map(|va| ast_ty_to_ty_list(ccx, &rs, va.ty, false)); ty::mk_ctor_fn(tcx, scope, input_tys, enum_ty) } @@ -650,10 +650,10 @@ pub fn convert_struct(ccx: &CrateCtxt, tcx.tcache.insert(local_def(ctor_id), tpt); } else if struct_def.fields[0].node.kind == ast::unnamed_field { // Tuple-like. - let inputs = - struct_def.fields.map( - |field| ccx.tcx.tcache.get( - &local_def(field.node.id)).ty); + let inputs = struct_def.fields.flat_map(|field| { + let rs = ExplicitRscope; + ast_ty_to_ty_list(ccx, &rs, field.node.ty, false) + }); let ctor_fn_ty = ty::mk_ctor_fn(tcx, ctor_id, inputs, selfty); write_ty_to_tcx(tcx, ctor_id, ctor_fn_ty); tcx.tcache.insert(local_def(ctor_id), ty_param_bounds_and_ty { diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index cdbd70ce3a729..d24d3e92b97c1 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -482,7 +482,7 @@ pub fn super_tys(this: &C, a: ty::t, b: ty::t) -> cres { } } - (&ty::ty_param(ref a_p), &ty::ty_param(ref b_p)) if a_p.idx == b_p.idx => { + (&ty::ty_param(false, ref a_p), &ty::ty_param(false, ref b_p)) if a_p.idx == b_p.idx => { Ok(a) } diff --git a/src/librustc/middle/typeck/variance.rs b/src/librustc/middle/typeck/variance.rs index 84dff19e452dd..3cf66637c55e3 100644 --- a/src/librustc/middle/typeck/variance.rs +++ b/src/librustc/middle/typeck/variance.rs @@ -659,7 +659,7 @@ impl<'self> ConstraintContext<'self> { substs, variance); } - ty::ty_param(ty::param_ty { def_id: ref def_id, .. }) => { + ty::ty_param(_, ty::param_ty { def_id: ref def_id, .. }) => { assert_eq!(def_id.crate, ast::LOCAL_CRATE); match self.terms_cx.inferred_map.find(&def_id.node) { Some(&index) => { diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 2b3db1e0a89aa..2324fd7861dfd 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -471,7 +471,7 @@ pub fn ty_to_str(cx: ctxt, typ: t) -> ~str { } ty_infer(infer_ty) => infer_ty.to_str(), ty_err => ~"[type error]", - ty_param(param_ty {idx: id, def_id: did}) => { + ty_param(expand, param_ty {idx: id, def_id: did}) => { let param_def = cx.ty_param_defs.find(&did.node); let ident = match param_def { Some(def) => { @@ -482,7 +482,8 @@ pub fn ty_to_str(cx: ctxt, typ: t) -> ~str { format!("BUG[{:?}]", id) } }; - if !cx.sess.verbose() { ident } else { format!("{}:{:?}", ident, did) } + let s = if !cx.sess.verbose() { ident } else { format!("{}:{:?}", ident, did) }; + if expand { ".." + s } else { s } } ty_self(..) => ~"Self", ty_enum(did, ref substs) | ty_struct(did, ref substs) => { diff --git a/src/librustdoc/clean.rs b/src/librustdoc/clean.rs index ab9fabb08415a..21ffa4e70c73e 100644 --- a/src/librustdoc/clean.rs +++ b/src/librustdoc/clean.rs @@ -628,8 +628,8 @@ impl Clean for ast::Ty { ty_vec(ref m) => Vector(~m.ty.clean()), ty_fixed_length_vec(ref m, ref e) => FixedVector(~m.ty.clean(), e.span.to_src()), - ty_tup(ref tys) => Tuple(tys.iter().map(|x| x.clean()).collect()), - ty_path(ref p, ref tpbs, id) => + ty_tup(false, ref tys) => Tuple(tys.iter().map(|x| x.clean()).collect()), + ty_path(false, ref p, ref tpbs, id) => resolve_type(p.clean(), tpbs.clean(), id), ty_closure(ref c) => Closure(~c.clean()), ty_bare_fn(ref barefn) => BareFunction(~barefn.clean()), diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index e64e16150410d..4d63bebd2aa6f 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -882,8 +882,8 @@ pub enum ty_ { ty_rptr(Option, mt), ty_closure(@TyClosure), ty_bare_fn(@TyBareFn), - ty_tup(~[P]), - ty_path(Path, Option>, NodeId), // for #7264; see above + ty_tup(bool /* expand */, ~[P]), + ty_path(bool /* expand */, Path, Option>, NodeId), // for #7264; see above ty_typeof(@Expr), // ty_infer means the type should be inferred instead of it having been // specified. This should only appear at the "top level" of a type and not diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs index 961d8170fd35d..e52a8cb2c3cb3 100644 --- a/src/libsyntax/ast_map.rs +++ b/src/libsyntax/ast_map.rs @@ -86,7 +86,7 @@ pub fn impl_pretty_name(trait_ref: &Option, ty: &Ty, default: Ident) -> path_elt { let itr = get_ident_interner(); let ty_ident = match ty.node { - ty_path(ref path, _, _) => path.segments.last().identifier, + ty_path(_, ref path, _, _) => path.segments.last().identifier, _ => default }; let hash = (trait_ref, ty).hash(); diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 11a55a4adbc09..9e7c670a1d729 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -506,7 +506,7 @@ impl<'self, O: IdVisitingOperation> Visitor<()> for IdVisitor<'self, O> { fn visit_ty(&mut self, typ: &Ty, env: ()) { self.operation.visit_id(typ.id); match typ.node { - ty_path(_, _, id) => self.operation.visit_id(id), + ty_path(_, _, _, id) => self.operation.visit_id(id), _ => {} } visit::walk_ty(self, typ, env) diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 8a8de3906c4c2..7665d36f42a67 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -292,7 +292,7 @@ impl AstBuilder for @ExtCtxt { fn ty_path(&self, path: ast::Path, bounds: Option>) -> P { self.ty(path.span, - ast::ty_path(path, bounds, ast::DUMMY_NODE_ID)) + ast::ty_path(false, path, bounds, ast::DUMMY_NODE_ID)) } // Might need to take bounds as an argument in the future, if you ever want diff --git a/src/libsyntax/ext/deriving/ty.rs b/src/libsyntax/ext/deriving/ty.rs index 87381d25dc700..bddd842a171cd 100644 --- a/src/libsyntax/ext/deriving/ty.rs +++ b/src/libsyntax/ext/deriving/ty.rs @@ -155,7 +155,7 @@ impl<'self> Ty<'self> { let ty = if fields.is_empty() { ast::ty_nil } else { - ast::ty_tup(fields.map(|f| f.to_ty(cx, span, self_ty, self_generics))) + ast::ty_tup(false, fields.map(|f| f.to_ty(cx, span, self_ty, self_generics))) }; cx.ty(span, ty) diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 3547fa8251b03..cd32698dd0116 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -266,9 +266,9 @@ pub trait ast_fold { decl: fold_fn_decl(f.decl, self) }) } - ty_tup(ref tys) => ty_tup(tys.map(|&ty| self.fold_ty(ty))), - ty_path(ref path, ref bounds, id) => { - ty_path(self.fold_path(path), + ty_tup(expand, ref tys) => ty_tup(expand, tys.map(|&ty| self.fold_ty(ty))), + ty_path(expand, ref path, ref bounds, id) => { + ty_path(expand, self.fold_path(path), fold_opt_bounds(bounds, self), self.new_id(id)) } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 612151f83e442..3ebb590016029 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -658,7 +658,7 @@ mod test { node: ast::item_fn(ast::P(ast::fn_decl{ inputs: ~[ast::arg{ ty: ast::P(ast::Ty{id: ast::DUMMY_NODE_ID, - node: ast::ty_path(ast::Path{ + node: ast::ty_path(false, ast::Path{ span:sp(10,13), global:false, segments: ~[ diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 62bfd7c80f9fd..a983bb2a350c8 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1172,14 +1172,16 @@ impl Parser { } } - // parse a type. - // Useless second parameter for compatibility with quasiquote macros. - // Bleh! - pub fn parse_ty(&self, _: bool) -> P { + // parse a type, optionally expanding within a list of types + pub fn parse_ty_maybe_expand(&self, can_expand: bool) -> P { maybe_whole!(no_clone self, nt_ty); let lo = self.span.lo; + let expand = can_expand && self.eat(&token::DOTDOT); + + let lo_inner = self.span.lo; + let t = if *self.token == token::LPAREN { self.bump(); if *self.token == token::RPAREN { @@ -1189,26 +1191,30 @@ impl Parser { // (t) is a parenthesized ty // (t,) is the type of a tuple with only one field, // of type t - let mut ts = ~[self.parse_ty(false)]; + let mut ts = ~[self.parse_ty_maybe_expand(true)]; let mut one_tuple = false; while *self.token == token::COMMA { self.bump(); if *self.token != token::RPAREN { - ts.push(self.parse_ty(false)); + ts.push(self.parse_ty_maybe_expand(true)); } else { one_tuple = true; } } + self.expect(&token::RPAREN); if ts.len() == 1 && !one_tuple { - self.expect(&token::RPAREN); - return ts[0] + match ts[0].node { + ty_tup(true, _) | ty_path(true, _, _, _) => { + ty_tup(false, ts) /* (..T) */ + } + _ => { ts[0].node.clone() } + } + } else { + ty_tup(false, ts) } - let t = ty_tup(ts); - self.expect(&token::RPAREN); - t } } else if *self.token == token::AT { // MANAGED POINTER @@ -1273,15 +1279,36 @@ impl Parser { path, bounds } = self.parse_path(LifetimeAndTypesAndBounds); - ty_path(path, bounds, ast::DUMMY_NODE_ID) + ty_path(false, path, bounds, ast::DUMMY_NODE_ID) } else { self.fatal(format!("expected type, found token {:?}", *self.token)); }; let sp = mk_sp(lo, self.last_span.hi); + + let t = if expand { + let sp_inner = mk_sp(lo_inner, self.last_span.hi); + match t { + ty_nil => ty_tup(true, ~[]), // FIXME #10784 DRY. + ty_tup(false, fields) => ty_tup(true, fields), + ty_path(false, path, bounds, id) => ty_path(true, path, bounds, id), + _ => { + self.span_err(sp_inner, "expected tuple or path after `..`"); + t + } + } + } else { t }; + P(Ty {id: ast::DUMMY_NODE_ID, node: t, span: sp}) } + // parse a type. + // Useless second parameter for compatibility with quasiquote macros. + // Bleh! + pub fn parse_ty(&self, _: bool) -> P { + self.parse_ty_maybe_expand(false) + } + // parse the type following a @ or a ~ pub fn parse_box_or_uniq_pointee(&self, sigil: ast::Sigil, @@ -1364,7 +1391,7 @@ impl Parser { special_idents::invalid) }; - let t = self.parse_ty(false); + let t = self.parse_ty_maybe_expand(!require_name); ast::arg { ty: t, @@ -3516,7 +3543,7 @@ impl Parser { let lifetimes = self.parse_lifetimes(); let result = self.parse_seq_to_gt( Some(token::COMMA), - |p| p.parse_ty(false)); + |p| p.parse_ty_maybe_expand(true)); (lifetimes, opt_vec::take_vec(result)) } @@ -3931,7 +3958,7 @@ impl Parser { let opt_trait = if could_be_trait && self.eat_keyword(keywords::For) { // New-style trait. Reinterpret the type as a trait. let opt_trait_ref = match ty.node { - ty_path(ref path, None, node_id) => { + ty_path(false, ref path, None, node_id) => { Some(trait_ref { path: /* bad */ (*path).clone(), ref_id: node_id @@ -4022,7 +4049,7 @@ impl Parser { let struct_field_ = ast::struct_field_ { kind: unnamed_field, id: ast::DUMMY_NODE_ID, - ty: p.parse_ty(false), + ty: p.parse_ty_maybe_expand(true), attrs: attrs, }; spanned(lo, p.span.hi, struct_field_) @@ -4473,7 +4500,7 @@ impl Parser { &token::LPAREN, &token::RPAREN, seq_sep_trailing_disallowed(token::COMMA), - |p| p.parse_ty(false) + |p| p.parse_ty_maybe_expand(true) ); for ty in arg_tys.move_iter() { args.push(ast::variant_arg { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 3c6fa86485d21..fcbbeeed0e68c 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -416,7 +416,10 @@ pub fn print_type(s: @ps, ty: &ast::Ty) { print_opt_lifetime(s, lifetime); print_mt(s, mt); } - ast::ty_tup(ref elts) => { + ast::ty_tup(expand, ref elts) => { + if expand { + word(s.s, ".."); + } popen(s); commasep(s, inconsistent, *elts, print_type_ref); if elts.len() == 1 { @@ -442,7 +445,12 @@ pub fn print_type(s: @ps, ty: &ast::Ty) { f.purity, f.onceness, f.decl, None, &f.bounds, Some(&generics), None); } - ast::ty_path(ref path, ref bounds, _) => print_bounded_path(s, path, bounds), + ast::ty_path(expand, ref path, ref bounds, _) => { + if expand { + word(s.s, ".."); + } + print_bounded_path(s, path, bounds); + } ast::ty_fixed_length_vec(ref mt, v) => { word(s.s, "["); match mt.mutbl { diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 985dcd272719d..9c9b95c14088e 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -303,7 +303,8 @@ pub fn walk_ty>(visitor: &mut V, typ: &Ty, env: E) { visitor.visit_opt_lifetime_ref(typ.span, lifetime, env.clone()); visitor.visit_ty(mutable_type.ty, env) } - ty_tup(ref tuple_element_types) => { + ty_tup(_expand, ref tuple_element_types) => { + // FIXME(eddyb) #10769 what to do with expand? for &tuple_element_type in tuple_element_types.iter() { visitor.visit_ty(tuple_element_type, env.clone()) } @@ -331,7 +332,8 @@ pub fn walk_ty>(visitor: &mut V, typ: &Ty, env: E) { walk_lifetime_decls(visitor, &function_declaration.lifetimes, env.clone()); } - ty_path(ref path, ref bounds, _) => { + ty_path(_expand, ref path, ref bounds, _) => { + // FIXME(eddyb) #10769 what to do with expand? walk_path(visitor, path, env.clone()); for bounds in bounds.iter() { walk_ty_param_bounds(visitor, bounds, env.clone()) diff --git a/src/test/compile-fail/tuple-expansion-enum.rs b/src/test/compile-fail/tuple-expansion-enum.rs new file mode 100644 index 0000000000000..63ea850ebb684 --- /dev/null +++ b/src/test/compile-fail/tuple-expansion-enum.rs @@ -0,0 +1,16 @@ +// Copyright 2013 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. + +enum MaybeTup { + SomeTup(..T), //~ ERROR cannot expand non-tuple type `T` + NoTup +} + +fn main() {} diff --git a/src/test/compile-fail/tuple-expansion-fn.rs b/src/test/compile-fail/tuple-expansion-fn.rs new file mode 100644 index 0000000000000..601d056bb67d5 --- /dev/null +++ b/src/test/compile-fail/tuple-expansion-fn.rs @@ -0,0 +1,16 @@ +// Copyright 2013 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. + +// error-pattern: cannot expand non-tuple type `..U` + +// FIXME(eddyb) #10769 these generic substitution errors don't have spans. +fn foo(_: (T, ..U, T)) {} + +fn main() {} diff --git a/src/test/compile-fail/tuple-expansion-generic.rs b/src/test/compile-fail/tuple-expansion-generic.rs new file mode 100644 index 0000000000000..7fcb89a38adc3 --- /dev/null +++ b/src/test/compile-fail/tuple-expansion-generic.rs @@ -0,0 +1,14 @@ +// Copyright 2013 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. + +type Pair = (T, U); +type MaybePair = Pair<..T>; //~ ERROR wrong number of type arguments: expected 2 but found 1 + +fn main() {} diff --git a/src/test/compile-fail/tuple-expansion-impl.rs b/src/test/compile-fail/tuple-expansion-impl.rs new file mode 100644 index 0000000000000..1a0ae54b49120 --- /dev/null +++ b/src/test/compile-fail/tuple-expansion-impl.rs @@ -0,0 +1,19 @@ +// Copyright 2013 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. + +// error-pattern: cannot expand non-tuple type `..T` + +trait Tuple {} + +// FIXME(eddyb) #10769 these generic substitution errors don't have spans. +impl Tuple for (..T) {} +//^ ERROR cannot determine a type for this bounded type parameter: unconstrained type + +fn main() {} diff --git a/src/test/compile-fail/tuple-expansion-parse-type.rs b/src/test/compile-fail/tuple-expansion-parse-type.rs new file mode 100644 index 0000000000000..311beaa1baf45 --- /dev/null +++ b/src/test/compile-fail/tuple-expansion-parse-type.rs @@ -0,0 +1,23 @@ +// Copyright 2013 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. + +type A = ( + ..(u8, i8), + ..~(u8, i8), //~ ERROR expected tuple or path after `..` + ..*(u8, i8), //~ ERROR expected tuple or path after `..` + ..&(u8, i8), //~ ERROR expected tuple or path after `..` + ..[int], //~ ERROR expected tuple or path after `..` + ..[int, ..5], //~ ERROR expected tuple or path after `..` + ..fn(u8, i8) -> int, //~ ERROR expected tuple or path after `..` + ..|u8, i8| -> int, //~ ERROR expected tuple or path after `..` + ..proc(u8, i8) -> int //~ ERROR expected tuple or path after `..` +); + +type B = ..T; //~ ERROR expected type, found token DOTDOT diff --git a/src/test/compile-fail/tuple-expansion-struct.rs b/src/test/compile-fail/tuple-expansion-struct.rs new file mode 100644 index 0000000000000..086d741256b05 --- /dev/null +++ b/src/test/compile-fail/tuple-expansion-struct.rs @@ -0,0 +1,13 @@ +// Copyright 2013 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 Tuple(..T); //~ ERROR cannot expand non-tuple type `T` + +fn main() {} diff --git a/src/test/run-pass/tuple-expansion-type.rs b/src/test/run-pass/tuple-expansion-type.rs new file mode 100644 index 0000000000000..d680c779c2a2d --- /dev/null +++ b/src/test/run-pass/tuple-expansion-type.rs @@ -0,0 +1,49 @@ +// Copyright 2013 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. + +#[feature(macro_rules)]; + +fn same_type(_: Option, _: Option) {} + +macro_rules! ty_eq( + ($T:ty, $U:ty) => (same_type(None::<$T>, None::<$U>)) +) + +fn main() { + type A = (..(u8, i8)); + ty_eq!(A, (u8, i8)); + + type B = (..((u8, i8))); + ty_eq!(B, (u8, i8)); + + type C = fn(..(u8, i8)) -> int; + ty_eq!(C, fn(u8, i8) -> int); + + type D = 'static|..(u8, i8)| -> int; + ty_eq!(D, 'static|u8, i8| -> int); + + type E = proc(..(u8, i8)) -> int; + ty_eq!(E, proc(u8, i8) -> int); + + type F = (T, U, T); + ty_eq!(F, (char, int, char)); + + type G = (..F<..(u8, i8)>); + ty_eq!(G, (u8, i8, u8)); + + type TupleWrap = (T, ..U, T); + ty_eq!(TupleWrap, (char, u8, i8, char)); + + type I = (T, ..F, T); + ty_eq!(I, (char, char, (u8, i8), char, char)); + + type TupleConcat = (..T, ..U); + ty_eq!(TupleConcat<(char, int), (u8, i8)>, (char, int, u8, i8)); +}