From 1a6d029b075c2006f6a49c5ca4a062bc2a713cd5 Mon Sep 17 00:00:00 2001
From: Tim Chevalier <chevalier@alum.wellesley.edu>
Date: Tue, 21 Jun 2011 17:56:56 -0700
Subject: [PATCH] Emit a better error message for unbound type parameters in
 nested functions

This code was causing a bounds check failure:

fn hd[U](&vec[U] v) -> U {
  fn hd1(&vec[U] w) -> U {
    ret w.(0);
  }
  ret hd1(v);
}

because in hd1, U was being treated as if it referred to a type
parameter of hd1, rather than referring to the lexically enclosing binding
for U that's part of hd.

I'm actually not sure whether this is a legit program or not. But I wanted
to get rid of the bounds check error, so I assumed that program shouldn't
compile and made it a proper error message.
---
 src/comp/middle/ty.rs                     | 17 +++++++++++------
 src/comp/middle/typeck.rs                 |  2 +-
 src/test/compile-fail/nested-ty-params.rs | 11 +++++++++++
 3 files changed, 23 insertions(+), 7 deletions(-)
 create mode 100644 src/test/compile-fail/nested-ty-params.rs

diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs
index b38c9237cef..a519ac33bd7 100644
--- a/src/comp/middle/ty.rs
+++ b/src/comp/middle/ty.rs
@@ -2580,18 +2580,23 @@ fn type_err_to_str(&ty::type_err err) -> str {
 
 // Converts type parameters in a type to type variables and returns the
 // resulting type along with a list of type variable IDs.
-fn bind_params_in_type(&ctxt cx, fn() -> int  next_ty_var, t typ,
+fn bind_params_in_type(&span sp, &ctxt cx, fn() -> int  next_ty_var, t typ,
                        uint ty_param_count) -> tup(vec[int], t) {
     let vec[int] param_var_ids = [];
     auto i = 0u;
     while (i < ty_param_count) { param_var_ids += [next_ty_var()]; i += 1u; }
-    fn binder(ctxt cx, vec[int] param_var_ids, fn() -> int  next_ty_var,
-              uint index) -> t {
-        ret mk_var(cx, param_var_ids.(index));
+    fn binder(span sp, ctxt cx, vec[int] param_var_ids,
+              fn() -> int next_ty_var, uint index) -> t {
+        if (index < vec::len(param_var_ids)) {
+            ret mk_var(cx, param_var_ids.(index));
+        }
+        else {
+            cx.sess.span_fatal(sp, "Unbound type parameter in callee's type");
+        }
     }
     auto new_typ =
-        fold_ty(cx, fm_param(bind binder(cx, param_var_ids, next_ty_var, _)),
-                typ);
+        fold_ty(cx, fm_param(bind binder(sp, cx, param_var_ids,
+                                         next_ty_var, _)), typ);
     ret tup(param_var_ids, new_typ);
 }
 
diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs
index 3a33e64b6b9..1ad5bb693a7 100644
--- a/src/comp/middle/typeck.rs
+++ b/src/comp/middle/typeck.rs
@@ -132,7 +132,7 @@ fn instantiate_path(&@fn_ctxt fcx, &ast::path pth, &ty_param_count_and_ty tpt,
                     &span sp) -> ty_param_substs_opt_and_ty {
     auto ty_param_count = tpt._0;
     auto bind_result =
-        bind_params_in_type(fcx.ccx.tcx, bind next_ty_var_id(fcx), tpt._1,
+        bind_params_in_type(sp, fcx.ccx.tcx, bind next_ty_var_id(fcx), tpt._1,
                             ty_param_count);
     auto ty_param_vars = bind_result._0;
     auto t = bind_result._1;
diff --git a/src/test/compile-fail/nested-ty-params.rs b/src/test/compile-fail/nested-ty-params.rs
new file mode 100644
index 00000000000..e4fed7f07ec
--- /dev/null
+++ b/src/test/compile-fail/nested-ty-params.rs
@@ -0,0 +1,11 @@
+// error-pattern:Unbound type parameter in callee
+/* I'm actually not sure whether this should compile.
+   But having a nice error message seems better than
+   a bounds check failure (which is what was happening
+   before.) */
+fn hd[U](&vec[U] v) -> U {
+  fn hd1(&vec[U] w) -> U {
+    ret w.(0);
+  }
+  ret hd1(v);
+}