From c6c58e745ecec09e9536ee15ca70bbab69c96dcb Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Fri, 22 May 2015 13:48:28 +0300 Subject: [PATCH 1/4] Make wf check the bounds of built-in types Fixes #24957 --- src/librustc/middle/traits/error_reporting.rs | 18 +++++ src/librustc/middle/traits/mod.rs | 7 +- src/librustc_typeck/check/mod.rs | 1 - src/librustc_typeck/check/wf.rs | 67 ++++++++++++++----- .../associated-types-coherence-failure.rs | 2 +- src/test/compile-fail/issue-18107.rs | 3 +- src/test/compile-fail/issue-23041.rs | 7 +- src/test/compile-fail/issue-24957.rs | 24 +++++++ src/test/compile-fail/issue-5883.rs | 1 - src/test/compile-fail/unsized6.rs | 9 ++- src/test/compile-fail/wf-non-well-formed.rs | 41 ++++++++++++ .../wf-specific-sized-where-clause.rs | 18 +++++ 12 files changed, 165 insertions(+), 33 deletions(-) create mode 100644 src/test/compile-fail/issue-24957.rs create mode 100644 src/test/compile-fail/wf-non-well-formed.rs create mode 100644 src/test/compile-fail/wf-specific-sized-where-clause.rs diff --git a/src/librustc/middle/traits/error_reporting.rs b/src/librustc/middle/traits/error_reporting.rs index 2b82987480d6e..4490d1079c73c 100644 --- a/src/librustc/middle/traits/error_reporting.rs +++ b/src/librustc/middle/traits/error_reporting.rs @@ -430,6 +430,24 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, "the return type of a function must have a \ statically known size"); } + ObligationCauseCode::ArgumentType => { + tcx.sess.span_note( + cause_span, + "the type of a function's argument must have a \ + statically known size"); + } + ObligationCauseCode::TupleElemSized => { + tcx.sess.span_note( + cause_span, + "tuples can only contain elements with a \ + statically known size"); + } + ObligationCauseCode::VecElemSized => { + tcx.sess.span_note( + cause_span, + "arrays can only contain elements with a \ + statically known size"); + } ObligationCauseCode::AssignmentLhsSized => { tcx.sess.span_note( cause_span, diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index fe61bb5e4ea6f..71b2c3757d7d4 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -114,14 +114,17 @@ pub enum ObligationCauseCode<'tcx> { StructInitializerSized, // S { ... } must be Sized VariableType(ast::NodeId), // Type of each variable must be Sized ReturnType, // Return type must be Sized + ArgumentType, // Argument type must be Sized + VecElemSized, // Array element must be Sized + TupleElemSized, // Tuple element must be Sized + FieldSized, // Types of fields (other than the last) + // in a struct must be sized. RepeatVec, // [T,..n] --> T must be Copy // Captures of variable the given id by a closure (span is the // span of the closure) ClosureCapture(ast::NodeId, Span, ty::BuiltinBound), - // Types of fields (other than the last) in a struct must be sized. - FieldSized, // static items must have `Sync` type SharedStatic, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 0e64063d6a402..724f30a8ec941 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -667,7 +667,6 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, .collect(); if let ty::FnConverging(ret_ty) = ret_ty { - fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::ReturnType); fn_sig_tys.push(ret_ty); } diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index 79736c08f3796..347c323cc567c 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -16,7 +16,6 @@ use middle::region; use middle::subst::{self, TypeSpace, FnSpace, ParamSpace, SelfSpace}; use middle::traits; use middle::ty::{self, Ty}; -use middle::ty::liberate_late_bound_regions; use middle::ty_fold::{TypeFolder, TypeFoldable, super_fold_ty}; use util::ppaux::{Repr, UserString}; @@ -510,10 +509,7 @@ impl<'cx,'tcx> BoundsChecker<'cx,'tcx> { &trait_predicates); self.fcx.add_obligations_for_parameters( - traits::ObligationCause::new( - self.span, - self.fcx.body_id, - traits::ItemObligation(trait_ref.def_id)), + self.cause(traits::ItemObligation(trait_ref.def_id)), &bounds); for &ty in trait_ref.substs.types.iter() { @@ -532,8 +528,13 @@ impl<'cx,'tcx> BoundsChecker<'cx,'tcx> { ty.fold_with(self); self.binding_count -= 1; } + + fn cause(&self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> { + traits::ObligationCause::new(self.span, self.fcx.body_id, code) + } } +// Note: TypeFolder here is used as a visitor. impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> { fn tcx(&self) -> &ty::ctxt<'tcx> { self.fcx.tcx() @@ -543,7 +544,7 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> { where T : TypeFoldable<'tcx> + Repr<'tcx> { self.binding_count += 1; - let value = liberate_late_bound_regions( + let value = ty::liberate_late_bound_regions( self.fcx.tcx(), region::DestructionScopeData::new(self.scope), binder); @@ -554,6 +555,24 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> { ty::Binder(value) } + + fn fold_fn_sig(&mut self, sig: &ty::FnSig<'tcx>) -> ty::FnSig<'tcx> { + if let ty::FnConverging(ret) = sig.output { + self.fcx.register_builtin_bound(self.fold_ty(ret), + ty::BoundSized, + self.cause(traits::ReturnType)); + } + + for input in &sig.inputs { + self.fcx.register_builtin_bound(self.fold_ty(input), + ty::BoundSized, + self.cause(traits::ArgumentType)); + } + + sig.clone() + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { debug!("BoundsChecker t={}", t.repr(self.tcx())); @@ -569,7 +588,23 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> { None => { } } - match t.sty{ + match t.sty { + ty::ty_vec(ety, _) => { + self.fcx.register_builtin_bound(self.fold_ty(ety), + ty::BoundSized, + self.cause(traits::VecElemSized)); + t + } + ty::ty_tup(ref tys) => { + for ty in tys { + self.fcx.register_builtin_bound(self.fold_ty(ty), + ty::BoundSized, + self.cause(traits::TupleElemSized) + ); + + } + t + } ty::ty_struct(type_id, substs) | ty::ty_enum(type_id, substs) => { let type_predicates = ty::lookup_predicates(self.fcx.tcx(), type_id); @@ -578,9 +613,7 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> { if self.binding_count == 0 { self.fcx.add_obligations_for_parameters( - traits::ObligationCause::new(self.span, - self.fcx.body_id, - traits::ItemObligation(type_id)), + self.cause(traits::ItemObligation(type_id)), &bounds); } else { // There are two circumstances in which we ignore @@ -605,22 +638,22 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> { // // (I believe we should do the same for traits, but // that will require an RFC. -nmatsakis) + // + // TODO(arielb1): this also seems to be triggered + // when you have something like + // for<'a> Trait<&'a (), &'free1 &'free2 ()> let bounds = filter_to_trait_obligations(bounds); self.fcx.add_obligations_for_parameters( - traits::ObligationCause::new(self.span, - self.fcx.body_id, - traits::ItemObligation(type_id)), + self.cause(traits::ItemObligation(type_id)), &bounds); } - self.fold_substs(substs); + t } _ => { - super_fold_ty(self, t); + super_fold_ty(self, t) } } - - t // we're not folding to produce a new type, so just return `t` here } } diff --git a/src/test/compile-fail/associated-types-coherence-failure.rs b/src/test/compile-fail/associated-types-coherence-failure.rs index 915cb077787ea..757271dc56795 100644 --- a/src/test/compile-fail/associated-types-coherence-failure.rs +++ b/src/test/compile-fail/associated-types-coherence-failure.rs @@ -14,7 +14,7 @@ use std::marker::PhantomData; use std::ops::Deref; -pub struct Cow<'a, B: ?Sized>(PhantomData<(&'a (),B)>); +pub struct Cow<'a, B: ?Sized+'a>(PhantomData<(&'a (),&'a B)>); /// Trait for moving into a `Cow` pub trait IntoCow<'a, B: ?Sized> { diff --git a/src/test/compile-fail/issue-18107.rs b/src/test/compile-fail/issue-18107.rs index 6300a1dc15d60..1b04ee9b2a612 100644 --- a/src/test/compile-fail/issue-18107.rs +++ b/src/test/compile-fail/issue-18107.rs @@ -10,8 +10,7 @@ pub trait AbstractRenderer {} -fn _create_render(_: &()) -> - AbstractRenderer +fn _create_render(_: &()) -> AbstractRenderer //~^ ERROR: the trait `core::marker::Sized` is not implemented { match 0 { diff --git a/src/test/compile-fail/issue-23041.rs b/src/test/compile-fail/issue-23041.rs index 68895759c5c2a..b27862a61e547 100644 --- a/src/test/compile-fail/issue-23041.rs +++ b/src/test/compile-fail/issue-23041.rs @@ -11,8 +11,7 @@ use std::any::Any; fn main() { - fn bar(x:i32) ->i32 { 3*x }; - let b:Box = Box::new(bar as fn(_)->_); - b.downcast_ref::_>(); - //~^ ERROR cannot determine a type for this expression: unconstrained type + fn bar(x:&'static i32) -> &'static i32 { x }; + let b:Box = Box::new(bar as fn(&'static _)->&'static _); + b.downcast_ref::&_>(); //~ ERROR unconstrained type } diff --git a/src/test/compile-fail/issue-24957.rs b/src/test/compile-fail/issue-24957.rs new file mode 100644 index 0000000000000..857403cc3e10a --- /dev/null +++ b/src/test/compile-fail/issue-24957.rs @@ -0,0 +1,24 @@ +// Copyright 2015 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. + +pub enum BsonValue { +//~^ ERROR the trait `core::marker::Sized` is not implemented +//~^^ ERROR the trait `core::marker::Sized` is not implemented + A([u8]), + B([BsonValue]), +} + +pub fn set_value(_v:&BsonValue) +{ +} + +fn main() +{ +} diff --git a/src/test/compile-fail/issue-5883.rs b/src/test/compile-fail/issue-5883.rs index 9ff957b6e6dea..b81d637c58401 100644 --- a/src/test/compile-fail/issue-5883.rs +++ b/src/test/compile-fail/issue-5883.rs @@ -16,7 +16,6 @@ struct Struct { fn new_struct(r: A+'static) -> Struct { //~^ ERROR the trait `core::marker::Sized` is not implemented - //~^ ERROR the trait `core::marker::Sized` is not implemented Struct { r: r } } diff --git a/src/test/compile-fail/unsized6.rs b/src/test/compile-fail/unsized6.rs index 3f18f359d306e..87509c72b3623 100644 --- a/src/test/compile-fail/unsized6.rs +++ b/src/test/compile-fail/unsized6.rs @@ -12,11 +12,13 @@ trait T {} +struct T2(U, V); + fn f1(x: &X) { let _: X; // <-- this is OK, no bindings created, no initializer. - let _: (isize, (X, isize)); // same + let _: T2>; let y: X; //~ERROR the trait `core::marker::Sized` is not implemented - let y: (isize, (X, isize)); //~ERROR the trait `core::marker::Sized` is not implemented + let y: T2>; //~ERROR the trait `core::marker::Sized` is not implemented } fn f2(x: &X) { let y: X; //~ERROR the trait `core::marker::Sized` is not implemented @@ -34,8 +36,5 @@ fn f4(x1: Box, x2: Box, x3: Box) { let (y, z) = (*x3, 4); //~ERROR the trait `core::marker::Sized` is not implemented } -fn g1(x: X) {} //~ERROR the trait `core::marker::Sized` is not implemented -fn g2(x: X) {} //~ERROR the trait `core::marker::Sized` is not implemented - pub fn main() { } diff --git a/src/test/compile-fail/wf-non-well-formed.rs b/src/test/compile-fail/wf-non-well-formed.rs new file mode 100644 index 0000000000000..43b2917a10392 --- /dev/null +++ b/src/test/compile-fail/wf-non-well-formed.rs @@ -0,0 +1,41 @@ +// Copyright 2015 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. + +// Check that we catch attempts to create non-well-formed types + +trait Tr {} + +fn g1(x: X) {} //~ERROR the trait `core::marker::Sized` is not implemented +fn g2(x: X) {} //~ERROR the trait `core::marker::Sized` is not implemented + +fn bogus( //~ERROR the trait `core::marker::Sized` is not implemented + _: [u8]) +{ + loop {} +} + +struct S(T); + +fn b1() -> &'static [(u8,fn(&'static [S<()>]))] +{} //~^ ERROR the trait `Tr` is not implemented +fn b2() -> fn([u8]) +{} //~^ ERROR the trait `core::marker::Sized` is not implemented +fn b3() -> fn()->[u8] +{} //~^ ERROR the trait `core::marker::Sized` is not implemented +fn b4() -> &'static [[u8]] +{} //~^ ERROR the trait `core::marker::Sized` is not implemented +fn b5() -> &'static [[u8]; 2] +{} //~^ ERROR the trait `core::marker::Sized` is not implemented +fn b6() -> &'static ([u8],) +{} //~^ ERROR the trait `core::marker::Sized` is not implemented +fn b7() -> &'static (u32,[u8],u32) +{} //~^ ERROR the trait `core::marker::Sized` is not implemented + +fn main() {} diff --git a/src/test/compile-fail/wf-specific-sized-where-clause.rs b/src/test/compile-fail/wf-specific-sized-where-clause.rs new file mode 100644 index 0000000000000..065d6f9feecb4 --- /dev/null +++ b/src/test/compile-fail/wf-specific-sized-where-clause.rs @@ -0,0 +1,18 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Wrap<'a, T: ?Sized>(&'a (), T); + +fn foo<'a, T>(a: for<'s> fn() -> Wrap<'s, T>) where Wrap<'a, T>: Sized { + //~^ ERROR mismatched types + //~^^ ERROR mismatched types +} + +fn main() {} From 892666a8915fe11821d3432c1810d00f06587767 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Fri, 22 May 2015 16:02:24 +0300 Subject: [PATCH 2/4] Check the types of extern items Fixes #25637. --- src/librustc_typeck/check/regionck.rs | 6 ++-- src/librustc_typeck/check/wf.rs | 44 +++++++++++++++------------ src/test/compile-fail/issue-25637.rs | 22 ++++++++++++++ 3 files changed, 49 insertions(+), 23 deletions(-) create mode 100644 src/test/compile-fail/issue-25637.rs diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 090d111b62b89..3d371d7acb216 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -122,11 +122,11 @@ pub fn regionck_expr(fcx: &FnCtxt, e: &ast::Expr) { rcx.resolve_regions_and_report_errors(); } -pub fn regionck_item(fcx: &FnCtxt, item: &ast::Item) { - let mut rcx = Rcx::new(fcx, RepeatingScope(item.id), item.id, Subject(item.id)); +pub fn regionck_item(fcx: &FnCtxt, id: ast::NodeId) { + let mut rcx = Rcx::new(fcx, RepeatingScope(id), id, Subject(id)); let tcx = fcx.tcx(); rcx.free_region_map.relate_free_regions_from_predicates(tcx, &fcx.inh.param_env.caller_bounds); - rcx.visit_region_obligations(item.id); + rcx.visit_region_obligations(id); rcx.resolve_regions_and_report_errors(); } diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index 347c323cc567c..45bd4ea088551 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -94,13 +94,13 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { } } ast::ItemFn(..) => { - self.check_item_type(item); + self.check_item_type(item.span, item.id); } ast::ItemStatic(..) => { - self.check_item_type(item); + self.check_item_type(item.span, item.id); } ast::ItemConst(..) => { - self.check_item_type(item); + self.check_item_type(item.span, item.id); } ast::ItemStruct(ref struct_def, ref ast_generics) => { self.check_type_defn(item, |fcx| { @@ -133,32 +133,32 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { } } - fn with_fcx(&mut self, item: &ast::Item, mut f: F) where + fn with_fcx(&mut self, span: Span, id: ast::NodeId, mut f: F) where F: for<'fcx> FnMut(&mut CheckTypeWellFormedVisitor<'ccx, 'tcx>, &FnCtxt<'fcx, 'tcx>), { let ccx = self.ccx; - let item_def_id = local_def(item.id); + let item_def_id = local_def(id); let type_scheme = ty::lookup_item_type(ccx.tcx, item_def_id); let type_predicates = ty::lookup_predicates(ccx.tcx, item_def_id); - reject_non_type_param_bounds(ccx.tcx, item.span, &type_predicates); + reject_non_type_param_bounds(ccx.tcx, span, &type_predicates); let param_env = ty::construct_parameter_environment(ccx.tcx, - item.span, + span, &type_scheme.generics, &type_predicates, - item.id); + id); let inh = Inherited::new(ccx.tcx, param_env); - let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(type_scheme.ty), item.id); + let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(type_scheme.ty), id); f(self, &fcx); fcx.select_all_obligations_or_error(); - regionck::regionck_item(&fcx, item); + regionck::regionck_item(&fcx, id); } /// In a type definition, we check that to ensure that the types of the fields are well-formed. fn check_type_defn(&mut self, item: &ast::Item, mut lookup_fields: F) where F: for<'fcx> FnMut(&FnCtxt<'fcx, 'tcx>) -> Vec>, { - self.with_fcx(item, |this, fcx| { + self.with_fcx(item.span, item.id, |this, fcx| { let variants = lookup_fields(fcx); let mut bounds_checker = BoundsChecker::new(fcx, item.span, @@ -193,18 +193,17 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { }); } - fn check_item_type(&mut self, - item: &ast::Item) + fn check_item_type(&mut self, span: Span, id: ast::NodeId) { - self.with_fcx(item, |this, fcx| { + self.with_fcx(span, id, |this, fcx| { let mut bounds_checker = BoundsChecker::new(fcx, - item.span, - item.id, + span, + id, Some(&mut this.cache)); debug!("check_item_type at bounds_checker.scope: {:?}", bounds_checker.scope); - let type_scheme = ty::lookup_item_type(fcx.tcx(), local_def(item.id)); - let item_ty = fcx.instantiate_type_scheme(item.span, + let type_scheme = ty::lookup_item_type(fcx.tcx(), local_def(id)); + let item_ty = fcx.instantiate_type_scheme(span, &fcx.inh.param_env.free_substs, &type_scheme.ty); @@ -215,7 +214,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { fn check_impl(&mut self, item: &ast::Item) { - self.with_fcx(item, |this, fcx| { + self.with_fcx(item.span, item.id, |this, fcx| { let mut bounds_checker = BoundsChecker::new(fcx, item.span, item.id, @@ -426,11 +425,16 @@ fn reject_shadowing_type_parameters<'tcx>(tcx: &ty::ctxt<'tcx>, } impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> { - fn visit_item(&mut self, i: &ast::Item) { + fn visit_item(&mut self, i: &'v ast::Item) { self.check_item_well_formed(i); visit::walk_item(self, i); } + fn visit_foreign_item(&mut self, item: &'v ast::ForeignItem) { + self.check_item_type(item.span, item.id); + visit::walk_foreign_item(self, item); + } + fn visit_fn(&mut self, fk: visit::FnKind<'v>, fd: &'v ast::FnDecl, b: &'v ast::Block, span: Span, id: ast::NodeId) { diff --git a/src/test/compile-fail/issue-25637.rs b/src/test/compile-fail/issue-25637.rs new file mode 100644 index 0000000000000..99eea3154fb50 --- /dev/null +++ b/src/test/compile-fail/issue-25637.rs @@ -0,0 +1,22 @@ +// Copyright 2015 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. + +extern { + fn foo(x: Option); + //~^ ERROR the trait `core::marker::Sized` is not implemented + + fn foo1(x: &'static Option<[u8]>); + //~^ ERROR the trait `core::marker::Sized` is not implemented + + static FOO: &'static [[u16]]; + //~^ ERROR the trait `core::marker::Sized` is not implemented +} + +fn main() {} From 3923108d4997de0bf2b301f64f8030e40ef35ac4 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sat, 23 May 2015 16:53:45 +0300 Subject: [PATCH 3/4] Check associated types and consts for well-formedness Because we don't check the well-formedness of region relationships of an impl's on the Self-type, or infer region relationss from them, many impls now have to specify their region relations, making this a [breaking-change]. The most common pattern I found that is now broken is that impl<'a, T> IntoIterator for &'a Collection { type Item = &'a T; type IntoIter = ...; } now has to specify its `T: 'a` bound. --- src/libcollections/binary_heap.rs | 2 +- src/libcollections/btree/map.rs | 4 +- src/libcollections/btree/set.rs | 2 +- src/libcollections/enum_set.rs | 2 +- src/libcollections/linked_list.rs | 4 +- src/libcollections/vec.rs | 4 +- src/libcollections/vec_deque.rs | 4 +- src/libcollections/vec_map.rs | 4 +- src/libcore/array.rs | 4 +- src/libcore/slice.rs | 4 +- src/librustc/middle/subst.rs | 2 +- src/librustc/middle/traits/select.rs | 8 +- src/librustc/middle/ty.rs | 90 ++++++------- src/librustc_trans/trans/context.rs | 4 +- src/librustc_typeck/check/wf.rs | 123 ++++++++++++------ src/libstd/collections/hash/map.rs | 4 +- src/libstd/collections/hash/set.rs | 2 +- src/libstd/sync/mpsc/mod.rs | 2 +- src/test/compile-fail/wf-non-well-formed.rs | 15 +++ .../associated-types-nested-projections.rs | 2 +- 20 files changed, 165 insertions(+), 121 deletions(-) diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index af7112a5cb4e3..c012ba4f9fb83 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -675,7 +675,7 @@ impl IntoIterator for BinaryHeap { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> IntoIterator for &'a BinaryHeap where T: Ord { +impl<'a, T: 'a> IntoIterator for &'a BinaryHeap where T: Ord { type Item = &'a T; type IntoIter = Iter<'a, T>; diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index 11f16e2f400b4..de7868491331f 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -500,7 +500,7 @@ impl IntoIterator for BTreeMap { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V> IntoIterator for &'a BTreeMap { +impl<'a, K: 'a, V: 'a> IntoIterator for &'a BTreeMap { type Item = (&'a K, &'a V); type IntoIter = Iter<'a, K, V>; @@ -510,7 +510,7 @@ impl<'a, K, V> IntoIterator for &'a BTreeMap { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V> IntoIterator for &'a mut BTreeMap { +impl<'a, K: 'a, V: 'a> IntoIterator for &'a mut BTreeMap { type Item = (&'a K, &'a mut V); type IntoIter = IterMut<'a, K, V>; diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index a3b9320e2b521..0042234108b2c 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -490,7 +490,7 @@ impl IntoIterator for BTreeSet { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> IntoIterator for &'a BTreeSet { +impl<'a, T: 'a> IntoIterator for &'a BTreeSet { type Item = &'a T; type IntoIter = Iter<'a, T>; diff --git a/src/libcollections/enum_set.rs b/src/libcollections/enum_set.rs index e6cdb88d3e174..66a7ba1a77933 100644 --- a/src/libcollections/enum_set.rs +++ b/src/libcollections/enum_set.rs @@ -272,7 +272,7 @@ impl FromIterator for EnumSet { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, E> IntoIterator for &'a EnumSet where E: CLike { +impl<'a, E: 'a> IntoIterator for &'a EnumSet where E: CLike { type Item = E; type IntoIter = Iter; diff --git a/src/libcollections/linked_list.rs b/src/libcollections/linked_list.rs index 61ebf7f6df91c..4af94c326d9f4 100644 --- a/src/libcollections/linked_list.rs +++ b/src/libcollections/linked_list.rs @@ -846,7 +846,7 @@ impl IntoIterator for LinkedList { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> IntoIterator for &'a LinkedList { +impl<'a, T: 'a> IntoIterator for &'a LinkedList { type Item = &'a T; type IntoIter = Iter<'a, T>; @@ -855,7 +855,7 @@ impl<'a, T> IntoIterator for &'a LinkedList { } } -impl<'a, T> IntoIterator for &'a mut LinkedList { +impl<'a, T: 'a> IntoIterator for &'a mut LinkedList { type Item = &'a mut T; type IntoIter = IterMut<'a, T>; diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 5ec71b7353c3e..ac18a444b4c1f 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1562,7 +1562,7 @@ impl IntoIterator for Vec { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> IntoIterator for &'a Vec { +impl<'a, T: 'a> IntoIterator for &'a Vec { type Item = &'a T; type IntoIter = slice::Iter<'a, T>; @@ -1572,7 +1572,7 @@ impl<'a, T> IntoIterator for &'a Vec { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> IntoIterator for &'a mut Vec { +impl<'a, T: 'a> IntoIterator for &'a mut Vec { type Item = &'a mut T; type IntoIter = slice::IterMut<'a, T>; diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index 80bbe4681e728..6c44837ddf650 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -1757,7 +1757,7 @@ impl IntoIterator for VecDeque { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> IntoIterator for &'a VecDeque { +impl<'a, T: 'a> IntoIterator for &'a VecDeque { type Item = &'a T; type IntoIter = Iter<'a, T>; @@ -1767,7 +1767,7 @@ impl<'a, T> IntoIterator for &'a VecDeque { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> IntoIterator for &'a mut VecDeque { +impl<'a, T: 'a> IntoIterator for &'a mut VecDeque { type Item = &'a mut T; type IntoIter = IterMut<'a, T>; diff --git a/src/libcollections/vec_map.rs b/src/libcollections/vec_map.rs index aa0ab41b7455b..7a3d76f0aabcb 100644 --- a/src/libcollections/vec_map.rs +++ b/src/libcollections/vec_map.rs @@ -800,7 +800,7 @@ impl IntoIterator for VecMap { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> IntoIterator for &'a VecMap { +impl<'a, T: 'a> IntoIterator for &'a VecMap { type Item = (usize, &'a T); type IntoIter = Iter<'a, T>; @@ -810,7 +810,7 @@ impl<'a, T> IntoIterator for &'a VecMap { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> IntoIterator for &'a mut VecMap { +impl<'a, T: 'a> IntoIterator for &'a mut VecMap { type Item = (usize, &'a mut T); type IntoIter = IterMut<'a, T>; diff --git a/src/libcore/array.rs b/src/libcore/array.rs index 91301ee558ca5..1742d8dad6311 100644 --- a/src/libcore/array.rs +++ b/src/libcore/array.rs @@ -94,7 +94,7 @@ macro_rules! array_impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, T> IntoIterator for &'a [T; $N] { + impl<'a, T: 'a> IntoIterator for &'a [T; $N] { type Item = &'a T; type IntoIter = Iter<'a, T>; @@ -104,7 +104,7 @@ macro_rules! array_impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, T> IntoIterator for &'a mut [T; $N] { + impl<'a, T: 'a> IntoIterator for &'a mut [T; $N] { type Item = &'a mut T; type IntoIter = IterMut<'a, T>; diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index cbac70921b7ee..ca2bd82dcd58d 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -647,7 +647,7 @@ impl<'a, T> Default for &'a [T] { // #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> IntoIterator for &'a [T] { +impl<'a, T: 'a> IntoIterator for &'a [T] { type Item = &'a T; type IntoIter = Iter<'a, T>; @@ -657,7 +657,7 @@ impl<'a, T> IntoIterator for &'a [T] { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> IntoIterator for &'a mut [T] { +impl<'a, T: 'a> IntoIterator for &'a mut [T] { type Item = &'a mut T; type IntoIter = IterMut<'a, T>; diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index 500255db330c5..9a958a29b49b0 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -538,7 +538,7 @@ impl IntoIterator for VecPerParamSpace { } } -impl<'a,T> IntoIterator for &'a VecPerParamSpace { +impl<'a, T: 'a> IntoIterator for &'a VecPerParamSpace { type Item = &'a T; type IntoIter = Iter<'a, T>; diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 8011d29626315..f4ba188b84446 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -2982,10 +2982,10 @@ impl<'o,'tcx> TraitObligationStackList<'o,'tcx> { } } -impl<'o,'tcx> Iterator for TraitObligationStackList<'o,'tcx>{ - type Item = &'o TraitObligationStack<'o,'tcx>; +impl<'o, 'tcx: 'o> Iterator for TraitObligationStackList<'o, 'tcx> { + type Item = &'o TraitObligationStack<'o, 'tcx>; - fn next(&mut self) -> Option<&'o TraitObligationStack<'o,'tcx>> { + fn next(&mut self) -> Option<&'o TraitObligationStack<'o, 'tcx>> { match self.head { Some(o) => { *self = o.previous; @@ -2996,7 +2996,7 @@ impl<'o,'tcx> Iterator for TraitObligationStackList<'o,'tcx>{ } } -impl<'o,'tcx> Repr<'tcx> for TraitObligationStack<'o,'tcx> { +impl<'o, 'tcx> Repr<'tcx> for TraitObligationStack<'o, 'tcx> { fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { format!("TraitObligationStack({})", self.obligation.repr(tcx)) diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 15e1ac2f2c65e..6e0cb1b54b114 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -2328,7 +2328,16 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { } } - pub fn for_item(cx: &'a ctxt<'tcx>, id: NodeId) -> ParameterEnvironment<'a, 'tcx> { + pub fn for_item(cx: &'a ctxt<'tcx>, id: NodeId) + -> ParameterEnvironment<'a, 'tcx> + { + // TODO: use Self after a snapshot (or remove this comment) + ParameterEnvironment::for_item_inner(cx, id, construct_parameter_environment) + } + + pub fn for_item_inner(cx: &'a ctxt<'tcx>, id: NodeId, f: F) -> T + where F: FnOnce(&'a ctxt<'tcx>, Span, &Generics<'tcx>, + &GenericPredicates<'tcx>, NodeId) -> T { match cx.map.find(id) { Some(ast_map::NodeImplItem(ref impl_item)) => { match impl_item.node { @@ -2336,30 +2345,18 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { let def_id = ast_util::local_def(id); let scheme = lookup_item_type(cx, def_id); let predicates = lookup_predicates(cx, def_id); - construct_parameter_environment(cx, - impl_item.span, - &scheme.generics, - &predicates, - id) + f(cx, impl_item.span, &scheme.generics, &predicates, id) } ast::MethodImplItem(_, ref body) => { let method_def_id = ast_util::local_def(id); match ty::impl_or_trait_item(cx, method_def_id) { - MethodTraitItem(ref method_ty) => { - let method_generics = &method_ty.generics; - let method_bounds = &method_ty.predicates; - construct_parameter_environment( - cx, - impl_item.span, - method_generics, - method_bounds, - body.id) - } - _ => { - cx.sess - .bug("ParameterEnvironment::for_item(): \ - got non-method item from impl method?!") - } + MethodTraitItem(ref method_ty) => f(cx, + impl_item.span, + &method_ty.generics, + &method_ty.predicates, + body.id), + _ => cx.sess.bug("ParameterEnvironment::for_item(): \ + got non-method item from impl method?!") } } ast::TypeImplItem(_) => { @@ -2378,11 +2375,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { let def_id = ast_util::local_def(id); let scheme = lookup_item_type(cx, def_id); let predicates = lookup_predicates(cx, def_id); - construct_parameter_environment(cx, - trait_item.span, - &scheme.generics, - &predicates, - id) + f(cx, trait_item.span, &scheme.generics, &predicates, id) } None => { cx.sess.bug("ParameterEnvironment::from_item(): \ @@ -2401,22 +2394,14 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { ast::MethodTraitItem(_, Some(ref body)) => { let method_def_id = ast_util::local_def(id); match ty::impl_or_trait_item(cx, method_def_id) { - MethodTraitItem(ref method_ty) => { - let method_generics = &method_ty.generics; - let method_bounds = &method_ty.predicates; - construct_parameter_environment( - cx, - trait_item.span, - method_generics, - method_bounds, - body.id) - } - _ => { - cx.sess - .bug("ParameterEnvironment::for_item(): \ - got non-method item from provided \ - method?!") - } + MethodTraitItem(ref method_ty) => f(cx, + trait_item.span, + &method_ty.generics, + &method_ty.predicates, + body.id), + _ => cx.sess.bug("ParameterEnvironment::for_item(): \ + got non-method item from provided \ + method?!") } } ast::TypeTraitItem(..) => { @@ -2434,11 +2419,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { let fn_scheme = lookup_item_type(cx, fn_def_id); let fn_predicates = lookup_predicates(cx, fn_def_id); - construct_parameter_environment(cx, - item.span, - &fn_scheme.generics, - &fn_predicates, - body.id) + f(cx, item.span, &fn_scheme.generics, &fn_predicates, body.id) } ast::ItemEnum(..) | ast::ItemStruct(..) | @@ -2448,11 +2429,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { let def_id = ast_util::local_def(id); let scheme = lookup_item_type(cx, def_id); let predicates = lookup_predicates(cx, def_id); - construct_parameter_environment(cx, - item.span, - &scheme.generics, - &predicates, - id) + f(cx, item.span, &scheme.generics, &predicates, id) } _ => { cx.sess.span_bug(item.span, @@ -2464,7 +2441,14 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { } Some(ast_map::NodeExpr(..)) => { // This is a convenience to allow closures to work. - ParameterEnvironment::for_item(cx, cx.map.get_parent(id)) + ParameterEnvironment::for_item_inner(cx, cx.map.get_parent(id), f) + } + Some(ast_map::NodeForeignItem(ref item)) => { + let def_id = ast_util::local_def(id); + let scheme = lookup_item_type(cx, def_id); + let predicates = lookup_predicates(cx, def_id); + + f(cx, item.span, &scheme.generics, &predicates, id) } _ => { cx.sess.bug(&format!("ParameterEnvironment::from_item(): \ diff --git a/src/librustc_trans/trans/context.rs b/src/librustc_trans/trans/context.rs index 51db0adf5b775..678975c1e2b40 100644 --- a/src/librustc_trans/trans/context.rs +++ b/src/librustc_trans/trans/context.rs @@ -171,7 +171,7 @@ pub struct CrateContextIterator<'a, 'tcx: 'a> { index: usize, } -impl<'a, 'tcx> Iterator for CrateContextIterator<'a,'tcx> { +impl<'a, 'tcx: 'a> Iterator for CrateContextIterator<'a, 'tcx> { type Item = CrateContext<'a, 'tcx>; fn next(&mut self) -> Option> { @@ -198,7 +198,7 @@ pub struct CrateContextMaybeIterator<'a, 'tcx: 'a> { origin: usize, } -impl<'a, 'tcx> Iterator for CrateContextMaybeIterator<'a, 'tcx> { +impl<'a, 'tcx: 'a> Iterator for CrateContextMaybeIterator<'a, 'tcx> { type Item = (CrateContext<'a, 'tcx>, bool); fn next(&mut self) -> Option<(CrateContext<'a, 'tcx>, bool)> { diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index 45bd4ea088551..315e4775b004b 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -24,6 +24,7 @@ use syntax::ast; use syntax::ast_util::local_def; use syntax::codemap::Span; use syntax::parse::token::{self, special_idents}; +use syntax::ptr::P; use syntax::visit; use syntax::visit::Visitor; @@ -76,8 +77,8 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { /// /// won't be allowed unless there's an *explicit* implementation of `Send` /// for `T` - ast::ItemImpl(_, ast::ImplPolarity::Positive, _, _, _, _) => { - self.check_impl(item); + ast::ItemImpl(_, ast::ImplPolarity::Positive, _, _, _, ref items) => { + self.check_impl(item, &items); } ast::ItemImpl(_, ast::ImplPolarity::Negative, _, Some(_), _, _) => { let trait_ref = ty::impl_id_to_trait_ref(ccx.tcx, item.id); @@ -117,9 +118,6 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { self.check_variances_for_type_defn(item, ast_generics); } ast::ItemTrait(_, _, _, ref items) => { - let trait_predicates = - ty::lookup_predicates(ccx.tcx, local_def(item.id)); - reject_non_type_param_bounds(ccx.tcx, item.span, &trait_predicates); if ty::trait_has_default_impl(ccx.tcx, local_def(item.id)) { if !items.is_empty() { ccx.tcx.sess.span_err( @@ -128,28 +126,74 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { have no methods or associated items") } } + + let def = ty::lookup_trait_def(self.ccx.tcx, local_def(item.id)); + let predicates = ty::lookup_predicates(self.ccx.tcx, local_def(item.id)); + let env = ty::construct_parameter_environment(self.ccx.tcx, + item.span, + &def.generics, + &predicates, + item.id); + reject_non_type_param_bounds(self.ccx.tcx, item.span, &predicates); + + self.with_fcx_inner(item.span, item.id, env, |fcx, bounds_checker| { + for ast_item in items { + bounds_checker.span = ast_item.span; + match ty::impl_or_trait_item(fcx.tcx(), local_def(ast_item.id)) { + ty::ConstTraitItem(c) => { + let cty = fcx.instantiate_type_scheme( + item.span, + &fcx.param_env().free_substs, + &c.ty + ); + bounds_checker.check_ty(cty); + } + ty::MethodTraitItem(_) => { + /* these are checked by visit_impl_item */ + } + ty::TypeTraitItem(_) => { + /* default associated types don't do anything + * yet. + * FIXME: when we *do* implement them, + * we need to also wf-check them. + */ + } + } + } + }); } _ => {} } } - fn with_fcx(&mut self, span: Span, id: ast::NodeId, mut f: F) where - F: for<'fcx> FnMut(&mut CheckTypeWellFormedVisitor<'ccx, 'tcx>, &FnCtxt<'fcx, 'tcx>), + fn with_fcx(&mut self, span: Span, id: ast::NodeId, f: F) + where F: for<'fcx> FnOnce(&FnCtxt<'fcx, 'tcx>, &mut BoundsChecker<'fcx, 'tcx>) + { + let param_env = ty::ParameterEnvironment::for_item_inner( + self.ccx.tcx, + id, + |tcx, _span, generics, predicates, _id| { + reject_non_type_param_bounds(tcx, span, &predicates); + ty::construct_parameter_environment(tcx, span, generics, predicates, id) + } + ); + + self.with_fcx_inner(span, id, param_env, f) + } + + fn with_fcx_inner<'ecx, F>(&mut self, + span: Span, + id: ast::NodeId, + param_env: ty::ParameterEnvironment<'ecx, 'tcx>, + f: F) where + F: for<'fcx> FnOnce(&FnCtxt<'fcx, 'tcx>, &mut BoundsChecker<'fcx, 'tcx>) { let ccx = self.ccx; - let item_def_id = local_def(id); - let type_scheme = ty::lookup_item_type(ccx.tcx, item_def_id); - let type_predicates = ty::lookup_predicates(ccx.tcx, item_def_id); - reject_non_type_param_bounds(ccx.tcx, span, &type_predicates); - let param_env = - ty::construct_parameter_environment(ccx.tcx, - span, - &type_scheme.generics, - &type_predicates, - id); let inh = Inherited::new(ccx.tcx, param_env); - let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(type_scheme.ty), id); - f(self, &fcx); + let fcx = blank_fn_ctxt(ccx, &inh, ty::FnDiverging, id); + let mut bounds_checker = BoundsChecker::new(&fcx, span, id, + Some(&mut self.cache)); + f(&fcx, &mut bounds_checker); fcx.select_all_obligations_or_error(); regionck::regionck_item(&fcx, id); } @@ -158,12 +202,8 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { fn check_type_defn(&mut self, item: &ast::Item, mut lookup_fields: F) where F: for<'fcx> FnMut(&FnCtxt<'fcx, 'tcx>) -> Vec>, { - self.with_fcx(item.span, item.id, |this, fcx| { + self.with_fcx(item.span, item.id, |fcx, bounds_checker| { let variants = lookup_fields(fcx); - let mut bounds_checker = BoundsChecker::new(fcx, - item.span, - item.id, - Some(&mut this.cache)); debug!("check_type_defn at bounds_checker.scope: {:?}", bounds_checker.scope); for variant in &variants { @@ -195,11 +235,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { fn check_item_type(&mut self, span: Span, id: ast::NodeId) { - self.with_fcx(span, id, |this, fcx| { - let mut bounds_checker = BoundsChecker::new(fcx, - span, - id, - Some(&mut this.cache)); + self.with_fcx(span, id, |fcx, bounds_checker| { debug!("check_item_type at bounds_checker.scope: {:?}", bounds_checker.scope); let type_scheme = ty::lookup_item_type(fcx.tcx(), local_def(id)); @@ -212,13 +248,10 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { } fn check_impl(&mut self, - item: &ast::Item) + item: &ast::Item, + impl_items: &[P]) { - self.with_fcx(item.span, item.id, |this, fcx| { - let mut bounds_checker = BoundsChecker::new(fcx, - item.span, - item.id, - Some(&mut this.cache)); + self.with_fcx(item.span, item.id, |fcx, bounds_checker| { debug!("check_impl at bounds_checker.scope: {:?}", bounds_checker.scope); // Find the impl self type as seen from the "inside" -- @@ -272,6 +305,22 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { for obligation in predicates.obligations { fcx.register_predicate(obligation); } + + for ast_item in impl_items { + bounds_checker.span = ast_item.span; + match ty::impl_or_trait_item(fcx.tcx(), local_def(ast_item.id)) { + ty::ConstTraitItem(_) => { /* these are checked by the trait */ } + ty::MethodTraitItem(_) => { /* these are checked by visit_impl_item */ } + ty::TypeTraitItem(at) => { + let assoc = fcx.instantiate_type_scheme( + item.span, + &fcx.param_env().free_substs, + &ty::lookup_item_type(fcx.tcx(), at.def_id).ty + ); + bounds_checker.check_ty(assoc); + } + } + } }); } @@ -642,10 +691,6 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> { // // (I believe we should do the same for traits, but // that will require an RFC. -nmatsakis) - // - // TODO(arielb1): this also seems to be triggered - // when you have something like - // for<'a> Trait<&'a (), &'free1 &'free2 ()> let bounds = filter_to_trait_obligations(bounds); self.fcx.add_obligations_for_parameters( self.cause(traits::ItemObligation(type_id)), diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 093218c6e4c59..4818f6d08006c 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1350,7 +1350,7 @@ enum VacantEntryState { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V, S> IntoIterator for &'a HashMap +impl<'a, K: 'a, V: 'a, S> IntoIterator for &'a HashMap where K: Eq + Hash, S: HashState { type Item = (&'a K, &'a V); @@ -1362,7 +1362,7 @@ impl<'a, K, V, S> IntoIterator for &'a HashMap } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V, S> IntoIterator for &'a mut HashMap +impl<'a, K: 'a, V: 'a, S> IntoIterator for &'a mut HashMap where K: Eq + Hash, S: HashState { type Item = (&'a K, &'a mut V); diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index 44fc0f7016d8e..a763fabff2c93 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -803,7 +803,7 @@ pub struct Union<'a, T: 'a, S: 'a> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, S> IntoIterator for &'a HashSet +impl<'a, T: 'a, S: 'a> IntoIterator for &'a HashSet where T: Eq + Hash, S: HashState { type Item = &'a T; diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 77aeeca796809..ac0691f6f91c6 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -907,7 +907,7 @@ impl<'a, T> Iterator for Iter<'a, T> { } #[stable(feature = "receiver_into_iter", since = "1.1.0")] -impl<'a, T> IntoIterator for &'a Receiver { +impl<'a, T: 'a> IntoIterator for &'a Receiver { type Item = T; type IntoIter = Iter<'a, T>; diff --git a/src/test/compile-fail/wf-non-well-formed.rs b/src/test/compile-fail/wf-non-well-formed.rs index 43b2917a10392..756a081569e55 100644 --- a/src/test/compile-fail/wf-non-well-formed.rs +++ b/src/test/compile-fail/wf-non-well-formed.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(associated_consts)] + // Check that we catch attempts to create non-well-formed types trait Tr {} @@ -39,3 +41,16 @@ fn b7() -> &'static (u32,[u8],u32) {} //~^ ERROR the trait `core::marker::Sized` is not implemented fn main() {} + +trait TrBogus { + type T = &'static [[u32]]; + //^^ Associated type defaults don't work yet + + const X1: &'static [[u16]]; + //~^ ERROR the trait `core::marker::Sized` is not implemented +} + +impl Iterator for S { + type Item = ([u8], T); + //~^ ERROR the trait `core::marker::Sized` is not implemented +} diff --git a/src/test/run-pass/associated-types-nested-projections.rs b/src/test/run-pass/associated-types-nested-projections.rs index 83f0d360e6122..fa55673446a39 100644 --- a/src/test/run-pass/associated-types-nested-projections.rs +++ b/src/test/run-pass/associated-types-nested-projections.rs @@ -26,7 +26,7 @@ trait IntoIterator { fn into_iter(self) -> Self::Iter; } -impl<'a, T> IntoIterator for &'a [T; 3] { +impl<'a, T: 'a> IntoIterator for &'a [T; 3] { type Iter = slice::Iter<'a, T>; fn into_iter(self) -> slice::Iter<'a, T> { From 9d2b640ecb0b0e31fcb85b5a27c93ab476eefb61 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sun, 24 May 2015 01:23:06 +0300 Subject: [PATCH 4/4] Make default associated types not parse They don't do anything ATM. This is a [breaking-change] --- src/libcore/ops.rs | 2 +- src/librustc_typeck/collect.rs | 2 +- src/librustdoc/clean/mod.rs | 4 ++-- src/libsyntax/ast.rs | 2 +- src/libsyntax/fold.rs | 5 ++--- src/libsyntax/parse/parser.rs | 6 +++++- src/libsyntax/print/pprust.rs | 5 ++--- src/libsyntax/visit.rs | 3 +-- src/test/auxiliary/lang-item-public.rs | 2 +- src/test/compile-fail/issue-22673.rs | 2 +- src/test/compile-fail/lint-missing-doc.rs | 3 --- src/test/compile-fail/wf-non-well-formed.rs | 3 --- .../parse-fail/associated-types-defaults.rs | 19 +++++++++++++++++++ 13 files changed, 36 insertions(+), 22 deletions(-) create mode 100644 src/test/parse-fail/associated-types-defaults.rs diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index f16614cfd092d..40cb448296c46 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -405,7 +405,7 @@ div_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } pub trait Rem { /// The resulting type after applying the `%` operator #[stable(feature = "rust1", since = "1.0.0")] - type Output = Self; + type Output; /// The method for the `%` operator #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 014991f7ea560..7429eb5fa85b8 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1376,7 +1376,7 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) { trait_items.iter().flat_map(|trait_item| { let bounds = match trait_item.node { - ast::TypeTraitItem(ref bounds, _) => bounds, + ast::TypeTraitItem(ref bounds) => bounds, _ => { return vec!().into_iter(); } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 4c2357f8a8f0d..0fcecfb6ed084 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1247,8 +1247,8 @@ impl Clean for ast::TraitItem { ast::MethodTraitItem(ref sig, None) => { TyMethodItem(sig.clean(cx)) } - ast::TypeTraitItem(ref bounds, ref default) => { - AssociatedTypeItem(bounds.clean(cx), default.clean(cx)) + ast::TypeTraitItem(ref bounds) => { + AssociatedTypeItem(bounds.clean(cx), None) } }; Item { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index e00cb82649b7b..938454e55d6ba 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1238,7 +1238,7 @@ pub struct TraitItem { pub enum TraitItem_ { ConstTraitItem(P, Option>), MethodTraitItem(MethodSig, Option>), - TypeTraitItem(TyParamBounds, Option>), + TypeTraitItem(TyParamBounds), } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 4bf15f509a048..48bbfd26ddef9 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -991,9 +991,8 @@ pub fn noop_fold_trait_item(i: P, folder: &mut T) MethodTraitItem(noop_fold_method_sig(sig, folder), body.map(|x| folder.fold_block(x))) } - TypeTraitItem(bounds, default) => { - TypeTraitItem(folder.fold_bounds(bounds), - default.map(|x| folder.fold_ty(x))) + TypeTraitItem(bounds) => { + TypeTraitItem(folder.fold_bounds(bounds)) } }, span: folder.new_span(span) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 2b6f91bbc993a..09c579945681c 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1158,8 +1158,12 @@ impl<'a> Parser<'a> { let (name, node) = if try!(p.eat_keyword(keywords::Type)) { let TyParam {ident, bounds, default, ..} = try!(p.parse_ty_param()); + if let Some(dty) = default { + p.span_err(dty.span, + "defaults are not supported in associated types"); + } try!(p.expect(&token::Semi)); - (ident, TypeTraitItem(bounds, default)) + (ident, TypeTraitItem(bounds)) } else if try!(p.eat_keyword(keywords::Const)) { let ident = try!(p.parse_ident()); try!(p.expect(&token::Colon)); diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index b71d65a8fb0c5..9e169ebbc424b 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1272,9 +1272,8 @@ impl<'a> State<'a> { try!(word(&mut self.s, ";")); } } - ast::TypeTraitItem(ref bounds, ref default) => { - try!(self.print_associated_type(ti.ident, Some(bounds), - default.as_ref().map(|ty| &**ty))); + ast::TypeTraitItem(ref bounds) => { + try!(self.print_associated_type(ti.ident, Some(bounds), None)) } } self.ann.post(self, NodeSubItem(ti.id)) diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 6cf791b10be67..c948c22500985 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -638,9 +638,8 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai visitor.visit_fn(FkMethod(trait_item.ident, sig, None), &sig.decl, body, trait_item.span, trait_item.id); } - TypeTraitItem(ref bounds, ref default) => { + TypeTraitItem(ref bounds) => { walk_ty_param_bounds_helper(visitor, bounds); - walk_ty_opt(visitor, default); } } } diff --git a/src/test/auxiliary/lang-item-public.rs b/src/test/auxiliary/lang-item-public.rs index d195bd7e77bd8..8f579bd032c75 100644 --- a/src/test/auxiliary/lang-item-public.rs +++ b/src/test/auxiliary/lang-item-public.rs @@ -31,7 +31,7 @@ pub trait Copy { #[lang="rem"] pub trait Rem { - type Output = Self; + type Output; fn rem(self, rhs: RHS) -> Self::Output; } diff --git a/src/test/compile-fail/issue-22673.rs b/src/test/compile-fail/issue-22673.rs index 6983d1f0706a0..442e6bcda5a09 100644 --- a/src/test/compile-fail/issue-22673.rs +++ b/src/test/compile-fail/issue-22673.rs @@ -10,7 +10,7 @@ trait Expr : PartialEq { //~^ ERROR: unsupported cyclic reference between types/traits detected - type Item = Expr; + type Item; } fn main() {} diff --git a/src/test/compile-fail/lint-missing-doc.rs b/src/test/compile-fail/lint-missing-doc.rs index 04db6c8c8f39c..d74627206ef71 100644 --- a/src/test/compile-fail/lint-missing-doc.rs +++ b/src/test/compile-fail/lint-missing-doc.rs @@ -71,13 +71,10 @@ pub trait D { /// dox pub trait E { type AssociatedType; //~ ERROR: missing documentation for an associated type - type AssociatedTypeDef = Self; //~ ERROR: missing documentation for an associated type /// dox type DocumentedType; /// dox - type DocumentedTypeDef = Self; - /// dox fn dummy(&self) {} } diff --git a/src/test/compile-fail/wf-non-well-formed.rs b/src/test/compile-fail/wf-non-well-formed.rs index 756a081569e55..e11e76353b243 100644 --- a/src/test/compile-fail/wf-non-well-formed.rs +++ b/src/test/compile-fail/wf-non-well-formed.rs @@ -43,9 +43,6 @@ fn b7() -> &'static (u32,[u8],u32) fn main() {} trait TrBogus { - type T = &'static [[u32]]; - //^^ Associated type defaults don't work yet - const X1: &'static [[u16]]; //~^ ERROR the trait `core::marker::Sized` is not implemented } diff --git a/src/test/parse-fail/associated-types-defaults.rs b/src/test/parse-fail/associated-types-defaults.rs new file mode 100644 index 0000000000000..d14b276457f49 --- /dev/null +++ b/src/test/parse-fail/associated-types-defaults.rs @@ -0,0 +1,19 @@ +// Copyright 2015 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. + +// compile-flags: -Z parse-only + +// Replace this with a real test-of-functionality when we implement +// default associated types. + +trait Foo { + type Assoc = [u8]; + //~^ ERROR defaults are not supported in associated types +}