about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2013-03-27 05:40:56 -0400
committerNiko Matsakis <niko@alum.mit.edu>2013-04-05 05:36:02 -0400
commitd94830830f81bde37124efd6b4c8b6c9649180e0 (patch)
tree24c6dd4a3060396985cbd57d8caf52fd6ea3fee2
parent1745a2cd08d1aa7437ec3d080c9ca85434b54cf5 (diff)
downloadrust-d94830830f81bde37124efd6b4c8b6c9649180e0.tar.gz
rust-d94830830f81bde37124efd6b4c8b6c9649180e0.zip
Move the replacement of bound regions out from `check_arguments` and into check_call / method_resolution
-rw-r--r--src/librustc/middle/moves.rs6
-rw-r--r--src/librustc/middle/ty.rs10
-rw-r--r--src/librustc/middle/typeck/check/method.rs40
-rw-r--r--src/librustc/middle/typeck/check/mod.rs164
4 files changed, 142 insertions, 78 deletions
diff --git a/src/librustc/middle/moves.rs b/src/librustc/middle/moves.rs
index 2f379ece5d3..7740485e82c 100644
--- a/src/librustc/middle/moves.rs
+++ b/src/librustc/middle/moves.rs
@@ -463,7 +463,7 @@ pub impl VisitContext {
             expr_method_call(callee, _, _, ref args, _) => { // callee.m(args)
                 // Implicit self is equivalent to & mode, but every
                 // other kind should be + mode.
-                self.use_receiver(expr.id, expr.span, callee, visitor);
+                self.use_receiver(callee, visitor);
                 self.use_fn_args(expr.callee_id, *args, visitor);
             }
 
@@ -665,7 +665,7 @@ pub impl VisitContext {
             return false;
         }
 
-        self.use_receiver(expr.id, expr.span, receiver_expr, visitor);
+        self.use_receiver(receiver_expr, visitor);
 
         // for overloaded operatrs, we are always passing in a
         // borrowed pointer, so it's always read mode:
@@ -718,8 +718,6 @@ pub impl VisitContext {
     }
 
     fn use_receiver(&self,
-                    _expr_id: node_id,
-                    _span: span,
                     receiver_expr: @expr,
                     visitor: vt<VisitContext>)
     {
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 30b933061e2..19ffb4edc84 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -2726,6 +2726,16 @@ fn node_id_has_type_params(cx: ctxt, id: ast::node_id) -> bool {
     cx.node_type_substs.contains_key(&id)
 }
 
+pub fn ty_fn_sig(fty: t) -> FnSig {
+    match get(fty).sty {
+        ty_bare_fn(ref f) => copy f.sig,
+        ty_closure(ref f) => copy f.sig,
+        ref s => {
+            fail!(fmt!("ty_fn_sig() called on non-fn type: %?", s))
+        }
+    }
+}
+
 // Type accessors for substructures of types
 pub fn ty_fn_args(fty: t) -> ~[arg] {
     match get(fty).sty {
diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs
index 3b01f0e839a..69d8fb495e1 100644
--- a/src/librustc/middle/typeck/check/method.rs
+++ b/src/librustc/middle/typeck/check/method.rs
@@ -92,6 +92,7 @@ use middle::typeck::check;
 use middle::typeck::infer;
 use middle::typeck::{method_map_entry, method_origin, method_param};
 use middle::typeck::{method_self, method_static, method_trait, method_super};
+use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig;
 use util::common::indenter;
 use util::ppaux::expr_repr;
 
@@ -99,6 +100,7 @@ use core::hashmap::HashSet;
 use core::result;
 use core::uint;
 use core::vec;
+use std::list::Nil;
 use syntax::ast::{def_id, sty_value, sty_region, sty_box};
 use syntax::ast::{sty_uniq, sty_static, node_id, by_copy, by_ref};
 use syntax::ast::{m_const, m_mutbl, m_imm};
@@ -121,7 +123,7 @@ pub fn lookup(
         fcx: @mut FnCtxt,
 
         // In a call `a.b::<X, Y, ...>(...)`:
-        expr: @ast::expr,                   // The expression `a.b`.
+        expr: @ast::expr,                   // The expression `a.b(...)`.
         self_expr: @ast::expr,              // The expression `a`.
         callee_id: node_id,                 // Where to store `a.b`'s type
         m_name: ast::ident,                 // The ident `b`.
@@ -1092,10 +1094,16 @@ pub impl<'self> LookupContext<'self> {
     fn confirm_candidate(&self,
                          self_ty: ty::t,
                          candidate: &Candidate)
-        -> method_map_entry {
+        -> method_map_entry
+    {
         let tcx = self.tcx();
         let fty = self.fn_ty_from_origin(&candidate.origin);
 
+        debug!("confirm_candidate(expr=%s, candidate=%s, fty=%s)",
+               expr_repr(tcx, self.expr),
+               self.cand_to_str(candidate),
+               self.ty_to_str(fty));
+
         self.enforce_trait_instance_limitations(fty, candidate);
         self.enforce_drop_trait_limitations(candidate);
 
@@ -1145,7 +1153,33 @@ pub impl<'self> LookupContext<'self> {
             ../*bad*/copy candidate.rcvr_substs
         };
 
-        self.fcx.write_ty_substs(self.callee_id, fty, all_substs);
+        // Compute the method type with type parameters substituted
+        debug!("fty=%s all_substs=%s",
+               self.ty_to_str(fty),
+               ty::substs_to_str(tcx, &all_substs));
+        let fty = ty::subst(tcx, &all_substs, fty);
+        debug!("after subst, fty=%s", self.ty_to_str(fty));
+
+        // Replace any bound regions that appear in the function
+        // signature with region variables
+        let bare_fn_ty = match ty::get(fty).sty {
+            ty::ty_bare_fn(ref f) => copy *f,
+            ref s => {
+                tcx.sess.span_bug(
+                    self.expr.span,
+                    fmt!("Invoking method with non-bare-fn ty: %?", s));
+            }
+        };
+        let (_, _, fn_sig) =
+            replace_bound_regions_in_fn_sig(
+                tcx, @Nil, None, &bare_fn_ty.sig,
+                |_br| self.fcx.infcx().next_region_var(
+                    self.expr.span, self.expr.id));
+        let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {sig: fn_sig, ..bare_fn_ty});
+        debug!("after replacing bound regions, fty=%s", self.ty_to_str(fty));
+
+        self.fcx.write_ty(self.callee_id, fty);
+        self.fcx.write_substs(self.callee_id, all_substs);
         method_map_entry {
             self_arg: arg {
                 mode: ast::expl(candidate.self_mode),
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index 516ec3a50cd..32009495772 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -1122,16 +1122,44 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
                                unifier: &fn()) {
     debug!(">> typechecking %s", fcx.expr_to_str(expr));
 
-    fn check_argument_types(
+    fn check_method_argument_types(
         fcx: @mut FnCtxt,
         sp: span,
-        call_expr_id: ast::node_id,
-        in_fty: ty::t,
+        method_fn_ty: ty::t,
         callee_expr: @ast::expr,
         args: &[@ast::expr],
         sugar: ast::CallSugar,
         deref_args: DerefArgs) -> ty::t
     {
+        match ty::get(method_fn_ty).sty {
+            ty::ty_bare_fn(ref fty) => {
+                check_argument_types(fcx, sp, fty.sig.inputs, callee_expr,
+                                     args, sugar, deref_args);
+                fty.sig.output
+            }
+            ty::ty_err => {
+                let err_inputs = err_args(fcx.tcx(), args.len());
+                check_argument_types(fcx, sp, err_inputs, callee_expr,
+                                     args, sugar, deref_args);
+                method_fn_ty
+            }
+            _ => {
+                fcx.tcx().sess.span_bug(
+                    sp,
+                    fmt!("Method without bare fn type"));
+            }
+        }
+    }
+
+    fn check_argument_types(
+        fcx: @mut FnCtxt,
+        sp: span,
+        fn_inputs: &[ty::arg],
+        callee_expr: @ast::expr,
+        args: &[@ast::expr],
+        sugar: ast::CallSugar,
+        deref_args: DerefArgs)
+    {
         /*!
          *
          * Generic function that factors out common logic from
@@ -1140,59 +1168,12 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
 
         let tcx = fcx.ccx.tcx;
 
-        // Replace all region parameters in the arguments and return
-        // type with fresh region variables.
-
-        debug!("check_argument_types: before universal quant., in_fty=%s",
-               fcx.infcx().ty_to_str(in_fty));
-
-        let sty = structure_of(fcx, sp, in_fty);
-
-        // FIXME(#3678) For now, do not permit calls to C abi functions.
-        match sty {
-            ty::ty_bare_fn(ty::BareFnTy {abis, _}) => {
-                if !abis.is_rust() {
-                    tcx.sess.span_err(
-                        sp,
-                        fmt!("Calls to C ABI functions are not (yet) \
-                              supported; be patient, dear user"));
-                }
-            }
-            _ => {}
-        }
-
-        // Extract the function signature from `in_fty`.
-        let sig = match sty {
-            ty::ty_bare_fn(ty::BareFnTy {sig: sig, _}) |
-            ty::ty_closure(ty::ClosureTy {sig: sig, _}) => sig,
-            _ => {
-                fcx.type_error_message(sp, |actual| {
-                    fmt!("expected function but \
-                          found `%s`", actual) }, in_fty, None);
-
-                // check each arg against "error", in order to set up
-                // all the node type bindings
-                FnSig {bound_lifetime_names: opt_vec::Empty,
-                       inputs: args.map(|_x| ty::arg {mode: ast::expl(ast::by_copy),
-                                                      ty: ty::mk_err(tcx)}),
-                       output: ty::mk_err(tcx)}
-            }
-        };
-
-        // Replace any bound regions that appear in the function
-        // signature with region variables
-        let (_, _, sig) =
-            replace_bound_regions_in_fn_sig(
-                tcx, @Nil, None, &sig,
-                |_br| fcx.infcx().next_region_var(
-                    sp, call_expr_id));
-
         // Grab the argument types, supplying fresh type variables
         // if the wrong number of arguments were supplied
         let supplied_arg_count = args.len();
-        let expected_arg_count = sig.inputs.len();
+        let expected_arg_count = fn_inputs.len();
         let formal_tys = if expected_arg_count == supplied_arg_count {
-            sig.inputs.map(|a| a.ty)
+            fn_inputs.map(|a| a.ty)
         } else {
             let suffix = match sugar {
                 ast::NoSugar => "",
@@ -1216,10 +1197,8 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
             vec::from_elem(supplied_arg_count, ty::mk_err(tcx))
         };
 
-        debug!("check_argument_types: after universal quant., \
-                formal_tys=%? sig.output=%s",
-               formal_tys.map(|t| fcx.infcx().ty_to_str(*t)),
-               fcx.infcx().ty_to_str(sig.output));
+        debug!("check_argument_types: formal_tys=%?",
+               formal_tys.map(|t| fcx.infcx().ty_to_str(*t)));
 
         // Check the arguments.
         // We do this in a pretty awful way: first we typecheck any arguments
@@ -1269,8 +1248,11 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
                 }
             }
         }
+    }
 
-        sig.output
+    fn err_args(tcx: ty::ctxt, len: uint) -> ~[ty::arg] {
+        vec::from_fn(len, |_| ty::arg {mode: ast::expl(ast::by_copy),
+                                       ty: ty::mk_err(tcx)})
     }
 
     // A generic function for checking assignment expressions
@@ -1295,13 +1277,53 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
         // that they appear in call position.
         check_expr(fcx, f);
 
+
+        // Extract the function signature from `in_fty`.
+        let fn_ty = fcx.expr_ty(f);
+        let fn_sty = structure_of(fcx, f.span, fn_ty);
+
+        // FIXME(#3678) For now, do not permit calls to C abi functions.
+        match fn_sty {
+            ty::ty_bare_fn(ty::BareFnTy {abis, _}) => {
+                if !abis.is_rust() {
+                    fcx.tcx().sess.span_err(
+                        call_expr.span,
+                        fmt!("Calls to C ABI functions are not (yet) \
+                              supported; be patient, dear user"));
+                }
+            }
+            _ => {}
+        }
+
+        let fn_sig = match fn_sty {
+            ty::ty_bare_fn(ty::BareFnTy {sig: sig, _}) |
+            ty::ty_closure(ty::ClosureTy {sig: sig, _}) => sig,
+            _ => {
+                fcx.type_error_message(call_expr.span, |actual| {
+                    fmt!("expected function but \
+                          found `%s`", actual) }, fn_ty, None);
+
+                // check each arg against "error", in order to set up
+                // all the node type bindings
+                FnSig {bound_lifetime_names: opt_vec::Empty,
+                       inputs: err_args(fcx.tcx(), args.len()),
+                       output: ty::mk_err(fcx.tcx())}
+            }
+        };
+
+        // Replace any bound regions that appear in the function
+        // signature with region variables
+        let (_, _, fn_sig) =
+            replace_bound_regions_in_fn_sig(
+                fcx.tcx(), @Nil, None, &fn_sig,
+                |_br| fcx.infcx().next_region_var(call_expr.span, call_expr.id));
+
         // Call the generic checker.
-        let ret_ty = check_argument_types(fcx, call_expr.span, call_expr.id,
-                                          fcx.expr_ty(f), f, args, sugar,
-                                          DontDerefArgs);
+        check_argument_types(fcx, call_expr.span, fn_sig.inputs, f,
+                             args, sugar, DontDerefArgs);
 
         // Pull the return type out of the type of the function.
-        fcx.write_ty(call_expr.id, ret_ty);
+        fcx.write_ty(call_expr.id, fn_sig.output);
     }
 
     // Checks a method call.
@@ -1313,6 +1335,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
                          tps: &[@ast::Ty],
                          sugar: ast::CallSugar) {
         check_expr(fcx, rcvr);
+
         // no need to check for bot/err -- callee does that
         let expr_t = structurally_resolved_type(fcx,
                                                 expr.span,
@@ -1352,9 +1375,9 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
 
         // Call the generic checker.
         let fn_ty = fcx.node_ty(expr.callee_id);
-        let ret_ty = check_argument_types(fcx, expr.span, expr.id,
-                                          fn_ty, expr, args, sugar,
-                                          DontDerefArgs);
+        let ret_ty = check_method_argument_types(fcx, expr.span,
+                                                 fn_ty, expr, args, sugar,
+                                                 DontDerefArgs);
 
         // Pull the return type out of the type of the function.
         fcx.write_ty(expr.id, ret_ty);
@@ -1405,10 +1428,9 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
                 let method_ty = fcx.node_ty(op_ex.callee_id);
                 let method_map = fcx.inh.method_map;
                 method_map.insert(op_ex.id, *origin);
-                check_argument_types(fcx, op_ex.span,
-                                     op_ex.id, method_ty,
-                                     op_ex, args,
-                                     ast::NoSugar, deref_args)
+                check_method_argument_types(fcx, op_ex.span,
+                                            method_ty, op_ex, args,
+                                            ast::NoSugar, deref_args)
             }
             _ => {
                 let tcx = fcx.tcx();
@@ -1416,9 +1438,9 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
                 // Check the args anyway
                 // so we get all the error messages
                 let expected_ty = ty::mk_err(tcx);
-                check_argument_types(fcx, op_ex.span, op_ex.id,
-                                     expected_ty, op_ex, args,
-                                     ast::NoSugar, deref_args);
+                check_method_argument_types(fcx, op_ex.span,
+                                            expected_ty, op_ex, args,
+                                            ast::NoSugar, deref_args);
                 ty::mk_err(tcx)
             }
         }