From c18a1327e3ccf02ae9f755ca280d53177eeb298d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 7 Nov 2014 06:16:57 -0500 Subject: [PATCH 1/5] Make TyTrait embed a `TraitRef`, so that when we extend TraitRef, it naturally carries over to object types. I wanted to embed an `Rc`, but I was foiled by the current static rules, which prohibit non-Sync values from being stored in static locations. This means that the constants for `ty_int` and so forth cannot be initialized. --- src/librustc/metadata/tydecode.rs | 5 +- src/librustc/metadata/tyencode.rs | 11 ++-- src/librustc/middle/astencode.rs | 42 ++++++------ src/librustc/middle/traits/coherence.rs | 2 +- src/librustc/middle/trans/debuginfo.rs | 10 +-- src/librustc/middle/trans/expr.rs | 6 +- src/librustc/middle/ty.rs | 66 +++++++++++-------- src/librustc/middle/ty_fold.rs | 16 ++--- src/librustc/middle/typeck/astconv.rs | 40 +++++------ src/librustc/middle/typeck/check/method.rs | 45 ++++++------- src/librustc/middle/typeck/check/vtable.rs | 13 ++-- src/librustc/middle/typeck/coherence/mod.rs | 8 +-- .../middle/typeck/coherence/orphan.rs | 25 ++++--- src/librustc/middle/typeck/collect.rs | 14 ++-- src/librustc/middle/typeck/infer/coercion.rs | 29 ++++---- src/librustc/middle/typeck/infer/combine.rs | 10 +-- src/librustc/middle/typeck/infer/mod.rs | 10 +-- src/librustc/middle/typeck/variance.rs | 10 +-- src/librustc/util/ppaux.rs | 8 +-- 19 files changed, 178 insertions(+), 192 deletions(-) diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 227a6f71bfda9..26b2afd2f3c31 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -389,11 +389,10 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t { } 'x' => { assert_eq!(next(st), '['); - let def = parse_def(st, NominalType, |x,y| conv(x,y)); - let substs = parse_substs(st, |x,y| conv(x,y)); + let trait_ref = parse_trait_ref(st, |x,y| conv(x,y)); let bounds = parse_existential_bounds(st, |x,y| conv(x,y)); assert_eq!(next(st), ']'); - return ty::mk_trait(st.tcx, def, substs, bounds); + return ty::mk_trait(st.tcx, trait_ref, bounds); } 'p' => { let did = parse_def(st, TypeParameter, |x,y| conv(x,y)); diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 027b9980a32b9..a7b64cb20e588 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -231,13 +231,10 @@ fn enc_sty(w: &mut SeekableMemWriter, cx: &ctxt, st: &ty::sty) { enc_substs(w, cx, substs); mywrite!(w, "]"); } - ty::ty_trait(box ty::TyTrait { - def_id, - ref substs, - ref bounds - }) => { - mywrite!(w, "x[{}|", (cx.ds)(def_id)); - enc_substs(w, cx, substs); + ty::ty_trait(box ty::TyTrait { ref principal, + ref bounds }) => { + mywrite!(w, "x["); + enc_trait_ref(w, cx, principal); enc_existential_bounds(w, cx, bounds); mywrite!(w, "]"); } diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 9268418ef94e9..aaf3b16c5eedb 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -1085,16 +1085,19 @@ impl<'a> rbml_writer_helpers for Encoder<'a> { this.emit_enum_variant_arg(1, |this| idx.encode(this)) }) } - ty::UnsizeVtable(ty::TyTrait { def_id, - bounds: ref b, - ref substs }, + ty::UnsizeVtable(ty::TyTrait { ref principal, + bounds: ref b }, self_ty) => { this.emit_enum_variant("UnsizeVtable", 2, 4, |this| { - this.emit_enum_variant_arg( - 0, |this| Ok(this.emit_existential_bounds(ecx, b))); - this.emit_enum_variant_arg(1, |this| def_id.encode(this)); - this.emit_enum_variant_arg(2, |this| Ok(this.emit_ty(ecx, self_ty))); - this.emit_enum_variant_arg(3, |this| Ok(this.emit_substs(ecx, substs))) + this.emit_enum_variant_arg(0, |this| { + try!(this.emit_struct_field("principal", 0, |this| { + Ok(this.emit_trait_ref(ecx, &*principal)) + })); + this.emit_struct_field("bounds", 1, |this| { + Ok(this.emit_existential_bounds(ecx, b)) + }) + }); + this.emit_enum_variant_arg(1, |this| Ok(this.emit_ty(ecx, self_ty))) }) } } @@ -1693,18 +1696,19 @@ impl<'a> rbml_decoder_decoder_helpers for reader::Decoder<'a> { ty::UnsizeStruct(box uk, idx) } 2 => { - let b = - this.read_enum_variant_arg( - 0, |this| Ok(this.read_existential_bounds(dcx))).unwrap(); - let def_id: ast::DefId = - this.read_enum_variant_arg(1, |this| Decodable::decode(this)).unwrap(); + let ty_trait = try!(this.read_enum_variant_arg(0, |this| { + let principal = try!(this.read_struct_field("principal", 0, |this| { + Ok(this.read_trait_ref(dcx)) + })); + Ok(ty::TyTrait { + principal: (*principal).clone(), + bounds: try!(this.read_struct_field("bounds", 1, |this| { + Ok(this.read_existential_bounds(dcx)) + })), + }) + })); let self_ty = - this.read_enum_variant_arg(2, |this| Ok(this.read_ty(dcx))).unwrap(); - let substs = this.read_enum_variant_arg(3, - |this| Ok(this.read_substs(dcx))).unwrap(); - let ty_trait = ty::TyTrait { def_id: def_id.tr(dcx), - bounds: b, - substs: substs }; + this.read_enum_variant_arg(1, |this| Ok(this.read_ty(dcx))).unwrap(); ty::UnsizeVtable(ty_trait, self_ty) } _ => panic!("bad enum variant for ty::UnsizeKind") diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs index 09490f9bdf7e9..9900620b229da 100644 --- a/src/librustc/middle/traits/coherence.rs +++ b/src/librustc/middle/traits/coherence.rs @@ -143,7 +143,7 @@ pub fn ty_is_local(tcx: &ty::ctxt, } ty::ty_trait(ref tt) => { - tt.def_id.krate == ast::LOCAL_CRATE + tt.principal.def_id.krate == ast::LOCAL_CRATE } // Type parameters may be bound to types that are not local to diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 8309811cf0b45..5b2e978e11fee 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -423,8 +423,8 @@ impl TypeMap { from_def_id_and_substs(self, cx, - trait_data.def_id, - &trait_data.substs, + trait_data.principal.def_id, + &trait_data.principal.substs, &mut unique_type_id); }, ty::ty_bare_fn(ty::BareFnTy{ fn_style, abi, ref sig } ) => { @@ -2813,7 +2813,7 @@ fn trait_pointer_metadata(cx: &CrateContext, // But it does not describe the trait's methods. let def_id = match ty::get(trait_type).sty { - ty::ty_trait(box ty::TyTrait { def_id, .. }) => def_id, + ty::ty_trait(box ty::TyTrait { ref principal, .. }) => principal.def_id, _ => { let pp_type_name = ppaux::ty_to_string(cx.tcx(), trait_type); cx.sess().bug(format!("debuginfo: Unexpected trait-object type in \ @@ -3739,8 +3739,8 @@ fn push_debuginfo_type_name(cx: &CrateContext, output.push(']'); }, ty::ty_trait(ref trait_data) => { - push_item_name(cx, trait_data.def_id, false, output); - push_type_params(cx, &trait_data.substs, output); + push_item_name(cx, trait_data.principal.def_id, false, output); + push_type_params(cx, &trait_data.principal.substs, output); }, ty::ty_bare_fn(ty::BareFnTy{ fn_style, abi, ref sig } ) => { if fn_style == ast::UnsafeFn { diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 399be73329bd5..4b61f0c140911 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -324,10 +324,10 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, _ => bcx.sess().bug(format!("UnsizeStruct with bad sty: {}", bcx.ty_to_string(unsized_ty)).as_slice()) }, - &ty::UnsizeVtable(ty::TyTrait { def_id, ref substs, .. }, _) => { - let substs = substs.with_self_ty(unsized_ty); + &ty::UnsizeVtable(ty::TyTrait { ref principal, .. }, _) => { + let substs = principal.substs.with_self_ty(unsized_ty); let trait_ref = - Rc::new(ty::TraitRef { def_id: def_id, + Rc::new(ty::TraitRef { def_id: principal.def_id, substs: substs }); let trait_ref = trait_ref.subst(bcx.tcx(), &bcx.fcx.param_substs.substs); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index d1baeac81ab3a..3e8a7bb842ca8 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -378,14 +378,14 @@ pub fn type_of_adjust(cx: &ctxt, adj: &AutoAdjustment) -> Option { fn type_of_autoref(cx: &ctxt, autoref: &AutoRef) -> Option { match autoref { &AutoUnsize(ref k) => match k { - &UnsizeVtable(TyTrait { def_id, ref substs, bounds }, _) => { - Some(mk_trait(cx, def_id, substs.clone(), bounds)) + &UnsizeVtable(TyTrait { ref principal, bounds }, _) => { + Some(mk_trait(cx, (*principal).clone(), bounds)) } _ => None }, &AutoUnsizeUniq(ref k) => match k { - &UnsizeVtable(TyTrait { def_id, ref substs, bounds }, _) => { - Some(mk_uniq(cx, mk_trait(cx, def_id, substs.clone(), bounds))) + &UnsizeVtable(TyTrait { ref principal, bounds }, _) => { + Some(mk_uniq(cx, mk_trait(cx, (*principal).clone(), bounds))) } _ => None }, @@ -983,12 +983,12 @@ pub enum sty { #[deriving(Clone, PartialEq, Eq, Hash, Show)] pub struct TyTrait { - pub def_id: DefId, - pub substs: Substs, + // Principal trait reference. + pub principal: TraitRef, // would use Rc, but it runs afoul of some static rules pub bounds: ExistentialBounds } -#[deriving(PartialEq, Eq, Hash, Show)] +#[deriving(Clone, PartialEq, Eq, Hash, Show)] pub struct TraitRef { pub def_id: DefId, pub substs: Substs, @@ -1643,8 +1643,8 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t { &ty_enum(_, ref substs) | &ty_struct(_, ref substs) => { flags = flags | sflags(substs); } - &ty_trait(box TyTrait { ref substs, ref bounds, .. }) => { - flags = flags | sflags(substs); + &ty_trait(box TyTrait { ref principal, ref bounds }) => { + flags = flags | sflags(&principal.substs); flags = flags | flags_for_bounds(bounds); } &ty_uniq(tt) | &ty_vec(tt, _) | &ty_open(tt) => { @@ -1874,14 +1874,12 @@ pub fn mk_ctor_fn(cx: &ctxt, pub fn mk_trait(cx: &ctxt, - did: ast::DefId, - substs: Substs, + principal: ty::TraitRef, bounds: ExistentialBounds) -> t { // take a copy of substs so that we own the vectors inside let inner = box TyTrait { - def_id: did, - substs: substs, + principal: principal, bounds: bounds }; mk_t(cx, ty_trait(inner)) @@ -1934,9 +1932,15 @@ pub fn maybe_walk_ty(ty: t, f: |t| -> bool) { ty_ptr(ref tm) | ty_rptr(_, ref tm) => { maybe_walk_ty(tm.ty, f); } - ty_enum(_, ref substs) | ty_struct(_, ref substs) | ty_unboxed_closure(_, _, ref substs) | - ty_trait(box TyTrait { ref substs, .. }) => { - for subty in (*substs).types.iter() { + ty_trait(box TyTrait { ref principal, .. }) => { + for subty in principal.substs.types.iter() { + maybe_walk_ty(*subty, |x| f(x)); + } + } + ty_enum(_, ref substs) | + ty_struct(_, ref substs) | + ty_unboxed_closure(_, _, ref substs) => { + for subty in substs.types.iter() { maybe_walk_ty(*subty, |x| f(x)); } } @@ -3554,8 +3558,8 @@ pub fn unsize_ty(cx: &ctxt, format!("UnsizeStruct with bad sty: {}", ty_to_string(cx, ty)).as_slice()) }, - &UnsizeVtable(TyTrait { def_id, ref substs, bounds }, _) => { - mk_trait(cx, def_id, substs.clone(), bounds) + &UnsizeVtable(TyTrait { ref principal, bounds }, _) => { + mk_trait(cx, (*principal).clone(), bounds) } } } @@ -3808,7 +3812,7 @@ pub fn ty_sort_string(cx: &ctxt, t: t) -> String { ty_bare_fn(_) => "extern fn".to_string(), ty_closure(_) => "fn".to_string(), ty_trait(ref inner) => { - format!("trait {}", item_path_str(cx, inner.def_id)) + format!("trait {}", item_path_str(cx, inner.principal.def_id)) } ty_struct(id, _) => { format!("struct {}", item_path_str(cx, id)) @@ -4230,11 +4234,14 @@ pub fn try_add_builtin_trait( pub fn ty_to_def_id(ty: t) -> Option { match get(ty).sty { - ty_trait(box TyTrait { def_id: id, .. }) | + ty_trait(ref tt) => + Some(tt.principal.def_id), ty_struct(id, _) | ty_enum(id, _) | - ty_unboxed_closure(id, _, _) => Some(id), - _ => None + ty_unboxed_closure(id, _, _) => + Some(id), + _ => + None } } @@ -5213,9 +5220,9 @@ pub fn hash_crate_independent(tcx: &ctxt, t: t, svh: &Svh) -> u64 { } } } - ty_trait(box TyTrait { def_id: d, bounds, .. }) => { + ty_trait(box TyTrait { ref principal, bounds }) => { byte!(17); - did(&mut state, d); + did(&mut state, principal.def_id); hash!(bounds); } ty_struct(d, _) => { @@ -5504,12 +5511,13 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec, typ: t) { walk_ty(typ, |typ| { match get(typ).sty { - ty_rptr(region, _) => accumulator.push(region), + ty_rptr(region, _) => { + accumulator.push(region) + } + ty_trait(ref t) => { + accumulator.push_all(t.principal.substs.regions().as_slice()); + } ty_enum(_, ref substs) | - ty_trait(box TyTrait { - ref substs, - .. - }) | ty_struct(_, ref substs) => { accum_substs(accumulator, substs); } diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index a96e81ce20bb4..2b83da35c3ba8 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -373,12 +373,11 @@ impl TypeFoldable for ty::UnsizeKind { match *self { ty::UnsizeLength(len) => ty::UnsizeLength(len), ty::UnsizeStruct(box ref k, n) => ty::UnsizeStruct(box k.fold_with(folder), n), - ty::UnsizeVtable(ty::TyTrait{bounds, def_id, ref substs}, self_ty) => { + ty::UnsizeVtable(ty::TyTrait{ref principal, bounds}, self_ty) => { ty::UnsizeVtable( ty::TyTrait { + principal: principal.fold_with(folder), bounds: bounds.fold_with(folder), - def_id: def_id, - substs: substs.fold_with(folder) }, self_ty.fold_with(folder)) } @@ -529,15 +528,10 @@ pub fn super_fold_sty<'tcx, T: TypeFolder<'tcx>>(this: &mut T, ty::ty_enum(tid, ref substs) => { ty::ty_enum(tid, substs.fold_with(this)) } - ty::ty_trait(box ty::TyTrait { - def_id, - ref substs, - bounds - }) => { + ty::ty_trait(box ty::TyTrait { ref principal, bounds }) => { ty::ty_trait(box ty::TyTrait { - def_id: def_id, - substs: substs.fold_with(this), - bounds: this.fold_existential_bounds(bounds), + principal: (*principal).fold_with(this), + bounds: bounds.fold_with(this), }) } ty::ty_tup(ref ts) => { diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index ae0bbd617e233..6430362f9cdfd 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -405,11 +405,11 @@ pub fn ast_path_to_trait_ref<'tcx,AC,RS>(this: &AC, associated_type: Option, path: &ast::Path, binder_id: ast::NodeId) - -> Rc + -> ty::TraitRef where AC: AstConv<'tcx>, RS: RegionScope { let trait_def = this.get_trait_def(trait_def_id); - Rc::new(ty::TraitRef { + ty::TraitRef { def_id: trait_def_id, substs: ast_path_substs(this, rscope, @@ -419,7 +419,7 @@ pub fn ast_path_to_trait_ref<'tcx,AC,RS>(this: &AC, associated_type, path, binder_id) - }) + } } pub fn ast_path_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( @@ -702,26 +702,17 @@ fn mk_pointer<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( None, path, id); - let bounds = match *opt_bounds { - None => { - conv_existential_bounds(this, - rscope, - path.span, - [result.clone()].as_slice(), - [].as_slice()) - } - Some(ref bounds) => { - conv_existential_bounds(this, - rscope, - path.span, - [result.clone()].as_slice(), - bounds.as_slice()) - } - }; + let empty_vec = []; + let bounds = match *opt_bounds { None => empty_vec.as_slice(), + Some(ref bounds) => bounds.as_slice() }; + let existential_bounds = conv_existential_bounds(this, + rscope, + path.span, + &[Rc::new(result.clone())], + bounds); let tr = ty::mk_trait(tcx, - result.def_id, - result.substs.clone(), - bounds); + result, + existential_bounds); return match ptr_ty { Uniq => { return ty::mk_uniq(tcx, tr); @@ -943,11 +934,10 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( let bounds = conv_existential_bounds(this, rscope, ast_ty.span, - &[result.clone()], + &[Rc::new(result.clone())], ast_bounds); ty::mk_trait(tcx, - result.def_id, - result.substs.clone(), + result, bounds) } def::DefTy(did, _) | def::DefStruct(did) => { diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index ef616a4a07afe..6280fce035a6c 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -632,9 +632,9 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { let span = self.self_expr.map_or(self.span, |e| e.span); check::autoderef(self.fcx, span, self_ty, None, NoPreference, |self_ty, _| { match get(self_ty).sty { - ty_trait(box TyTrait { def_id, ref substs, bounds, .. }) => { - self.push_inherent_candidates_from_object(self_ty, def_id, substs, bounds); - self.push_inherent_impl_candidates_for_type(def_id); + ty_trait(box TyTrait { ref principal, bounds, .. }) => { + self.push_inherent_candidates_from_object(self_ty, &*principal, bounds); + self.push_inherent_impl_candidates_for_type(principal.def_id); } ty_enum(did, _) | ty_struct(did, _) | @@ -744,24 +744,23 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { fn push_inherent_candidates_from_object(&mut self, self_ty: ty::t, - did: DefId, - substs: &subst::Substs, + principal: &ty::TraitRef, _bounds: ty::ExistentialBounds) { debug!("push_inherent_candidates_from_object(self_ty={})", self_ty.repr(self.tcx())); let tcx = self.tcx(); - // It is illegal to invoke a method on a trait instance that refers to - // the `Self` type. Here, we use a substitution that replaces `Self` - // with the object type itself. Hence, a `&self` method will wind up - // with an argument type like `&Trait`. - let rcvr_substs = substs.with_self_ty(self_ty); - - let trait_ref = Rc::new(TraitRef { - def_id: did, - substs: rcvr_substs.clone() - }); + // It is illegal to invoke a method on a trait instance that + // refers to the `Self` type. An error will be reported by + // `enforce_object_limitations()` if the method refers to the + // `Self` type anywhere other than the receiver. Here, we use + // a substitution that replaces `Self` with the object type + // itself. Hence, a `&self` method will wind up with an + // argument type like `&Trait`. + let rcvr_substs = principal.substs.with_self_ty(self_ty); + let trait_ref = Rc::new(TraitRef { def_id: principal.def_id, + substs: rcvr_substs.clone() }); self.push_inherent_candidates_from_bounds_inner( &[trait_ref.clone()], @@ -796,7 +795,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { method_ty: m, origin: MethodTraitObject(MethodObject { trait_ref: new_trait_ref, - object_trait_id: did, + object_trait_id: principal.def_id, method_num: method_num, real_index: vtable_index }) @@ -1151,17 +1150,19 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { fn auto_slice_trait(&self, ty: ty::t, autoderefs: uint) -> Option { debug!("auto_slice_trait"); match ty::get(ty).sty { - ty_trait(box ty::TyTrait { - def_id: trt_did, - substs: ref trt_substs, - bounds: b, - .. }) => { + ty_trait(box ty::TyTrait { ref principal, + bounds: b, + .. }) => { + let trt_did = principal.def_id; + let trt_substs = &principal.substs; let tcx = self.tcx(); self.search_for_some_kind_of_autorefd_method( |r, m| AutoPtr(r, m, None), autoderefs, [MutImmutable, MutMutable], |m, r| { - let tr = ty::mk_trait(tcx, trt_did, trt_substs.clone(), b); + let principal = ty::TraitRef::new(trt_did, + trt_substs.clone()); + let tr = ty::mk_trait(tcx, principal, b); ty::mk_rptr(tcx, r, ty::mt{ ty: tr, mutbl: m }) }) } diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 2fcce4cc3dcfd..498594716e7ab 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -140,11 +140,11 @@ pub fn check_object_safety(tcx: &ty::ctxt, object_trait: &ty::TyTrait, span: Spa // `call_once` which is the method which takes self by value. What could go // wrong? match tcx.lang_items.fn_once_trait() { - Some(def_id) if def_id == object_trait.def_id => return, + Some(def_id) if def_id == object_trait.principal.def_id => return, _ => {} } - let trait_items = ty::trait_items(tcx, object_trait.def_id); + let trait_items = ty::trait_items(tcx, object_trait.principal.def_id); let mut errors = Vec::new(); for item in trait_items.iter() { @@ -158,7 +158,7 @@ pub fn check_object_safety(tcx: &ty::ctxt, object_trait: &ty::TyTrait, span: Spa let mut errors = errors.iter().flat_map(|x| x.iter()).peekable(); if errors.peek().is_some() { - let trait_name = ty::item_path_str(tcx, object_trait.def_id); + let trait_name = ty::item_path_str(tcx, object_trait.principal.def_id); span_err!(tcx.sess, span, E0038, "cannot convert to a trait object because trait `{}` is not object-safe", trait_name); @@ -241,8 +241,7 @@ pub fn register_object_cast_obligations(fcx: &FnCtxt, // needs some refactoring so there is a more convenient type to pass around. let object_trait_ty = ty::mk_trait(fcx.tcx(), - object_trait.def_id, - object_trait.substs.clone(), + object_trait.principal.clone(), object_trait.bounds); debug!("register_object_cast_obligations: referent_ty={} object_trait_ty={}", @@ -252,13 +251,13 @@ pub fn register_object_cast_obligations(fcx: &FnCtxt, // Take the type parameters from the object type, but set // the Self type (which is unknown, for the object type) // to be the type we are casting from. - let mut object_substs = object_trait.substs.clone(); + let mut object_substs = object_trait.principal.substs.clone(); assert!(object_substs.self_ty().is_none()); object_substs.types.push(SelfSpace, referent_ty); // Create the obligation for casting from T to Trait. let object_trait_ref = - Rc::new(ty::TraitRef { def_id: object_trait.def_id, + Rc::new(ty::TraitRef { def_id: object_trait.principal.def_id, substs: object_substs }); let object_obligation = Obligation::new( diff --git a/src/librustc/middle/typeck/coherence/mod.rs b/src/librustc/middle/typeck/coherence/mod.rs index 19ff82469b515..898d987ace7cb 100644 --- a/src/librustc/middle/typeck/coherence/mod.rs +++ b/src/librustc/middle/typeck/coherence/mod.rs @@ -112,8 +112,8 @@ fn get_base_type_def_id(inference_context: &InferCtxt, ty_rptr(_, ty::mt {ty, ..}) | ty_uniq(ty) => { match ty::get(ty).sty { - ty_trait(box ty::TyTrait { def_id, .. }) => { - Some(def_id) + ty_trait(box ty::TyTrait { ref principal, .. }) => { + Some(principal.def_id) } _ => { panic!("get_base_type() returned a type that wasn't an \ @@ -121,8 +121,8 @@ fn get_base_type_def_id(inference_context: &InferCtxt, } } } - ty_trait(box ty::TyTrait { def_id, .. }) => { - Some(def_id) + ty_trait(box ty::TyTrait { ref principal, .. }) => { + Some(principal.def_id) } _ => { panic!("get_base_type() returned a type that wasn't an \ diff --git a/src/librustc/middle/typeck/coherence/orphan.rs b/src/librustc/middle/typeck/coherence/orphan.rs index 3c4ad3473610c..ba362fb878c81 100644 --- a/src/librustc/middle/typeck/coherence/orphan.rs +++ b/src/librustc/middle/typeck/coherence/orphan.rs @@ -18,6 +18,7 @@ use middle::ty; use syntax::ast::{Item, ItemImpl}; use syntax::ast; use syntax::ast_util; +use syntax::codemap::Span; use syntax::visit; use util::ppaux::Repr; @@ -30,6 +31,17 @@ struct OrphanChecker<'cx, 'tcx:'cx> { tcx: &'cx ty::ctxt<'tcx> } +impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { + fn check_def_id(&self, span: Span, def_id: ast::DefId) { + if def_id.krate != ast::LOCAL_CRATE { + span_err!(self.tcx.sess, span, E0116, + "cannot associate methods with a type outside the \ + crate the type is defined in; define and implement \ + a trait or new type instead"); + } + } +} + impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> { fn visit_item(&mut self, item: &'v ast::Item) { let def_id = ast_util::local_def(item.id); @@ -41,14 +53,11 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> { let self_ty = ty::lookup_item_type(self.tcx, def_id).ty; match ty::get(self_ty).sty { ty::ty_enum(def_id, _) | - ty::ty_struct(def_id, _) | - ty::ty_trait(box ty::TyTrait{ def_id, ..}) => { - if def_id.krate != ast::LOCAL_CRATE { - span_err!(self.tcx.sess, item.span, E0116, - "cannot associate methods with a type outside the \ - crate the type is defined in; define and implement \ - a trait or new type instead"); - } + ty::ty_struct(def_id, _) => { + self.check_def_id(item.span, def_id); + } + ty::ty_trait(box ty::TyTrait{ ref principal, ..}) => { + self.check_def_id(item.span, principal.def_id); } _ => { span_err!(self.tcx.sess, item.span, E0118, diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index ae2073f6316ea..d365c54c70121 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -1335,13 +1335,13 @@ pub fn instantiate_trait_ref<'tcx,AC>(this: &AC, ast_trait_ref.ref_id) { def::DefTrait(trait_did) => { let trait_ref = - astconv::ast_path_to_trait_ref(this, - &rscope, - trait_did, - Some(self_ty), - associated_type, - &ast_trait_ref.path, - ast_trait_ref.ref_id); + Rc::new(astconv::ast_path_to_trait_ref(this, + &rscope, + trait_did, + Some(self_ty), + associated_type, + &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/coercion.rs b/src/librustc/middle/typeck/infer/coercion.rs index e44aa3e8221b8..718d70050a08e 100644 --- a/src/librustc/middle/typeck/infer/coercion.rs +++ b/src/librustc/middle/typeck/infer/coercion.rs @@ -413,15 +413,14 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let ty = ty::mk_vec(tcx, t_a, None); Some((ty, ty::UnsizeLength(len))) } - (&ty::ty_trait(..), &ty::ty_trait(..)) => None, - (_, &ty::ty_trait(box ty::TyTrait { def_id, ref substs, bounds })) => { - let ty = ty::mk_trait(tcx, - def_id, - substs.clone(), - bounds); - Some((ty, ty::UnsizeVtable(ty::TyTrait { def_id: def_id, - bounds: bounds, - substs: substs.clone() }, + (&ty::ty_trait(..), &ty::ty_trait(..)) => { + None + } + (_, &ty::ty_trait(box ty::TyTrait { ref principal, bounds })) => { + // FIXME what is the purpose of `ty`? + let ty = ty::mk_trait(tcx, (*principal).clone(), bounds); + Some((ty, ty::UnsizeVtable(ty::TyTrait { principal: (*principal).clone(), + bounds: bounds }, ty_a))) } (&ty::ty_struct(did_a, ref substs_a), &ty::ty_struct(did_b, ref substs_b)) @@ -524,16 +523,10 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { match *sty_a { ty::ty_rptr(_, ty::mt{ty, mutbl}) => match ty::get(ty).sty { - ty::ty_trait(box ty::TyTrait { - def_id, - ref substs, - bounds, - .. - }) => - { + ty::ty_trait(box ty::TyTrait { ref principal, bounds }) => { debug!("mutbl={} b_mutbl={}", mutbl, b_mutbl); - - let tr = ty::mk_trait(tcx, def_id, substs.clone(), bounds); + // FIXME what is purpose of this type `tr`? + let tr = ty::mk_trait(tcx, (*principal).clone(), bounds); try!(self.subtype(mk_ty(tr), b)); Ok(Some(AdjustDerefRef(AutoDerefRef { autoderefs: 1, diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index e51eb331cdc37..ab3ec4991c39b 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -461,15 +461,11 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C, a: ty::t, b: ty::t) -> cres { + &ty::ty_trait(ref b_)) => { debug!("Trying to match traits {} and {}", a, b); - let substs = try!(this.substs(a_.def_id, &a_.substs, &b_.substs)); + let principal = try!(this.trait_refs(&a_.principal, &b_.principal)); let bounds = try!(this.existential_bounds(a_.bounds, b_.bounds)); - Ok(ty::mk_trait(tcx, - a_.def_id, - substs.clone(), - bounds)) + Ok(ty::mk_trait(tcx, principal, bounds)) } (&ty::ty_struct(a_id, ref a_substs), &ty::ty_struct(b_id, ref b_substs)) diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index 55c3c23685357..23000949115c3 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -856,16 +856,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { -> ty::TraitRef { // make up a dummy type just to reuse/abuse the resolve machinery let dummy0 = ty::mk_trait(self.tcx, - trait_ref.def_id, - trait_ref.substs.clone(), + (*trait_ref).clone(), ty::region_existential_bound(ty::ReStatic)); let dummy1 = self.resolve_type_vars_if_possible(dummy0); match ty::get(dummy1).sty { - ty::ty_trait(box ty::TyTrait { ref def_id, ref substs, .. }) => { - ty::TraitRef { - def_id: *def_id, - substs: (*substs).clone(), - } + ty::ty_trait(box ty::TyTrait { ref principal, .. }) => { + (*principal).clone() } _ => { self.tcx.sess.bug( diff --git a/src/librustc/middle/typeck/variance.rs b/src/librustc/middle/typeck/variance.rs index 4227cc521b48b..b6d8c85fa0b7c 100644 --- a/src/librustc/middle/typeck/variance.rs +++ b/src/librustc/middle/typeck/variance.rs @@ -778,14 +778,14 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { variance); } - ty::ty_trait(box ty::TyTrait { def_id, ref substs, bounds }) => { - let trait_def = ty::lookup_trait_def(self.tcx(), def_id); + ty::ty_trait(box ty::TyTrait { ref principal, bounds }) => { + let trait_def = ty::lookup_trait_def(self.tcx(), principal.def_id); let generics = &trait_def.generics; // Traits DO have a Self type parameter, but it is // erased from object types. assert!(!generics.types.is_empty_in(subst::SelfSpace) && - substs.types.is_empty_in(subst::SelfSpace)); + principal.substs.types.is_empty_in(subst::SelfSpace)); // Traits never declare region parameters in the self // space. @@ -801,10 +801,10 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { self.add_constraints_from_region(bounds.region_bound, contra); self.add_constraints_from_substs( - def_id, + principal.def_id, generics.types.get_slice(subst::TypeSpace), generics.regions.get_slice(subst::TypeSpace), - substs, + &principal.substs, variance); } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 9080b12c5436a..60a7436dbaa19 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -435,12 +435,12 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String { parameterized(cx, base.as_slice(), substs, &generics) } ty_trait(box ty::TyTrait { - def_id: did, ref substs, ref bounds + ref principal, ref bounds }) => { - let base = ty::item_path_str(cx, did); - let trait_def = ty::lookup_trait_def(cx, did); + let base = ty::item_path_str(cx, principal.def_id); + let trait_def = ty::lookup_trait_def(cx, principal.def_id); let ty = parameterized(cx, base.as_slice(), - substs, &trait_def.generics); + &principal.substs, &trait_def.generics); let bound_str = bounds.user_string(cx); let bound_sep = if bound_str.is_empty() { "" } else { "+" }; format!("{}{}{}", From 244231720d29db856c5a28c0dda6c2efd7c9219a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 7 Nov 2014 06:53:45 -0500 Subject: [PATCH 2/5] Update parser with `for` syntax --- src/librustc/lint/builtin.rs | 4 +- src/librustc/middle/privacy.rs | 4 +- src/librustc/middle/resolve.rs | 30 +- src/librustc/middle/resolve_lifetime.rs | 161 +++++---- src/librustc/middle/save/mod.rs | 3 +- src/librustc/middle/ty.rs | 3 +- src/librustc/middle/typeck/astconv.rs | 88 ++--- src/librustc/middle/typeck/collect.rs | 98 ++---- src/librustc/middle/typeck/infer/combine.rs | 1 - .../middle/typeck/infer/error_reporting.rs | 13 +- src/librustdoc/clean/mod.rs | 9 +- src/libsyntax/ast.rs | 20 +- src/libsyntax/ast_map/mod.rs | 2 +- src/libsyntax/ext/build.rs | 15 +- src/libsyntax/ext/deriving/generic/ty.rs | 4 +- src/libsyntax/fold.rs | 24 +- src/libsyntax/parse/parser.rs | 310 ++++++++++-------- src/libsyntax/print/pprust.rs | 31 +- src/libsyntax/visit.rs | 29 +- src/test/compile-fail/issue-10291.rs | 2 +- .../regions-fn-subtyping-return-static.rs | 4 +- src/test/compile-fail/regions-fn-subtyping.rs | 24 +- .../compile-fail/regions-name-undeclared.rs | 12 +- src/test/compile-fail/regions-nested-fns-2.rs | 2 +- src/test/compile-fail/regions-nested-fns.rs | 4 +- .../compile-fail/regions-ret-borrowed-1.rs | 2 +- src/test/run-pass/hrtb-parse.rs | 48 +++ .../run-pass/nullable-pointer-ffi-compat.rs | 2 +- 28 files changed, 544 insertions(+), 405 deletions(-) create mode 100644 src/test/run-pass/hrtb-parse.rs diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 2858a83008143..6f1287014d776 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -1690,8 +1690,8 @@ impl LintPass for Stability { for t in supertraits.iter() { match *t { ast::TraitTyParamBound(ref t) => { - let id = ty::trait_ref_to_def_id(cx.tcx, t); - self.lint(cx, id, t.path.span); + let id = ty::trait_ref_to_def_id(cx.tcx, &t.trait_ref); + self.lint(cx, id, t.trait_ref.path.span); } _ => (/* pass */) } diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 21b94babcb6a4..eddd616e616e0 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -1291,7 +1291,7 @@ impl<'a, 'tcx> VisiblePrivateTypesVisitor<'a, 'tcx> { match *ty_param_bound { ast::TraitTyParamBound(ref trait_ref) => { if !self.tcx.sess.features.borrow().visible_private_types && - self.path_is_private_type(trait_ref.ref_id) { + self.path_is_private_type(trait_ref.trait_ref.ref_id) { self.tcx.sess.span_err(span, "private type in exported type \ parameter bound"); @@ -1432,7 +1432,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> { // // Those in 2. are warned via walk_generics and this // call here. - visit::walk_trait_ref_helper(self, tr) + self.visit_trait_ref(tr) } } } else if trait_ref.is_none() && self_is_public_path { diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index a1a8cccf55a4b..62d1e13d41f06 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -33,12 +33,12 @@ use syntax::ast::{ItemTrait, ItemTy, LOCAL_CRATE, Local, ItemConst}; use syntax::ast::{MethodImplItem, Mod, Name, NamedField, NodeId}; use syntax::ast::{Pat, PatEnum, PatIdent, PatLit}; use syntax::ast::{PatRange, PatStruct, Path, PathListIdent, PathListMod}; -use syntax::ast::{PrimTy, Public, SelfExplicit, SelfStatic}; +use syntax::ast::{PolyTraitRef, PrimTy, Public, SelfExplicit, SelfStatic}; use syntax::ast::{RegionTyParamBound, StmtDecl, StructField}; use syntax::ast::{StructVariantKind, TraitRef, TraitTyParamBound}; use syntax::ast::{TupleVariantKind, Ty, TyBool, TyChar, TyClosure, TyF32}; use syntax::ast::{TyF64, TyFloat, TyI, TyI8, TyI16, TyI32, TyI64, TyInt}; -use syntax::ast::{TyParam, TyParamBound, TyPath, TyPtr, TyProc, TyQPath}; +use syntax::ast::{TyParam, TyParamBound, TyPath, TyPtr, TyPolyTraitRef, TyProc, TyQPath}; use syntax::ast::{TyRptr, TyStr, TyU, TyU8, TyU16, TyU32, TyU64, TyUint}; use syntax::ast::{TypeImplItem, UnnamedField}; use syntax::ast::{Variant, ViewItem, ViewItemExternCrate}; @@ -607,6 +607,7 @@ enum TraitReferenceType { TraitImplementation, // impl SomeTrait for T { ... } TraitDerivation, // trait T : SomeTrait { ... } TraitBoundingTypeParameter, // fn f() { ... } + TraitObject, // Box SomeTrait> } impl NameBindings { @@ -4244,11 +4245,11 @@ impl<'a> Resolver<'a> { this.resolve_type_parameter_bounds(item.id, bounds, TraitDerivation); - match unbound { - &Some(ast::TraitTyParamBound(ref tpb)) => { + match *unbound { + Some(ref tpb) => { this.resolve_trait_reference(item.id, tpb, TraitDerivation); } - _ => {} + None => {} } for trait_item in (*trait_items).iter() { @@ -4495,7 +4496,7 @@ impl<'a> Resolver<'a> { } match &type_parameter.unbound { &Some(ref unbound) => - self.resolve_type_parameter_bound( + self.resolve_trait_reference( type_parameter.id, unbound, TraitBoundingTypeParameter), &None => {} } @@ -4521,12 +4522,19 @@ impl<'a> Resolver<'a> { reference_type: TraitReferenceType) { match *type_parameter_bound { TraitTyParamBound(ref tref) => { - self.resolve_trait_reference(id, tref, reference_type) + self.resolve_poly_trait_reference(id, tref, reference_type) } RegionTyParamBound(..) => {} } } + fn resolve_poly_trait_reference(&mut self, + id: NodeId, + poly_trait_reference: &PolyTraitRef, + reference_type: TraitReferenceType) { + self.resolve_trait_reference(id, &poly_trait_reference.trait_ref, reference_type) + } + fn resolve_trait_reference(&mut self, id: NodeId, trait_reference: &TraitRef, @@ -4538,6 +4546,7 @@ impl<'a> Resolver<'a> { TraitBoundingTypeParameter => "bound type parameter with", TraitImplementation => "implement", TraitDerivation => "derive", + TraitObject => "reference", }; let msg = format!("attempt to {} a nonexistent trait `{}`", usage_str, path_str); @@ -5044,6 +5053,13 @@ impl<'a> Resolver<'a> { visit::walk_ty(self, ty); } + TyPolyTraitRef(ref poly_trait_ref) => { + self.resolve_poly_trait_reference( + ty.id, + &**poly_trait_ref, + TraitObject); + visit::walk_ty(self, ty); + } _ => { // Just resolve embedded types. visit::walk_ty(self, ty); diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 8246970c24ad7..8ac52b891b99d 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -19,6 +19,7 @@ use driver::session::Session; use middle::subst; +use std::fmt; use syntax::ast; use syntax::codemap::Span; use syntax::owned_slice::OwnedSlice; @@ -46,18 +47,12 @@ pub enum DefRegion { // that it corresponds to pub type NamedRegionMap = NodeMap; -// Returns an instance of some type that implements std::fmt::Show -fn lifetime_show(lt_name: &ast::Name) -> token::InternedString { - token::get_name(*lt_name) -} - struct LifetimeContext<'a> { sess: &'a Session, named_region_map: &'a mut NamedRegionMap, scope: Scope<'a> } -#[deriving(Show)] enum ScopeChain<'a> { /// EarlyScope(i, ['a, 'b, ...], s) extends s with early-bound /// lifetimes, assigning indexes 'a => i, 'b => i+1, ... etc. @@ -88,42 +83,32 @@ pub fn krate(sess: &Session, krate: &ast::Crate) -> NamedRegionMap { impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { fn visit_item(&mut self, item: &ast::Item) { - let lifetimes = match item.node { - ast::ItemFn(..) | // fn lifetimes get added in visit_fn below + match item.node { + ast::ItemFn(..) => { + // Fn lifetimes get added in visit_fn below: + self.with(RootScope, |this| visit::walk_item(this, item)); + } ast::ItemMod(..) | ast::ItemMac(..) | ast::ItemForeignMod(..) | - ast::ItemStatic(..) | ast::ItemConst(..) => { - self.with(|_, f| f(RootScope), |v| visit::walk_item(v, item)); - return; + ast::ItemStatic(..) | + ast::ItemConst(..) => { + // These sorts of items have no lifetime parameters at all. + self.with(RootScope, |this| visit::walk_item(this, item)); } ast::ItemTy(_, ref generics) | ast::ItemEnum(_, ref generics) | ast::ItemStruct(_, ref generics) | - ast::ItemTrait(ref generics, _, _, _) => { - self.with(|scope, f| { - f(EarlyScope(subst::TypeSpace, - &generics.lifetimes, - scope)) - }, |v| v.check_lifetime_defs(&generics.lifetimes)); - &generics.lifetimes - } + ast::ItemTrait(ref generics, _, _, _) | ast::ItemImpl(ref generics, _, _, _) => { - self.with(|scope, f| { - f(EarlyScope(subst::TypeSpace, - &generics.lifetimes, - scope)) - }, |v| v.check_lifetime_defs(&generics.lifetimes)); - &generics.lifetimes + // These kinds of items have only early bound lifetime parameters. + let lifetimes = &generics.lifetimes; + self.with(EarlyScope(subst::TypeSpace, lifetimes, &ROOT_SCOPE), |this| { + this.check_lifetime_defs(lifetimes); + visit::walk_item(this, item); + }); } - }; - - self.with(|_, f| f(EarlyScope(subst::TypeSpace, lifetimes, &ROOT_SCOPE)), |v| { - debug!("entering scope {}", v.scope); - v.check_lifetime_defs(lifetimes); - visit::walk_item(v, item); - debug!("exiting scope {}", v.scope); - }); + } } fn visit_fn(&mut self, fk: visit::FnKind<'v>, fd: &'v ast::FnDecl, @@ -131,7 +116,9 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { match fk { visit::FkItemFn(_, generics, _, _) | visit::FkMethod(_, generics, _) => { - self.visit_fn_decl(n, generics, |v| visit::walk_fn(v, fk, fd, b, s)) + self.visit_early_late( + subst::FnSpace, n, generics, + |this| visit::walk_fn(this, fk, fd, b, s)) } visit::FkFnBlock(..) => { visit::walk_fn(self, fk, fd, b, s) @@ -146,22 +133,20 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { _ => return visit::walk_ty(self, ty) }; - self.with(|scope, f| f(LateScope(ty.id, lifetimes, scope)), |v| { - v.check_lifetime_defs(lifetimes); - debug!("pushing fn scope id={} due to type", ty.id); - visit::walk_ty(v, ty); - debug!("popping fn scope id={} due to type", ty.id); + self.with(LateScope(ty.id, lifetimes, self.scope), |this| { + this.check_lifetime_defs(lifetimes); + visit::walk_ty(this, ty); }); } fn visit_ty_method(&mut self, m: &ast::TypeMethod) { - self.visit_fn_decl(m.id, &m.generics, |v| visit::walk_ty_method(v, m)) + self.visit_early_late( + subst::FnSpace, m.id, &m.generics, + |this| visit::walk_ty_method(this, m)) } fn visit_block(&mut self, b: &ast::Block) { - debug!("pushing block scope {}", b.id); - self.with(|scope, f| f(BlockScope(b.id, scope)), |v| visit::walk_block(v, b)); - debug!("popping block scope {}", b.id); + self.with(BlockScope(b.id, self.scope), |this| visit::walk_block(this, b)); } fn visit_lifetime_ref(&mut self, lifetime_ref: &ast::Lifetime) { @@ -188,13 +173,16 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { } impl<'a> LifetimeContext<'a> { - fn with(&mut self, wrap_scope: |Scope, |ScopeChain||, f: |&mut LifetimeContext|) { - let LifetimeContext { sess, ref mut named_region_map, scope} = *self; - wrap_scope(scope, |scope1| f(&mut LifetimeContext { + fn with(&mut self, wrap_scope: ScopeChain, f: |&mut LifetimeContext|) { + let LifetimeContext {sess, ref mut named_region_map, ..} = *self; + let mut this = LifetimeContext { sess: sess, named_region_map: *named_region_map, - scope: &scope1 - })) + scope: &wrap_scope + }; + debug!("entering scope {}", this.scope); + f(&mut this); + debug!("exiting scope {}", this.scope); } fn visit_ty_param_bounds(&mut self, @@ -202,7 +190,7 @@ impl<'a> LifetimeContext<'a> { for bound in bounds.iter() { match *bound { ast::TraitTyParamBound(ref trait_ref) => { - self.visit_trait_ref(trait_ref); + self.visit_poly_trait_ref(trait_ref); } ast::RegionTyParamBound(ref lifetime) => { self.visit_lifetime_ref(lifetime); @@ -211,23 +199,27 @@ impl<'a> LifetimeContext<'a> { } } - fn visit_trait_ref(&mut self, trait_ref: &ast::TraitRef) { - self.with(|scope, f| { - f(LateScope(trait_ref.ref_id, &trait_ref.lifetimes, scope)) - }, |v| { - v.check_lifetime_defs(&trait_ref.lifetimes); - for lifetime in trait_ref.lifetimes.iter() { - v.visit_lifetime_decl(lifetime); + fn visit_poly_trait_ref(&mut self, trait_ref: &ast::PolyTraitRef) { + let ref_id = trait_ref.trait_ref.ref_id; + self.with(LateScope(ref_id, &trait_ref.bound_lifetimes, self.scope), |this| { + this.check_lifetime_defs(&trait_ref.bound_lifetimes); + for lifetime in trait_ref.bound_lifetimes.iter() { + this.visit_lifetime_decl(lifetime); } - v.visit_path(&trait_ref.path, trait_ref.ref_id); + this.visit_trait_ref(&trait_ref.trait_ref) }) } + fn visit_trait_ref(&mut self, trait_ref: &ast::TraitRef) { + self.visit_path(&trait_ref.path, trait_ref.ref_id); + } + /// Visits self by adding a scope and handling recursive walk over the contents with `walk`. - fn visit_fn_decl(&mut self, - n: ast::NodeId, - generics: &ast::Generics, - walk: |&mut LifetimeContext|) { + fn visit_early_late(&mut self, + early_space: subst::ParamSpace, + binder_id: ast::NodeId, + generics: &ast::Generics, + walk: |&mut LifetimeContext|) { /*! * Handles visiting fns and methods. These are a bit * complicated because we must distinguish early- vs late-bound @@ -248,33 +240,25 @@ impl<'a> LifetimeContext<'a> { * numbered sequentially, starting from the lowest index that * is already in scope (for a fn item, that will be 0, but for * a method it might not be). Late bound lifetimes are - * resolved by name and associated with a binder id (`n`), so + * resolved by name and associated with a binder id (`binder_id`), so * the ordering is not important there. */ let referenced_idents = early_bound_lifetime_names(generics); - debug!("pushing fn scope id={} due to fn item/method\ - referenced_idents={}", - n, - referenced_idents.iter().map(lifetime_show).collect::>()); - let lifetimes = &generics.lifetimes; - if referenced_idents.is_empty() { - self.with(|scope, f| f(LateScope(n, lifetimes, scope)), |v| { - v.check_lifetime_defs(lifetimes); - walk(v); - }); - } else { - let (early, late) = lifetimes.clone().partition( - |l| referenced_idents.iter().any(|&i| i == l.lifetime.name)); - - self.with(|scope, f| f(EarlyScope(subst::FnSpace, &early, scope)), |v| { - v.with(|scope1, f| f(LateScope(n, &late, scope1)), |v| { - v.check_lifetime_defs(lifetimes); - walk(v); - }); + + debug!("visit_early_late: binder_id={} referenced_idents={}", + binder_id, + referenced_idents); + + let (early, late) = generics.lifetimes.clone().partition( + |l| referenced_idents.iter().any(|&i| i == l.lifetime.name)); + + self.with(EarlyScope(early_space, &early, self.scope), |this| { + this.with(LateScope(binder_id, &late, this.scope), |this| { + this.check_lifetime_defs(&generics.lifetimes); + walk(this); }); - } - debug!("popping fn scope id={} due to fn item/method", n); + }); } fn resolve_lifetime_ref(&mut self, lifetime_ref: &ast::Lifetime) { @@ -525,3 +509,14 @@ fn early_bound_lifetime_names(generics: &ast::Generics) -> Vec { } } } + +impl<'a> fmt::Show for ScopeChain<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match *self { + EarlyScope(space, defs, _) => write!(fmt, "EarlyScope({}, {})", space, defs), + LateScope(id, defs, _) => write!(fmt, "LateScope({}, {})", id, defs), + BlockScope(id, _) => write!(fmt, "BlockScope({})", id), + RootScope => write!(fmt, "RootScope"), + } + } +} diff --git a/src/librustc/middle/save/mod.rs b/src/librustc/middle/save/mod.rs index b64a160ab1f28..a2b80686d010e 100644 --- a/src/librustc/middle/save/mod.rs +++ b/src/librustc/middle/save/mod.rs @@ -710,6 +710,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { } }; + let trait_ref = &trait_ref.trait_ref; match self.lookup_type_ref(trait_ref.ref_id) { Some(id) => { let sub_span = self.span.sub_span_for_type_name(trait_ref.path.span); @@ -1068,7 +1069,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> { for bound in param.bounds.iter() { match *bound { ast::TraitTyParamBound(ref trait_ref) => { - self.process_trait_ref(trait_ref, None); + self.process_trait_ref(&trait_ref.trait_ref, None); } _ => {} } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 3e8a7bb842ca8..1a6e8eeb320f0 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -5546,7 +5546,8 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec, ty_param(_) | ty_infer(_) | ty_open(_) | - ty_err => {} + ty_err => { + } } }); diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 6430362f9cdfd..e27ff636a2a6f 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -51,8 +51,6 @@ use middle::const_eval; use middle::def; -use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem}; -use middle::lang_items::{FnOnceTraitLangItem}; use middle::resolve_lifetime as rl; use middle::subst::{FnSpace, TypeSpace, AssocSpace, SelfSpace, Subst, Substs}; use middle::subst::{VecPerParamSpace}; @@ -398,6 +396,46 @@ fn ast_path_substs<'tcx,AC,RS>( } } +pub fn instantiate_trait_ref<'tcx,AC,RS>(this: &AC, + rscope: &RS, + ast_trait_ref: &ast::TraitRef, + self_ty: Option, + associated_type: Option) + -> Rc + where AC: AstConv<'tcx>, + RS: RegionScope +{ + /*! + * Instantiates the path for the given trait reference, assuming that + * it's bound to a valid trait type. Returns the def_id for the defining + * trait. Fails if the type is a type other than a trait type. + */ + + match lookup_def_tcx(this.tcx(), + ast_trait_ref.path.span, + ast_trait_ref.ref_id) { + def::DefTrait(trait_did) => { + let trait_ref = + Rc::new(ast_path_to_trait_ref(this, + rscope, + trait_did, + self_ty, + associated_type, + &ast_trait_ref.path, + ast_trait_ref.ref_id)); + + this.tcx().trait_refs.borrow_mut().insert(ast_trait_ref.ref_id, + trait_ref.clone()); + trait_ref + } + _ => { + this.tcx().sess.span_fatal( + ast_trait_ref.path.span, + format!("`{}` is not a trait", ast_trait_ref.path.user_string(this.tcx()))[]); + } + } +} + pub fn ast_path_to_trait_ref<'tcx,AC,RS>(this: &AC, rscope: &RS, trait_def_id: ast::DefId, @@ -620,41 +658,6 @@ enum PointerTy { Uniq } -pub fn trait_ref_for_unboxed_function<'tcx, AC: AstConv<'tcx>, - RS:RegionScope>( - this: &AC, - rscope: &RS, - kind: ast::UnboxedClosureKind, - decl: &ast::FnDecl, - self_ty: Option) - -> ty::TraitRef { - let lang_item = match kind { - ast::FnUnboxedClosureKind => FnTraitLangItem, - ast::FnMutUnboxedClosureKind => FnMutTraitLangItem, - ast::FnOnceUnboxedClosureKind => FnOnceTraitLangItem, - }; - let trait_did = this.tcx().lang_items.require(lang_item).unwrap(); - let input_types = decl.inputs - .iter() - .map(|input| { - ast_ty_to_ty(this, rscope, &*input.ty) - }).collect::>(); - 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()); - - match self_ty { - Some(s) => substs.types.push(SelfSpace, s), - None => () - } - - ty::TraitRef { - def_id: trait_did, - substs: substs, - } -} - // Handle `~`, `Box`, and `&` being able to mean strs and vecs. // If a_seq_ty is a str or a vec, make it a str/vec. // Also handle first-class trait types. @@ -898,6 +901,16 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( ty::mk_closure(tcx, fn_decl) } + ast::TyPolyTraitRef(ref data) => { + // FIXME(#18639) this is just a placeholder for code to come + let principal = instantiate_trait_ref(this, rscope, &data.trait_ref, None, None); + let bounds = conv_existential_bounds(this, + rscope, + ast_ty.span, + &[principal.clone()], + &[]); + ty::mk_trait(tcx, (*principal).clone(), bounds) + } ast::TyPath(ref path, ref bounds, id) => { let a_def = match tcx.def_map.borrow().get(&id) { None => { @@ -1536,6 +1549,7 @@ pub fn partition_bounds<'a>(tcx: &ty::ctxt, for &ast_bound in ast_bounds.iter() { match *ast_bound { ast::TraitTyParamBound(ref b) => { + let b = &b.trait_ref; // FIXME match lookup_def_tcx(tcx, b.path.span, b.ref_id) { def::DefTrait(trait_did) => { match trait_def_ids.get(&trait_did) { diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index d365c54c70121..42411b598bfae 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -61,7 +61,6 @@ use syntax::ast_util::{local_def, PostExpansionMethod}; use syntax::codemap::Span; use syntax::parse::token::{special_idents}; use syntax::parse::token; -use syntax::print::pprust::{path_to_string}; use syntax::ptr::P; use syntax::visit; @@ -633,24 +632,33 @@ pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt, span: Span, generics: &ast::Generics, thing: &'static str) { + let mut warn = false; + for ty_param in generics.ty_params.iter() { - let bounds = ty_param.bounds.iter(); - let mut bounds = bounds.chain(ty_param.unbound.iter()); - for bound in bounds { + for bound in ty_param.bounds.iter() { match *bound { ast::TraitTyParamBound(..) => { - // According to accepted RFC #XXX, we should - // eventually accept these, but it will not be - // part of this PR. Still, convert to warning to - // make bootstrapping easier. - span_warn!(ccx.tcx.sess, span, E0122, - "trait bounds are not (yet) enforced \ - in {} definitions", - thing); + warn = true; } ast::RegionTyParamBound(..) => { } } } + + match ty_param.unbound { + Some(_) => { warn = true; } + None => { } + } + } + + if warn { + // According to accepted RFC #XXX, we should + // eventually accept these, but it will not be + // part of this PR. Still, convert to warning to + // make bootstrapping easier. + span_warn!(ccx.tcx.sess, span, E0122, + "trait bounds are not (yet) enforced \ + in {} definitions", + thing); } } @@ -1147,7 +1155,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { parent_visibility); for trait_ref in opt_trait_ref.iter() { - instantiate_trait_ref(&icx, trait_ref, selfty, None); + astconv::instantiate_trait_ref(&icx, &ExplicitRscope, trait_ref, Some(selfty), None); } }, ast::ItemTrait(_, _, _, ref trait_methods) => { @@ -1315,47 +1323,6 @@ pub fn convert_foreign(ccx: &CrateCtxt, i: &ast::ForeignItem) { ccx.tcx.tcache.borrow_mut().insert(local_def(i.id), pty); } -pub fn instantiate_trait_ref<'tcx,AC>(this: &AC, - ast_trait_ref: &ast::TraitRef, - self_ty: ty::t, - associated_type: Option) - -> Rc - where AC: AstConv<'tcx> { - /*! - * Instantiates the path for the given trait reference, assuming that - * it's bound to a valid trait type. Returns the def_id for the defining - * trait. Fails if the type is a type other than a trait type. - */ - - // FIXME(#5121) -- distinguish early vs late lifetime params - let rscope = ExplicitRscope; - - match lookup_def_tcx(this.tcx(), - ast_trait_ref.path.span, - ast_trait_ref.ref_id) { - def::DefTrait(trait_did) => { - let trait_ref = - Rc::new(astconv::ast_path_to_trait_ref(this, - &rscope, - trait_did, - Some(self_ty), - associated_type, - &ast_trait_ref.path, - ast_trait_ref.ref_id)); - - this.tcx().trait_refs.borrow_mut().insert(ast_trait_ref.ref_id, - trait_ref.clone()); - trait_ref - } - _ => { - this.tcx().sess.span_fatal( - ast_trait_ref.path.span, - format!("`{}` is not a trait", - path_to_string(&ast_trait_ref.path)).as_slice()); - } - } -} - fn get_trait_def(ccx: &CrateCtxt, trait_id: ast::DefId) -> Rc { if trait_id.krate != ast::LOCAL_CRATE { return ty::lookup_trait_def(ccx.tcx, trait_id) @@ -1720,14 +1687,14 @@ fn ty_generics_for_fn_or_method<'tcx,AC>( // Add the Sized bound, unless the type parameter is marked as `Sized?`. fn add_unsized_bound<'tcx,AC>(this: &AC, - unbound: &Option, + unbound: &Option, bounds: &mut ty::BuiltinBounds, desc: &str, span: Span) where AC: AstConv<'tcx> { let kind_id = this.tcx().lang_items.require(SizedTraitLangItem); match unbound { - &Some(ast::TraitTyParamBound(ref tpb)) => { + &Some(ref tpb) => { // FIXME(#8559) currently requires the unbound to be built-in. let trait_def_id = ty::trait_ref_to_def_id(this.tcx(), tpb); match kind_id { @@ -1752,7 +1719,7 @@ fn add_unsized_bound<'tcx,AC>(this: &AC, ty::try_add_builtin_trait(this.tcx(), kind_id.unwrap(), bounds); } // No lang item for Sized, so we can't add it as a bound. - _ => {} + &None => {} } } @@ -1870,11 +1837,11 @@ fn ty_generics<'tcx,AC>(this: &AC, let trait_def_id = match lookup_def_tcx(this.tcx(), - ast_trait_ref.path.span, - ast_trait_ref.ref_id) { + ast_trait_ref.trait_ref.path.span, + ast_trait_ref.trait_ref.ref_id) { def::DefTrait(trait_def_id) => trait_def_id, _ => { - this.tcx().sess.span_bug(ast_trait_ref.path.span, + this.tcx().sess.span_bug(ast_trait_ref.trait_ref.path.span, "not a trait?!") } }; @@ -1972,7 +1939,7 @@ fn compute_bounds<'tcx,AC>(this: &AC, name_of_bounded_thing: ast::Name, param_ty: ty::ParamTy, ast_bounds: &[ast::TyParamBound], - unbound: &Option, + unbound: &Option, span: Span, where_clause: &ast::WhereClause) -> ty::ParamBounds @@ -2047,10 +2014,11 @@ fn conv_param_bounds<'tcx,AC>(this: &AC, let trait_bounds: Vec> = trait_bounds.into_iter() .map(|b| { - instantiate_trait_ref(this, - b, - param_ty.to_ty(this.tcx()), - Some(param_ty.to_ty(this.tcx()))) + astconv::instantiate_trait_ref(this, + &ExplicitRscope, + b, + Some(param_ty.to_ty(this.tcx())), + Some(param_ty.to_ty(this.tcx()))) }) .collect(); let region_bounds: Vec = diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index ab3ec4991c39b..83d90274fd323 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -52,7 +52,6 @@ use middle::typeck::infer::type_variable::{RelationDir, EqTo, use middle::ty_fold::{TypeFoldable}; use util::ppaux::Repr; - use syntax::ast::{Onceness, FnStyle}; use syntax::ast; use syntax::abi; diff --git a/src/librustc/middle/typeck/infer/error_reporting.rs b/src/librustc/middle/typeck/infer/error_reporting.rs index 4ca6225346791..80b4948f6fbf2 100644 --- a/src/librustc/middle/typeck/infer/error_reporting.rs +++ b/src/librustc/middle/typeck/infer/error_reporting.rs @@ -1102,7 +1102,8 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { // be passing down a map. ast::RegionTyParamBound(lt) } - &ast::TraitTyParamBound(ref tr) => { + &ast::TraitTyParamBound(ref poly_tr) => { + let tr = &poly_tr.trait_ref; let last_seg = tr.path.segments.last().unwrap(); let mut insert = Vec::new(); let lifetimes = last_seg.parameters.lifetimes(); @@ -1119,10 +1120,12 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { region_names: region_names }; let new_path = self.rebuild_path(rebuild_info, lifetime); - ast::TraitTyParamBound(ast::TraitRef { - path: new_path, - ref_id: tr.ref_id, - lifetimes: tr.lifetimes.clone(), + ast::TraitTyParamBound(ast::PolyTraitRef { + bound_lifetimes: poly_tr.bound_lifetimes.clone(), + trait_ref: ast::TraitRef { + path: new_path, + ref_id: tr.ref_id, + } }) } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 4478c29f66a48..38e0c4fe040bd 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -963,6 +963,12 @@ impl Clean for ast::TraitRef { } } +impl Clean for ast::PolyTraitRef { + fn clean(&self, cx: &DocContext) -> Type { + self.trait_ref.clean(cx) + } +} + #[deriving(Clone, Encodable, Decodable)] pub enum TraitMethod { RequiredMethod(Item), @@ -1306,7 +1312,8 @@ impl Clean for ty::t { } ty::ty_struct(did, ref substs) | ty::ty_enum(did, ref substs) | - ty::ty_trait(box ty::TyTrait { def_id: did, ref substs, .. }) => { + ty::ty_trait(box ty::TyTrait { principal: ty::TraitRef { def_id: did, ref substs }, + .. }) => { let fqn = csearch::get_item_path(cx.tcx(), did); let fqn: Vec = fqn.into_iter().map(|i| { i.to_string() diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 20f7caac48222..145978bb73f4b 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -307,7 +307,7 @@ pub const DUMMY_NODE_ID: NodeId = -1; /// detects Copy, Send and Sync. #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum TyParamBound { - TraitTyParamBound(TraitRef), + TraitTyParamBound(PolyTraitRef), RegionTyParamBound(Lifetime) } @@ -318,7 +318,7 @@ pub struct TyParam { pub ident: Ident, pub id: NodeId, pub bounds: TyParamBounds, - pub unbound: Option, + pub unbound: Option, pub default: Option>, pub span: Span } @@ -1097,6 +1097,7 @@ pub enum Ty_ { TyBareFn(P), TyTup(Vec> ), TyPath(Path, Option, NodeId), // for #7264; see above + TyPolyTraitRef(P), // a type like `for<'a> Foo<&'a Bar>` /// A "qualified path", e.g. ` as SomeTrait>::SomeType` TyQPath(P), /// No-op; kept solely so that we can pretty-print faithfully @@ -1350,7 +1351,6 @@ pub struct Attribute_ { pub is_sugared_doc: bool, } - /// TraitRef's appear in impls. /// resolve maps each TraitRef's ref_id to its defining trait; that's all /// that the ref_id is for. The impl_id maps to the "self type" of this impl. @@ -1360,7 +1360,15 @@ pub struct Attribute_ { pub struct TraitRef { pub path: Path, pub ref_id: NodeId, - pub lifetimes: Vec, +} + +#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +pub struct PolyTraitRef { + /// The `'a` in `<'a> Foo<&'a T>` + pub bound_lifetimes: Vec, + + /// The `Foo<&'a T>` in `<'a> Foo<&'a T>` + pub trait_ref: TraitRef } #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] @@ -1448,8 +1456,8 @@ pub enum Item_ { ItemStruct(P, Generics), /// Represents a Trait Declaration ItemTrait(Generics, - Option, // (optional) default bound not required for Self. - // Currently, only Sized makes sense here. + Option, // (optional) default bound not required for Self. + // Currently, only Sized makes sense here. TyParamBounds, Vec), ItemImpl(Generics, diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs index 3adb062864e1e..d65be4c45e8f3 100644 --- a/src/libsyntax/ast_map/mod.rs +++ b/src/libsyntax/ast_map/mod.rs @@ -770,7 +770,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { for b in bounds.iter() { match *b { TraitTyParamBound(ref t) => { - self.insert(t.ref_id, NodeItem(i)); + self.insert(t.trait_ref.ref_id, NodeItem(i)); } _ => {} } diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 5921d630b8979..862cbf3d7ca06 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -68,10 +68,11 @@ pub trait AstBuilder { span: Span, id: ast::Ident, bounds: OwnedSlice, - unbound: Option, + unbound: Option, default: Option>) -> ast::TyParam; fn trait_ref(&self, path: ast::Path) -> ast::TraitRef; + fn poly_trait_ref(&self, path: ast::Path) -> ast::PolyTraitRef; fn typarambound(&self, path: ast::Path) -> ast::TyParamBound; fn lifetime(&self, span: Span, ident: ast::Name) -> ast::Lifetime; fn lifetime_def(&self, @@ -417,7 +418,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { span: Span, id: ast::Ident, bounds: OwnedSlice, - unbound: Option, + unbound: Option, default: Option>) -> ast::TyParam { ast::TyParam { ident: id, @@ -445,12 +446,18 @@ impl<'a> AstBuilder for ExtCtxt<'a> { ast::TraitRef { path: path, ref_id: ast::DUMMY_NODE_ID, - lifetimes: Vec::new(), + } + } + + fn poly_trait_ref(&self, path: ast::Path) -> ast::PolyTraitRef { + ast::PolyTraitRef { + bound_lifetimes: Vec::new(), + trait_ref: self.trait_ref(path) } } fn typarambound(&self, path: ast::Path) -> ast::TyParamBound { - ast::TraitTyParamBound(self.trait_ref(path)) + ast::TraitTyParamBound(self.poly_trait_ref(path)) } fn lifetime(&self, span: Span, name: ast::Name) -> ast::Lifetime { diff --git a/src/libsyntax/ext/deriving/generic/ty.rs b/src/libsyntax/ext/deriving/generic/ty.rs index a90618a30b6eb..1ec1e3b1224c4 100644 --- a/src/libsyntax/ext/deriving/generic/ty.rs +++ b/src/libsyntax/ext/deriving/generic/ty.rs @@ -194,7 +194,7 @@ impl<'a> Ty<'a> { fn mk_ty_param(cx: &ExtCtxt, span: Span, name: &str, - bounds: &[Path], unbound: Option, + bounds: &[Path], unbound: Option, self_ident: Ident, self_generics: &Generics) -> ast::TyParam { let bounds = bounds.iter().map(|b| { @@ -220,7 +220,7 @@ fn mk_generics(lifetimes: Vec, ty_params: Vec) #[deriving(Clone)] pub struct LifetimeBounds<'a> { pub lifetimes: Vec<(&'a str, Vec<&'a str>)>, - pub bounds: Vec<(&'a str, Option, Vec>)>, + pub bounds: Vec<(&'a str, Option, Vec>)>, } impl<'a> LifetimeBounds<'a> { diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 2074a6bfab982..85d4e157b7b84 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -227,6 +227,10 @@ pub trait Folder { noop_fold_trait_ref(p, self) } + fn fold_poly_trait_ref(&mut self, p: PolyTraitRef) -> PolyTraitRef { + noop_fold_poly_trait_ref(p, self) + } + fn fold_struct_def(&mut self, struct_def: P) -> P { noop_fold_struct_def(struct_def, self) } @@ -442,7 +446,10 @@ pub fn noop_fold_ty(t: P, fld: &mut T) -> P { TyFixedLengthVec(ty, e) => { TyFixedLengthVec(fld.fold_ty(ty), fld.fold_expr(e)) } - TyTypeof(expr) => TyTypeof(fld.fold_expr(expr)) + TyTypeof(expr) => TyTypeof(fld.fold_expr(expr)), + TyPolyTraitRef(poly_trait_ref) => { + TyPolyTraitRef(poly_trait_ref.map(|p| fld.fold_poly_trait_ref(p))) + }, }, span: fld.new_span(span) }) @@ -711,7 +718,7 @@ pub fn noop_fold_ty_param_bound(tpb: TyParamBound, fld: &mut T) -> TyParamBound where T: Folder { match tpb { - TraitTyParamBound(ty) => TraitTyParamBound(fld.fold_trait_ref(ty)), + TraitTyParamBound(ty) => TraitTyParamBound(fld.fold_poly_trait_ref(ty)), RegionTyParamBound(lifetime) => RegionTyParamBound(fld.fold_lifetime(lifetime)), } } @@ -722,7 +729,7 @@ pub fn noop_fold_ty_param(tp: TyParam, fld: &mut T) -> TyParam { id: fld.new_id(id), ident: ident, bounds: fld.fold_bounds(bounds), - unbound: unbound.map(|x| fld.fold_ty_param_bound(x)), + unbound: unbound.map(|x| fld.fold_trait_ref(x)), default: default.map(|x| fld.fold_ty(x)), span: span } @@ -842,13 +849,18 @@ pub fn noop_fold_trait_ref(p: TraitRef, fld: &mut T) -> TraitRef { let id = fld.new_id(p.ref_id); let TraitRef { path, - lifetimes, - .. + ref_id: _, } = p; ast::TraitRef { path: fld.fold_path(path), ref_id: id, - lifetimes: fld.fold_lifetime_defs(lifetimes), + } +} + +pub fn noop_fold_poly_trait_ref(p: PolyTraitRef, fld: &mut T) -> PolyTraitRef { + ast::PolyTraitRef { + bound_lifetimes: fld.fold_lifetime_defs(p.bound_lifetimes), + trait_ref: fld.fold_trait_ref(p.trait_ref) } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 9ba11d63da54f..6873c015fd51c 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -42,6 +42,7 @@ use ast::{Method, MutTy, BiMul, Mutability}; use ast::{MethodImplItem, NamedField, UnNeg, NoReturn, UnNot}; use ast::{Pat, PatEnum, PatIdent, PatLit, PatRange, PatRegion, PatStruct}; use ast::{PatTup, PatBox, PatWild, PatWildMulti, PatWildSingle}; +use ast::{PolyTraitRef}; use ast::{QPath, RequiredMethod}; use ast::{RetStyle, Return, BiShl, BiShr, Stmt, StmtDecl}; use ast::{StmtExpr, StmtSemi, StmtMac, StructDef, StructField}; @@ -53,7 +54,7 @@ use ast::{TtDelimited, TtSequence, TtToken}; use ast::{TupleVariantKind, Ty, Ty_, TyBot}; use ast::{TypeField, TyFixedLengthVec, TyClosure, TyProc, TyBareFn}; use ast::{TyTypeof, TyInfer, TypeMethod}; -use ast::{TyNil, TyParam, TyParamBound, TyParen, TyPath, TyPtr, TyQPath}; +use ast::{TyNil, TyParam, TyParamBound, TyParen, TyPath, TyPolyTraitRef, TyPtr, TyQPath}; use ast::{TyRptr, TyTup, TyU32, TyUniq, TyVec, UnUniq}; use ast::{TypeImplItem, TypeTraitItem, Typedef, UnboxedClosureKind}; use ast::{UnnamedField, UnsafeBlock}; @@ -968,30 +969,14 @@ impl<'a> Parser<'a> { /// Is the current token one of the keywords that signals a bare function /// type? pub fn token_is_bare_fn_keyword(&mut self) -> bool { - if self.token.is_keyword(keywords::Fn) { - return true - } - - if self.token.is_keyword(keywords::Unsafe) || - self.token.is_keyword(keywords::Once) { - return self.look_ahead(1, |t| t.is_keyword(keywords::Fn)) - } - - false + self.token.is_keyword(keywords::Fn) || + self.token.is_keyword(keywords::Unsafe) || + self.token.is_keyword(keywords::Extern) } /// Is the current token one of the keywords that signals a closure type? pub fn token_is_closure_keyword(&mut self) -> bool { - self.token.is_keyword(keywords::Unsafe) || - self.token.is_keyword(keywords::Once) - } - - /// Is the current token one of the keywords that signals an old-style - /// closure type (with explicit sigil)? - pub fn token_is_old_style_closure_keyword(&mut self) -> bool { - self.token.is_keyword(keywords::Unsafe) || - self.token.is_keyword(keywords::Once) || - self.token.is_keyword(keywords::Fn) + self.token.is_keyword(keywords::Unsafe) } pub fn get_lifetime(&mut self) -> ast::Ident { @@ -1001,8 +986,57 @@ impl<'a> Parser<'a> { } } + pub fn parse_for_in_type(&mut self) -> Ty_ { + /* + Parses whatever can come after a `for` keyword in a type. + The `for` has already been consumed. + + Deprecated: + + - for <'lt> |S| -> T + - for <'lt> proc(S) -> T + + Eventually: + + - for <'lt> [unsafe] [extern "ABI"] fn (S) -> T + - for <'lt> path::foo(a, b) + + */ + + // parse <'lt> + let lifetime_defs = self.parse_late_bound_lifetime_defs(); + + // examine next token to decide to do + if self.eat_keyword(keywords::Proc) { + self.parse_proc_type(lifetime_defs) + } else if self.token_is_bare_fn_keyword() || self.token_is_closure_keyword() { + self.parse_ty_bare_fn_or_ty_closure(lifetime_defs) + } else if self.token == token::ModSep || + self.token.is_ident() || + self.token.is_path() { + let trait_ref = self.parse_trait_ref(); + TyPolyTraitRef(P(PolyTraitRef { bound_lifetimes: lifetime_defs, + trait_ref: trait_ref })) + } else { + self.parse_ty_closure(lifetime_defs) + } + } + + pub fn parse_ty_path(&mut self, plus_allowed: bool) -> Ty_ { + let mode = if plus_allowed { + LifetimeAndTypesAndBounds + } else { + LifetimeAndTypesWithoutColons + }; + let PathAndBounds { + path, + bounds + } = self.parse_path(mode); + TyPath(path, bounds, ast::DUMMY_NODE_ID) + } + /// parse a TyBareFn type: - pub fn parse_ty_bare_fn(&mut self) -> Ty_ { + pub fn parse_ty_bare_fn(&mut self, lifetime_defs: Vec) -> Ty_ { /* [unsafe] [extern "ABI"] fn <'lt> (S) -> T @@ -1023,18 +1057,26 @@ impl<'a> Parser<'a> { }; self.expect_keyword(keywords::Fn); - let (decl, lifetimes) = self.parse_ty_fn_decl(true); + let lifetime_defs = self.parse_legacy_lifetime_defs(lifetime_defs); + let (inputs, variadic) = self.parse_fn_args(false, true); + let (ret_style, ret_ty) = self.parse_ret_ty(); + let decl = P(FnDecl { + inputs: inputs, + output: ret_ty, + cf: ret_style, + variadic: variadic + }); TyBareFn(P(BareFnTy { abi: abi, fn_style: fn_style, - lifetimes: lifetimes, + lifetimes: lifetime_defs, decl: decl })) } /// Parses a procedure type (`proc`). The initial `proc` keyword must /// already have been parsed. - pub fn parse_proc_type(&mut self) -> Ty_ { + pub fn parse_proc_type(&mut self, lifetime_defs: Vec) -> Ty_ { /* proc <'lt> (S) [:Bounds] -> T @@ -1043,19 +1085,12 @@ impl<'a> Parser<'a> { | | | | Return type | | | Bounds | | Argument types - | Lifetimes + | Legacy lifetimes the `proc` keyword */ - let lifetime_defs = if self.eat(&token::Lt) { - let lifetime_defs = self.parse_lifetime_defs(); - self.expect_gt(); - lifetime_defs - } else { - Vec::new() - }; - + let lifetime_defs = self.parse_legacy_lifetime_defs(lifetime_defs); let (inputs, variadic) = self.parse_fn_args(false, false); let bounds = self.parse_colon_then_ty_param_bounds(); let (ret_style, ret_ty) = self.parse_ret_ty(); @@ -1100,33 +1135,49 @@ impl<'a> Parser<'a> { return None } + pub fn parse_ty_bare_fn_or_ty_closure(&mut self, lifetime_defs: Vec) -> Ty_ { + // Both bare fns and closures can begin with stuff like unsafe + // and extern. So we just scan ahead a few tokens to see if we see + // a `fn`. + // + // Closure: [unsafe] <'lt> |S| [:Bounds] -> T + // Fn: [unsafe] [extern "ABI"] fn <'lt> (S) -> T + + if self.token.is_keyword(keywords::Fn) { + self.parse_ty_bare_fn(lifetime_defs) + } else if self.token.is_keyword(keywords::Extern) { + self.parse_ty_bare_fn(lifetime_defs) + } else if self.token.is_keyword(keywords::Unsafe) { + if self.look_ahead(1, |t| t.is_keyword(keywords::Fn) || + t.is_keyword(keywords::Extern)) { + self.parse_ty_bare_fn(lifetime_defs) + } else { + self.parse_ty_closure(lifetime_defs) + } + } else { + self.parse_ty_closure(lifetime_defs) + } + } + /// Parse a TyClosure type - pub fn parse_ty_closure(&mut self) -> Ty_ { + pub fn parse_ty_closure(&mut self, lifetime_defs: Vec) -> Ty_ { /* - [unsafe] [once] <'lt> |S| [:Bounds] -> T - ^~~~~~~^ ^~~~~^ ^~~~^ ^ ^~~~~~~~^ ^ - | | | | | | - | | | | | Return type - | | | | Closure bounds - | | | Argument types - | | Lifetime defs - | Once-ness (a.k.a., affine) + [unsafe] <'lt> |S| [:Bounds] -> T + ^~~~~~~^ ^~~~^ ^ ^~~~~~~~^ ^ + | | | | | + | | | | Return type + | | | Closure bounds + | | Argument types + | Deprecated lifetime defs + | Function Style */ let fn_style = self.parse_unsafety(); - let onceness = if self.eat_keyword(keywords::Once) {Once} else {Many}; - let lifetime_defs = if self.eat(&token::Lt) { - let lifetime_defs = self.parse_lifetime_defs(); - self.expect_gt(); - - lifetime_defs - } else { - Vec::new() - }; + let lifetime_defs = self.parse_legacy_lifetime_defs(lifetime_defs); let inputs = if self.eat(&token::OrOr) { Vec::new() @@ -1152,7 +1203,7 @@ impl<'a> Parser<'a> { TyClosure(P(ClosureTy { fn_style: fn_style, - onceness: onceness, + onceness: Many, bounds: bounds, decl: decl, lifetimes: lifetime_defs, @@ -1167,36 +1218,23 @@ impl<'a> Parser<'a> { } } - /// Parse a function type (following the 'fn') - pub fn parse_ty_fn_decl(&mut self, allow_variadic: bool) - -> (P, Vec) { - /* - - (fn) <'lt> (S) -> T - ^~~~^ ^~^ ^ - | | | - | | Return type - | Argument types - Lifetime_defs - - */ - let lifetime_defs = if self.eat(&token::Lt) { - let lifetime_defs = self.parse_lifetime_defs(); - self.expect_gt(); - lifetime_defs + /// Parses `[ 'for' '<' lifetime_defs '>' ]' + fn parse_legacy_lifetime_defs(&mut self, + lifetime_defs: Vec) + -> Vec + { + if self.eat(&token::Lt) { + if lifetime_defs.is_empty() { + self.warn("deprecated syntax, use `for` keyword now"); + let lifetime_defs = self.parse_lifetime_defs(); + self.expect_gt(); + lifetime_defs + } else { + self.fatal("cannot use new `for` keyword and older syntax together"); + } } else { - Vec::new() - }; - - let (inputs, variadic) = self.parse_fn_args(false, allow_variadic); - let (ret_style, ret_ty) = self.parse_ret_ty(); - let decl = P(FnDecl { - inputs: inputs, - output: ret_ty, - cf: ret_style, - variadic: variadic - }); - (decl, lifetime_defs) + lifetime_defs + } } /// Parses `type Foo;` in a trait declaration only. The `type` keyword has @@ -1433,25 +1471,24 @@ impl<'a> Parser<'a> { self.expect(&token::CloseDelim(token::Bracket)); t } else if self.token == token::BinOp(token::And) || - self.token == token::AndAnd { + self.token == token::AndAnd { // BORROWED POINTER self.expect_and(); self.parse_borrowed_pointee() - } else if self.token.is_keyword(keywords::Extern) || - self.token.is_keyword(keywords::Unsafe) || - self.token_is_bare_fn_keyword() { - // BARE FUNCTION - self.parse_ty_bare_fn() - } else if self.token_is_closure_keyword() || - self.token == token::BinOp(token::Or) || - self.token == token::OrOr || - (self.token == token::Lt && - self.look_ahead(1, |t| { - *t == token::Gt || t.is_lifetime() - })) { + } else if self.token.is_keyword(keywords::For) { + self.parse_for_in_type() + } else if self.token_is_bare_fn_keyword() || + self.token_is_closure_keyword() { + // BARE FUNCTION OR CLOSURE + self.parse_ty_bare_fn_or_ty_closure(Vec::new()) + } else if self.token == token::BinOp(token::Or) || + self.token == token::OrOr || + (self.token == token::Lt && + self.look_ahead(1, |t| { + *t == token::Gt || t.is_lifetime() + })) { // CLOSURE - - self.parse_ty_closure() + self.parse_ty_closure(Vec::new()) } else if self.eat_keyword(keywords::Typeof) { // TYPEOF // In order to not be ambiguous, the type must be surrounded by parens. @@ -1460,7 +1497,7 @@ impl<'a> Parser<'a> { self.expect(&token::CloseDelim(token::Paren)); TyTypeof(e) } else if self.eat_keyword(keywords::Proc) { - self.parse_proc_type() + self.parse_proc_type(Vec::new()) } else if self.token == token::Lt { // QUALIFIED PATH self.bump(); @@ -1479,16 +1516,7 @@ impl<'a> Parser<'a> { self.token.is_ident() || self.token.is_path() { // NAMED TYPE - let mode = if plus_allowed { - LifetimeAndTypesAndBounds - } else { - LifetimeAndTypesWithoutColons - }; - let PathAndBounds { - path, - bounds - } = self.parse_path(mode); - TyPath(path, bounds, ast::DUMMY_NODE_ID) + self.parse_ty_path(plus_allowed) } else if self.eat(&token::Underscore) { // TYPE TO BE INFERRED TyInfer @@ -3848,29 +3876,17 @@ impl<'a> Parser<'a> { } // matches bounds = ( boundseq )? - // where boundseq = ( bound + boundseq ) | bound - // and bound = 'region | ty + // where boundseq = ( polybound + boundseq ) | polybound + // and polybound = ( 'for' '<' 'region '>' )? bound + // and bound = 'region | trait_ref // NB: The None/Some distinction is important for issue #7264. fn parse_ty_param_bounds(&mut self) -> OwnedSlice { let mut result = vec!(); loop { - let lifetime_defs = if self.eat(&token::Lt) { - let lifetime_defs = self.parse_lifetime_defs(); - self.expect_gt(); - lifetime_defs - } else { - Vec::new() - }; match self.token { token::Lifetime(lifetime) => { - if lifetime_defs.len() > 0 { - let span = self.last_span; - self.span_err(span, "lifetime declarations are not \ - allowed here") - } - result.push(RegionTyParamBound(ast::Lifetime { id: ast::DUMMY_NODE_ID, span: self.span, @@ -3879,13 +3895,8 @@ impl<'a> Parser<'a> { self.bump(); } token::ModSep | token::Ident(..) => { - let path = - self.parse_path(LifetimeAndTypesWithoutColons).path; - result.push(TraitTyParamBound(ast::TraitRef { - path: path, - ref_id: ast::DUMMY_NODE_ID, - lifetimes: lifetime_defs, - })) + let poly_trait_ref = self.parse_poly_trait_ref(); + result.push(TraitTyParamBound(poly_trait_ref)) } _ => break, } @@ -3898,7 +3909,7 @@ impl<'a> Parser<'a> { return OwnedSlice::from_vec(result); } - fn trait_ref_from_ident(ident: Ident, span: Span) -> ast::TraitRef { + fn trait_ref_from_ident(ident: Ident, span: Span) -> TraitRef { let segment = ast::PathSegment { identifier: ident, parameters: ast::PathParameters::none() @@ -3911,7 +3922,6 @@ impl<'a> Parser<'a> { ast::TraitRef { path: path, ref_id: ast::DUMMY_NODE_ID, - lifetimes: Vec::new(), } } @@ -3927,7 +3937,7 @@ impl<'a> Parser<'a> { let mut unbound = None; if self.eat(&token::Question) { let tref = Parser::trait_ref_from_ident(ident, span); - unbound = Some(TraitTyParamBound(tref)); + unbound = Some(tref); span = self.span; ident = self.parse_ident(); } @@ -4538,7 +4548,6 @@ impl<'a> Parser<'a> { Some(TraitRef { path: (*path).clone(), ref_id: node_id, - lifetimes: Vec::new(), }) } TyPath(_, Some(_), _) => { @@ -4568,6 +4577,35 @@ impl<'a> Parser<'a> { Some(attrs)) } + /// Parse a::B + fn parse_trait_ref(&mut self) -> TraitRef { + ast::TraitRef { + path: self.parse_path(LifetimeAndTypesWithoutColons).path, + ref_id: ast::DUMMY_NODE_ID, + } + } + + fn parse_late_bound_lifetime_defs(&mut self) -> Vec { + if self.eat_keyword(keywords::For) { + self.expect(&token::Lt); + let lifetime_defs = self.parse_lifetime_defs(); + self.expect_gt(); + lifetime_defs + } else { + Vec::new() + } + } + + /// Parse for<'l> a::B + fn parse_poly_trait_ref(&mut self) -> PolyTraitRef { + let lifetime_defs = self.parse_late_bound_lifetime_defs(); + + ast::PolyTraitRef { + bound_lifetimes: lifetime_defs, + trait_ref: self.parse_trait_ref() + } + } + /// Parse struct Foo { ... } fn parse_item_struct(&mut self) -> ItemInfo { let class_name = self.parse_ident(); @@ -4681,7 +4719,7 @@ impl<'a> Parser<'a> { else { Inherited } } - fn parse_for_sized(&mut self) -> Option { + fn parse_for_sized(&mut self) -> Option { if self.eat_keyword(keywords::For) { let span = self.span; let ident = self.parse_ident(); @@ -4691,7 +4729,7 @@ impl<'a> Parser<'a> { return None; } let tref = Parser::trait_ref_from_ident(ident, span); - Some(TraitTyParamBound(tref)) + Some(tref) } else { None } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 63e2c5499e8f1..5b57a875c4afb 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -743,6 +743,9 @@ impl<'a> State<'a> { ast::TyPath(ref path, ref bounds, _) => { try!(self.print_bounded_path(path, bounds)); } + ast::TyPolyTraitRef(ref poly_trait_ref) => { + try!(self.print_poly_trait_ref(&**poly_trait_ref)); + } ast::TyQPath(ref qpath) => { try!(word(&mut self.s, "<")); try!(self.print_type(&*qpath.for_type)); @@ -960,7 +963,7 @@ impl<'a> State<'a> { try!(self.print_ident(item.ident)); try!(self.print_generics(generics)); match unbound { - &Some(TraitTyParamBound(ref tref)) => { + &Some(ref tref) => { try!(space(&mut self.s)); try!(self.word_space("for")); try!(self.print_trait_ref(tref)); @@ -995,19 +998,21 @@ impl<'a> State<'a> { } fn print_trait_ref(&mut self, t: &ast::TraitRef) -> IoResult<()> { - if t.lifetimes.len() > 0 { - try!(self.print_generics(&ast::Generics { - lifetimes: t.lifetimes.clone(), - ty_params: OwnedSlice::empty(), - where_clause: ast::WhereClause { - id: ast::DUMMY_NODE_ID, - predicates: Vec::new(), - }, - })); - } self.print_path(&t.path, false) } + fn print_poly_trait_ref(&mut self, t: &ast::PolyTraitRef) -> IoResult<()> { + if !t.bound_lifetimes.is_empty() { + try!(word(&mut self.s, "for<")); + for lifetime_def in t.bound_lifetimes.iter() { + try!(self.print_lifetime_def(lifetime_def)); + } + try!(word(&mut self.s, ">")); + } + + self.print_trait_ref(&t.trait_ref) + } + pub fn print_enum_def(&mut self, enum_definition: &ast::EnumDef, generics: &ast::Generics, ident: ast::Ident, span: codemap::Span, @@ -2383,7 +2388,7 @@ impl<'a> State<'a> { try!(match *bound { TraitTyParamBound(ref tref) => { - self.print_trait_ref(tref) + self.print_poly_trait_ref(tref) } RegionTyParamBound(ref lt) => { self.print_lifetime(lt) @@ -2450,7 +2455,7 @@ impl<'a> State<'a> { pub fn print_ty_param(&mut self, param: &ast::TyParam) -> IoResult<()> { match param.unbound { - Some(TraitTyParamBound(ref tref)) => { + Some(ref tref) => { try!(self.print_trait_ref(tref)); try!(self.word_space("?")); } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 9751abacbd3ff..1b1d1e9cace1a 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -75,6 +75,10 @@ pub trait Visitor<'v> { } fn visit_ty_method(&mut self, t: &'v TypeMethod) { walk_ty_method(self, t) } fn visit_trait_item(&mut self, t: &'v TraitItem) { walk_trait_item(self, t) } + fn visit_trait_ref(&mut self, t: &'v TraitRef) { walk_trait_ref(self, t) } + fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef) { + walk_poly_trait_ref(self, t) + } fn visit_struct_def(&mut self, s: &'v StructDef, _: Ident, _: &'v Generics, _: NodeId) { walk_struct_def(self, s) } @@ -202,9 +206,20 @@ pub fn walk_explicit_self<'v, V: Visitor<'v>>(visitor: &mut V, /// Like with walk_method_helper this doesn't correspond to a method /// in Visitor, and so it gets a _helper suffix. -pub fn walk_trait_ref_helper<'v,V>(visitor: &mut V, trait_ref: &'v TraitRef) - where V: Visitor<'v> { - walk_lifetime_decls(visitor, &trait_ref.lifetimes); +pub fn walk_poly_trait_ref<'v, V>(visitor: &mut V, + trait_ref: &'v PolyTraitRef) + where V: Visitor<'v> +{ + walk_lifetime_decls(visitor, &trait_ref.bound_lifetimes); + visitor.visit_trait_ref(&trait_ref.trait_ref); +} + +/// Like with walk_method_helper this doesn't correspond to a method +/// in Visitor, and so it gets a _helper suffix. +pub fn walk_trait_ref<'v,V>(visitor: &mut V, + trait_ref: &'v TraitRef) + where V: Visitor<'v> +{ visitor.visit_path(&trait_ref.path, trait_ref.ref_id) } @@ -248,8 +263,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { ref impl_items) => { visitor.visit_generics(type_parameters); match *trait_reference { - Some(ref trait_reference) => walk_trait_ref_helper(visitor, - trait_reference), + Some(ref trait_reference) => visitor.visit_trait_ref(trait_reference), None => () } visitor.visit_ty(&**typ); @@ -383,6 +397,9 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { visitor.visit_ty(&**ty); visitor.visit_expr(&**expression) } + TyPolyTraitRef(ref poly_trait_ref) => { + visitor.visit_poly_trait_ref(&**poly_trait_ref) + } TyTypeof(ref expression) => { visitor.visit_expr(&**expression) } @@ -497,7 +514,7 @@ pub fn walk_ty_param_bounds<'v, V: Visitor<'v>>(visitor: &mut V, for bound in bounds.iter() { match *bound { TraitTyParamBound(ref typ) => { - walk_trait_ref_helper(visitor, typ) + visitor.visit_poly_trait_ref(typ) } RegionTyParamBound(ref lifetime) => { visitor.visit_lifetime_ref(lifetime); diff --git a/src/test/compile-fail/issue-10291.rs b/src/test/compile-fail/issue-10291.rs index 995ae7b3d44e7..924132c6de26b 100644 --- a/src/test/compile-fail/issue-10291.rs +++ b/src/test/compile-fail/issue-10291.rs @@ -9,7 +9,7 @@ // except according to those terms. fn test<'x>(x: &'x int) { - drop::< <'z>|&'z int| -> &'z int >(|z| { + drop::< for<'z>|&'z int| -> &'z int >(|z| { x //~^ ERROR cannot infer an appropriate lifetime }); diff --git a/src/test/compile-fail/regions-fn-subtyping-return-static.rs b/src/test/compile-fail/regions-fn-subtyping-return-static.rs index 4c90b1f0eeabf..ac56e8ce14df6 100644 --- a/src/test/compile-fail/regions-fn-subtyping-return-static.rs +++ b/src/test/compile-fail/regions-fn-subtyping-return-static.rs @@ -22,11 +22,11 @@ struct S; // Given 'cx, return 'cx -type F = fn<'cx>(&'cx S) -> &'cx S; +type F = for<'cx> fn(&'cx S) -> &'cx S; fn want_F(f: F) { } // Given anything, return 'static -type G = fn<'cx>(&'cx S) -> &'static S; +type G = for<'cx> fn(&'cx S) -> &'static S; fn want_G(f: G) { } // Should meet both. diff --git a/src/test/compile-fail/regions-fn-subtyping.rs b/src/test/compile-fail/regions-fn-subtyping.rs index 8e8d892a39f22..91a6ff789ea39 100644 --- a/src/test/compile-fail/regions-fn-subtyping.rs +++ b/src/test/compile-fail/regions-fn-subtyping.rs @@ -17,29 +17,29 @@ fn test_fn<'x,'y,'z,T>(_x: &'x T, _y: &'y T, _z: &'z T) { // subtype::(of::()) will typecheck // iff T1 <: T2. - subtype::< <'a>|&'a T|>( - of::< <'a>|&'a T|>()); + subtype::< for<'a>|&'a T|>( + of::< for<'a>|&'a T|>()); - subtype::< <'a>|&'a T|>( - of::< <'b>|&'b T|>()); + subtype::< for<'a>|&'a T|>( + of::< for<'b>|&'b T|>()); - subtype::< <'b>|&'b T|>( + subtype::< for<'b>|&'b T|>( of::<|&'x T|>()); subtype::<|&'x T|>( - of::< <'b>|&'b T|>()); //~ ERROR mismatched types + of::< for<'b>|&'b T|>()); //~ ERROR mismatched types - subtype::< <'a,'b>|&'a T, &'b T|>( - of::< <'a>|&'a T, &'a T|>()); + subtype::< for<'a,'b>|&'a T, &'b T|>( + of::< for<'a>|&'a T, &'a T|>()); - subtype::< <'a>|&'a T, &'a T|>( - of::< <'a,'b>|&'a T, &'b T|>()); //~ ERROR mismatched types + subtype::< for<'a>|&'a T, &'a T|>( + of::< for<'a,'b>|&'a T, &'b T|>()); //~ ERROR mismatched types - subtype::< <'a,'b>|&'a T, &'b T|>( + subtype::< for<'a,'b>|&'a T, &'b T|>( of::<|&'x T, &'y T|>()); subtype::<|&'x T, &'y T|>( - of::< <'a,'b>|&'a T, &'b T|>()); //~ ERROR mismatched types + of::< for<'a,'b>|&'a T, &'b T|>()); //~ ERROR mismatched types } fn main() {} diff --git a/src/test/compile-fail/regions-name-undeclared.rs b/src/test/compile-fail/regions-name-undeclared.rs index ba3d7bd29f4ac..e9e585e84d0ef 100644 --- a/src/test/compile-fail/regions-name-undeclared.rs +++ b/src/test/compile-fail/regions-name-undeclared.rs @@ -43,16 +43,16 @@ fn bar<'a>(x: &'a int) { // &'a CAN be declared on functions and used then: fn g<'a>(a: &'a int) { } // OK - fn h(a: <'a>|&'a int|) { } // OK + fn h(a: for<'a>|&'a int|) { } // OK } // Test nesting of lifetimes in fn type declarations fn fn_types(a: &'a int, //~ ERROR undeclared lifetime - b: <'a>|a: &'a int, - b: &'b int, //~ ERROR undeclared lifetime - c: <'b>|a: &'a int, - b: &'b int|, - d: &'b int|, //~ ERROR undeclared lifetime + b: for<'a>|a: &'a int, + b: &'b int, //~ ERROR undeclared lifetime + c: for<'b>|a: &'a int, + b: &'b int|, + d: &'b int|, //~ ERROR undeclared lifetime c: &'a int) //~ ERROR undeclared lifetime { } diff --git a/src/test/compile-fail/regions-nested-fns-2.rs b/src/test/compile-fail/regions-nested-fns-2.rs index 60eae9ce80af1..a08cf2263894d 100644 --- a/src/test/compile-fail/regions-nested-fns-2.rs +++ b/src/test/compile-fail/regions-nested-fns-2.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn ignore(_f: <'z>|&'z int| -> &'z int) {} +fn ignore(_f: for<'z>|&'z int| -> &'z int) {} fn nested() { let y = 3; diff --git a/src/test/compile-fail/regions-nested-fns.rs b/src/test/compile-fail/regions-nested-fns.rs index 7dc57d37e2496..cf0b615bb01ab 100644 --- a/src/test/compile-fail/regions-nested-fns.rs +++ b/src/test/compile-fail/regions-nested-fns.rs @@ -14,13 +14,13 @@ fn nested<'x>(x: &'x int) { let y = 3; let mut ay = &y; //~ ERROR cannot infer - ignore::< <'z>|&'z int|>(|z| { + ignore::< for<'z>|&'z int|>(|z| { ay = x; ay = &y; ay = z; }); - ignore::< <'z>|&'z int| -> &'z int>(|z| { + ignore::< for<'z>|&'z int| -> &'z int>(|z| { if false { return x; } //~ ERROR cannot infer an appropriate lifetime for automatic if false { return ay; } return z; diff --git a/src/test/compile-fail/regions-ret-borrowed-1.rs b/src/test/compile-fail/regions-ret-borrowed-1.rs index 6d9b261917105..997775efa84b5 100644 --- a/src/test/compile-fail/regions-ret-borrowed-1.rs +++ b/src/test/compile-fail/regions-ret-borrowed-1.rs @@ -12,7 +12,7 @@ // some point regions-ret-borrowed reported an error but this file did // not, due to special hardcoding around the anonymous region. -fn with(f: <'a>|x: &'a int| -> R) -> R { +fn with(f: for<'a>|x: &'a int| -> R) -> R { f(&3) } diff --git a/src/test/run-pass/hrtb-parse.rs b/src/test/run-pass/hrtb-parse.rs new file mode 100644 index 0000000000000..080523f0060a7 --- /dev/null +++ b/src/test/run-pass/hrtb-parse.rs @@ -0,0 +1,48 @@ +// 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 we can parse all the various places that a `for` keyword +// can appear representing universal quantification. + +#![allow(unused_variables)] +#![allow(dead_code)] + +trait Get { + fn get(&self, arg: A) -> R; +} + +// Parse HRTB with explicit `for` in a where-clause: + +fn foo00(t: T) + where T : for<'a> Get<&'a int, &'a int> +{ +} + +fn foo01 Get<&'a int, &'a int>>(t: T) +{ +} + +// Parse HRTB with explicit `for` in various sorts of types: + +fn foo10(t: Box Get>) { } +fn foo11(t: Box Get(int) -> int>) { } + +fn foo20(t: for<'a> fn(int) -> int) { } +fn foo21(t: for<'a> unsafe fn(int) -> int) { } +fn foo22(t: for<'a> extern "C" fn(int) -> int) { } +fn foo23(t: for<'a> unsafe extern "C" fn(int) -> int) { } + +fn foo30(t: for<'a> |int| -> int) { } +fn foo31(t: for<'a> unsafe |int| -> int) { } + +//fn foo40(t: for<'a> proc(int) -> int) { } + +fn main() { +} diff --git a/src/test/run-pass/nullable-pointer-ffi-compat.rs b/src/test/run-pass/nullable-pointer-ffi-compat.rs index b5c541b0c6390..32432c07dcf41 100644 --- a/src/test/run-pass/nullable-pointer-ffi-compat.rs +++ b/src/test/run-pass/nullable-pointer-ffi-compat.rs @@ -29,7 +29,7 @@ static FOO: int = 0xDEADBEE; pub fn main() { unsafe { - let f: extern "C" fn<'a>(&'a int) -> &'a int = mem::transmute(foo); + let f: for<'a> extern "C" fn(&'a int) -> &'a int = mem::transmute(foo); assert_eq!(*f(&FOO), FOO); } } From 3112771001e0e7e9b068ba0bb0ca45c3e8f0f72a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 7 Nov 2014 15:48:39 -0500 Subject: [PATCH 3/5] Update tests where we don't report errors twice anymore --- src/test/compile-fail/regions-name-duplicated.rs | 1 - src/test/compile-fail/regions-name-static.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/src/test/compile-fail/regions-name-duplicated.rs b/src/test/compile-fail/regions-name-duplicated.rs index 58eaa4c57fe15..518fe0b00b6ce 100644 --- a/src/test/compile-fail/regions-name-duplicated.rs +++ b/src/test/compile-fail/regions-name-duplicated.rs @@ -9,7 +9,6 @@ // except according to those terms. struct Foo<'a, 'a> { //~ ERROR lifetime name `'a` declared twice -//~^ ERROR lifetime name `'a` declared twice x: &'a int } diff --git a/src/test/compile-fail/regions-name-static.rs b/src/test/compile-fail/regions-name-static.rs index bc8ca87d7e29d..9f50ad3666025 100644 --- a/src/test/compile-fail/regions-name-static.rs +++ b/src/test/compile-fail/regions-name-static.rs @@ -9,7 +9,6 @@ // except according to those terms. struct Foo<'static> { //~ ERROR illegal lifetime parameter name: `'static` -//~^ ERROR illegal lifetime parameter name: `'static` x: &'static int } From 091dc6e98a483c164735e9a0b9c5b3750a94a95f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 7 Nov 2014 15:48:55 -0500 Subject: [PATCH 4/5] Purge the old `once_fns`, which are not coming back --- src/libsyntax/feature_gate.rs | 10 ++-- src/libsyntax/parse/token.rs | 59 +++++++++---------- src/libsyntax/print/pprust.rs | 9 --- .../once-cant-call-twice-on-stack.rs | 28 --------- ...once-cant-move-out-of-non-once-on-stack.rs | 27 --------- src/test/compile-fail/once-fn-subtyping.rs | 17 ------ src/test/run-pass/once-move-out-on-heap.rs | 1 - src/test/run-pass/once-move-out-on-stack.rs | 27 --------- 8 files changed, 33 insertions(+), 145 deletions(-) delete mode 100644 src/test/compile-fail/once-cant-call-twice-on-stack.rs delete mode 100644 src/test/compile-fail/once-cant-move-out-of-non-once-on-stack.rs delete mode 100644 src/test/compile-fail/once-fn-subtyping.rs delete mode 100644 src/test/run-pass/once-move-out-on-stack.rs diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 80b158a54d36c..c38fea9b3d58a 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -38,7 +38,6 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[ ("globs", Active), ("macro_rules", Active), ("struct_variant", Active), - ("once_fns", Active), ("asm", Active), ("managed_boxes", Removed), ("non_ascii_idents", Active), @@ -307,11 +306,10 @@ impl<'a, 'v> Visitor<'v> for Context<'a> { fn visit_ty(&mut self, t: &ast::Ty) { match t.node { - ast::TyClosure(ref closure) if closure.onceness == ast::Once => { - self.gate_feature("once_fns", t.span, - "once functions are \ - experimental and likely to be removed"); - + ast::TyClosure(ref closure) => { + // this used to be blocked by a feature gate, but it should just + // be plain impossible right now + assert!(closure.onceness != ast::Once); }, _ => {} } diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index b0cca5e14de15..f501a5831d2ad 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -503,42 +503,41 @@ declare_special_idents_and_keywords! { (27, Mod, "mod"); (28, Move, "move"); (29, Mut, "mut"); - (30, Once, "once"); - (31, Pub, "pub"); - (32, Ref, "ref"); - (33, Return, "return"); + (30, Pub, "pub"); + (31, Ref, "ref"); + (32, Return, "return"); // Static and Self are also special idents (prefill de-dupes) (super::STATIC_KEYWORD_NAME_NUM, Static, "static"); (super::SELF_KEYWORD_NAME_NUM, Self, "self"); - (34, Struct, "struct"); + (33, Struct, "struct"); (super::SUPER_KEYWORD_NAME_NUM, Super, "super"); - (35, True, "true"); - (36, Trait, "trait"); - (37, Type, "type"); - (38, Unsafe, "unsafe"); - (39, Use, "use"); - (40, Virtual, "virtual"); - (41, While, "while"); - (42, Continue, "continue"); - (43, Proc, "proc"); - (44, Box, "box"); - (45, Const, "const"); - (46, Where, "where"); + (34, True, "true"); + (35, Trait, "trait"); + (36, Type, "type"); + (37, Unsafe, "unsafe"); + (38, Use, "use"); + (39, Virtual, "virtual"); + (40, While, "while"); + (41, Continue, "continue"); + (42, Proc, "proc"); + (43, Box, "box"); + (44, Const, "const"); + (45, Where, "where"); 'reserved: - (47, Alignof, "alignof"); - (48, Be, "be"); - (49, Offsetof, "offsetof"); - (50, Priv, "priv"); - (51, Pure, "pure"); - (52, Sizeof, "sizeof"); - (53, Typeof, "typeof"); - (54, Unsized, "unsized"); - (55, Yield, "yield"); - (56, Do, "do"); - (57, Abstract, "abstract"); - (58, Final, "final"); - (59, Override, "override"); + (46, Alignof, "alignof"); + (47, Be, "be"); + (48, Offsetof, "offsetof"); + (49, Priv, "priv"); + (50, Pure, "pure"); + (51, Sizeof, "sizeof"); + (52, Typeof, "typeof"); + (53, Unsized, "unsized"); + (54, Yield, "yield"); + (55, Do, "do"); + (56, Abstract, "abstract"); + (57, Final, "final"); + (58, Override, "override"); } } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 5b57a875c4afb..c1515a36bec68 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2663,12 +2663,10 @@ impl<'a> State<'a> { } else if opt_sigil == Some('&') { try!(self.print_fn_style(fn_style)); try!(self.print_extern_opt_abi(opt_abi)); - try!(self.print_onceness(onceness)); } else { assert!(opt_sigil.is_none()); try!(self.print_fn_style(fn_style)); try!(self.print_opt_abi_and_extern_if_nondefault(opt_abi)); - try!(self.print_onceness(onceness)); try!(word(&mut self.s, "fn")); } @@ -2987,13 +2985,6 @@ impl<'a> State<'a> { ast::UnsafeFn => self.word_nbsp("unsafe"), } } - - pub fn print_onceness(&mut self, o: ast::Onceness) -> IoResult<()> { - match o { - ast::Once => self.word_nbsp("once"), - ast::Many => Ok(()) - } - } } #[cfg(test)] diff --git a/src/test/compile-fail/once-cant-call-twice-on-stack.rs b/src/test/compile-fail/once-cant-call-twice-on-stack.rs deleted file mode 100644 index 17968195280a1..0000000000000 --- a/src/test/compile-fail/once-cant-call-twice-on-stack.rs +++ /dev/null @@ -1,28 +0,0 @@ -// 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. - -// Testing guarantees provided by once functions. -// This program would segfault if it were legal. - -#![feature(once_fns)] -use std::sync::Arc; - -fn foo(blk: once ||) { - blk(); - blk(); //~ ERROR use of moved value -} - -fn main() { - let x = Arc::new(true); - foo(|| { - assert!(*x); - drop(x); - }) -} diff --git a/src/test/compile-fail/once-cant-move-out-of-non-once-on-stack.rs b/src/test/compile-fail/once-cant-move-out-of-non-once-on-stack.rs deleted file mode 100644 index 3efebf6184406..0000000000000 --- a/src/test/compile-fail/once-cant-move-out-of-non-once-on-stack.rs +++ /dev/null @@ -1,27 +0,0 @@ -// 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. - -// Testing guarantees provided by once functions. -// This program would segfault if it were legal. - -use std::sync::Arc; - -fn foo(blk: ||) { - blk(); - blk(); -} - -fn main() { - let x = Arc::new(true); - foo(|| { - assert!(*x); - drop(x); //~ ERROR cannot move out of captured outer variable - }) -} diff --git a/src/test/compile-fail/once-fn-subtyping.rs b/src/test/compile-fail/once-fn-subtyping.rs deleted file mode 100644 index 7594deda3b2d8..0000000000000 --- a/src/test/compile-fail/once-fn-subtyping.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2012-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(once_fns)] -fn main() { - let f: once || = ||(); - let g: || = f; //~ ERROR mismatched types - let h: || = ||(); - let i: once || = h; // ok -} diff --git a/src/test/run-pass/once-move-out-on-heap.rs b/src/test/run-pass/once-move-out-on-heap.rs index dfd5992a40675..e24e809ed018a 100644 --- a/src/test/run-pass/once-move-out-on-heap.rs +++ b/src/test/run-pass/once-move-out-on-heap.rs @@ -11,7 +11,6 @@ // Testing guarantees provided by once functions. -#![feature(once_fns)] use std::sync::Arc; fn foo(blk: proc()) { diff --git a/src/test/run-pass/once-move-out-on-stack.rs b/src/test/run-pass/once-move-out-on-stack.rs deleted file mode 100644 index 0419fc54add15..0000000000000 --- a/src/test/run-pass/once-move-out-on-stack.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2013-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. - -// Testing guarantees provided by once functions. - - -#![feature(once_fns)] -use std::sync::Arc; - -fn foo(blk: once ||) { - blk(); -} - -pub fn main() { - let x = Arc::new(true); - foo(|| { - assert!(*x); - drop(x); - }) -} From cf4e53eee7377b42524176f39b0b428175c74fb1 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 7 Nov 2014 15:58:19 -0500 Subject: [PATCH 5/5] Fix tidy error --- src/librustc/middle/typeck/collect.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 42411b598bfae..c4e50c25e3ef4 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -1155,7 +1155,8 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { parent_visibility); for trait_ref in opt_trait_ref.iter() { - astconv::instantiate_trait_ref(&icx, &ExplicitRscope, trait_ref, Some(selfty), None); + astconv::instantiate_trait_ref(&icx, &ExplicitRscope, trait_ref, + Some(selfty), None); } }, ast::ItemTrait(_, _, _, ref trait_methods) => {