diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 9c00b8adfa3..5831ab850d3 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -3507,8 +3507,9 @@ impl<'a> Resolver<'a> { // its scope. self.resolve_error(span, - "attempt to use a type \ - argument out of scope"); + "can't use type parameters from \ + outer function; try using a local \ + type parameter instead"); } return None; @@ -3530,8 +3531,9 @@ impl<'a> Resolver<'a> { // its scope. self.resolve_error(span, - "attempt to use a type \ - argument out of scope"); + "can't use type parameters from \ + outer function; try using a local \ + type parameter instead"); } return None; diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index 7500c23e006..c9539b1d9a3 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -95,8 +95,9 @@ impl<'a> TypeFolder for SubstFolder<'a> { root.repr(self.tcx)), None => ~"" }; - let m = format!("missing type param `{}`{}", - t.repr(self.tcx), root_msg); + let m = format!("can't use type parameters from outer \ + function{}; try using a local type \ + parameter instead", root_msg); match self.span { Some(span) => self.tcx.sess.span_err(span, m), None => self.tcx.sess.err(m) diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 9c0c2d484a0..bc01d2b126d 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -2416,13 +2416,13 @@ pub enum Representability { /// Check whether a type is representable. This means it cannot contain unboxed /// structural recursion. This check is needed for structs and enums. -pub fn is_type_representable(cx: &ctxt, ty: t) -> Representability { +pub fn is_type_representable(cx: &ctxt, sp: Span, ty: t) -> Representability { // Iterate until something non-representable is found - fn find_nonrepresentable>(cx: &ctxt, seen: &mut Vec, + fn find_nonrepresentable>(cx: &ctxt, sp: Span, seen: &mut Vec, mut iter: It) -> Representability { for ty in iter { - let r = type_structurally_recursive(cx, seen, ty); + let r = type_structurally_recursive(cx, sp, seen, ty); if r != Representable { return r } @@ -2432,7 +2432,7 @@ pub fn is_type_representable(cx: &ctxt, ty: t) -> Representability { // Does the type `ty` directly (without indirection through a pointer) // contain any types on stack `seen`? - fn type_structurally_recursive(cx: &ctxt, seen: &mut Vec, + fn type_structurally_recursive(cx: &ctxt, sp: Span, seen: &mut Vec, ty: t) -> Representability { debug!("type_structurally_recursive: {}", ::util::ppaux::ty_to_str(cx, ty)); @@ -2455,19 +2455,19 @@ pub fn is_type_representable(cx: &ctxt, ty: t) -> Representability { match get(ty).sty { // Tuples ty_tup(ref ts) => { - find_nonrepresentable(cx, seen, ts.iter().map(|t| *t)) + find_nonrepresentable(cx, sp, seen, ts.iter().map(|t| *t)) } // Fixed-length vectors. // FIXME(#11924) Behavior undecided for zero-length vectors. ty_vec(ty, VstoreFixed(_)) => { - type_structurally_recursive(cx, seen, ty) + type_structurally_recursive(cx, sp, seen, ty) } // Push struct and enum def-ids onto `seen` before recursing. ty_struct(did, ref substs) => { seen.push(did); let fields = struct_fields(cx, did, substs); - let r = find_nonrepresentable(cx, seen, + let r = find_nonrepresentable(cx, sp, seen, fields.iter().map(|f| f.mt.ty)); seen.pop(); r @@ -2478,8 +2478,10 @@ pub fn is_type_representable(cx: &ctxt, ty: t) -> Representability { let mut r = Representable; for variant in vs.iter() { - let iter = variant.args.iter().map(|aty| subst(cx, substs, *aty)); - r = find_nonrepresentable(cx, seen, iter); + let iter = variant.args.iter().map(|aty| { + aty.subst_spanned(cx, substs, Some(sp)) + }); + r = find_nonrepresentable(cx, sp, seen, iter); if r != Representable { break } } @@ -2499,7 +2501,7 @@ pub fn is_type_representable(cx: &ctxt, ty: t) -> Representability { // contains a different, structurally recursive type, maintain a stack // of seen types and check recursion for each of them (issues #3008, #3779). let mut seen: Vec = Vec::new(); - type_structurally_recursive(cx, &mut seen, ty) + type_structurally_recursive(cx, sp, &mut seen, ty) } pub fn type_is_trait(ty: t) -> bool { diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index cff8c149bb6..6770640cfac 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -3356,7 +3356,7 @@ pub fn check_representable(tcx: &ty::ctxt, // recursive type. It is only necessary to throw an error on those that // contain themselves. For case 2, there must be an inner type that will be // caught by case 1. - match ty::is_type_representable(tcx, rty) { + match ty::is_type_representable(tcx, sp, rty) { ty::SelfRecursive => { tcx.sess.span_err( sp, format!("illegal recursive {} type; \ diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 7e53445147f..6df8da3edaa 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -945,7 +945,24 @@ pub fn ty_generics(ccx: &CrateCtxt, let param_ty = ty::param_ty {idx: base_index + offset, def_id: local_def(param.id)}; let bounds = @compute_bounds(ccx, param_ty, ¶m.bounds); - let default = param.default.map(|x| ast_ty_to_ty(ccx, &ExplicitRscope, x)); + let default = param.default.map(|path| { + let ty = ast_ty_to_ty(ccx, &ExplicitRscope, path); + let cur_idx = param_ty.idx; + + ty::walk_ty(ty, |t| { + match ty::get(t).sty { + ty::ty_param(p) => if p.idx > cur_idx { + ccx.tcx.sess.span_err(path.span, + "type parameters with a default cannot use \ + forward declared identifiers") + }, + _ => {} + } + }); + + ty + }); + let def = ty::TypeParameterDef { ident: param.ident, def_id: local_def(param.id), diff --git a/src/test/compile-fail/bad-type-env-capture.rs b/src/test/compile-fail/bad-type-env-capture.rs index f03665febd2..4e5dc652fb5 100644 --- a/src/test/compile-fail/bad-type-env-capture.rs +++ b/src/test/compile-fail/bad-type-env-capture.rs @@ -9,7 +9,7 @@ // except according to those terms. fn foo() { - fn bar(b: T) { } //~ ERROR attempt to use a type argument out of scope + fn bar(b: T) { } //~ ERROR can't use type parameters from outer //~^ ERROR use of undeclared type name } fn main() { } diff --git a/src/test/compile-fail/generic-type-params-forward-mention.rs b/src/test/compile-fail/generic-type-params-forward-mention.rs index 424a92d74ee..ace53fb51a4 100644 --- a/src/test/compile-fail/generic-type-params-forward-mention.rs +++ b/src/test/compile-fail/generic-type-params-forward-mention.rs @@ -12,8 +12,7 @@ // Ensure that we get an error and not an ICE for this problematic case. struct Foo, U = bool>; - +//~^ ERROR type parameters with a default cannot use forward declared identifiers fn main() { let x: Foo; - //~^ ERROR missing type param `U` in the substitution of `std::option::Option` } diff --git a/src/test/compile-fail/issue-3021-c.rs b/src/test/compile-fail/issue-3021-c.rs index 1fb71f01d06..5b3e343deea 100644 --- a/src/test/compile-fail/issue-3021-c.rs +++ b/src/test/compile-fail/issue-3021-c.rs @@ -11,8 +11,8 @@ fn siphash() { trait t { - fn g(&self, x: T) -> T; //~ ERROR attempt to use a type argument out of scope - //~^ ERROR attempt to use a type argument out of scope + fn g(&self, x: T) -> T; //~ ERROR can't use type parameters from outer function; try using + //~^ ERROR can't use type parameters from outer function; try using //~^^ ERROR use of undeclared type name `T` //~^^^ ERROR use of undeclared type name `T` } diff --git a/src/test/compile-fail/issue-3214.rs b/src/test/compile-fail/issue-3214.rs index 5be0a1e708b..be49ca1fe06 100644 --- a/src/test/compile-fail/issue-3214.rs +++ b/src/test/compile-fail/issue-3214.rs @@ -10,7 +10,7 @@ fn foo() { struct foo { - x: T, //~ ERROR attempt to use a type argument out of scope + x: T, //~ ERROR can't use type parameters from outer function; //~^ ERROR use of undeclared type name } diff --git a/src/test/compile-fail/issue-5997-enum.rs b/src/test/compile-fail/issue-5997-enum.rs new file mode 100644 index 00000000000..7be01b4abb4 --- /dev/null +++ b/src/test/compile-fail/issue-5997-enum.rs @@ -0,0 +1,21 @@ +// 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. + +fn f() -> bool { + enum E { V(Z) } + //~^ ERROR can't use type parameters from outer function in the + + true +} + +fn main() { + let b = f::(); + assert!(b); +} diff --git a/src/test/compile-fail/issue-5997-struct.rs b/src/test/compile-fail/issue-5997-struct.rs new file mode 100644 index 00000000000..b2a63ed1c7b --- /dev/null +++ b/src/test/compile-fail/issue-5997-struct.rs @@ -0,0 +1,21 @@ +// 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. + +fn f() -> bool { + struct S(T); //~ ERROR use of undeclared type name `T` + //~^ ERROR can't use type parameters from outer function; try using + + true +} + +fn main() { + let b = f::(); + assert!(b); +} diff --git a/src/test/compile-fail/nested-ty-params.rs b/src/test/compile-fail/nested-ty-params.rs index 7b7ce6bee2f..0ee2a3add87 100644 --- a/src/test/compile-fail/nested-ty-params.rs +++ b/src/test/compile-fail/nested-ty-params.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:attempt to use a type argument out of scope +// error-pattern:can't use type parameters from outer function; try using fn hd(v: Vec ) -> U { fn hd1(w: [U]) -> U { return w[0]; } diff --git a/src/test/compile-fail/type-arg-out-of-scope.rs b/src/test/compile-fail/type-arg-out-of-scope.rs index 240b1aa06d4..ac2f9d0379f 100644 --- a/src/test/compile-fail/type-arg-out-of-scope.rs +++ b/src/test/compile-fail/type-arg-out-of-scope.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:attempt to use a type argument out of scope +// error-pattern:can't use type parameters from outer function; try using fn foo(x: T) { fn bar(f: |T| -> T) { } } diff --git a/src/test/run-pass/issue-5997.rs b/src/test/run-pass/issue-5997.rs new file mode 100644 index 00000000000..9e2a001cb21 --- /dev/null +++ b/src/test/run-pass/issue-5997.rs @@ -0,0 +1,22 @@ +// 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. + +fn f() -> bool { + enum E { V(T) } + + struct S(T); + + true +} + +fn main() { + let b = f::(); + assert!(b); +} \ No newline at end of file