diff options
| author | Niko Matsakis <niko@alum.mit.edu> | 2013-03-27 05:40:56 -0400 |
|---|---|---|
| committer | Niko Matsakis <niko@alum.mit.edu> | 2013-04-05 05:36:02 -0400 |
| commit | d94830830f81bde37124efd6b4c8b6c9649180e0 (patch) | |
| tree | 24c6dd4a3060396985cbd57d8caf52fd6ea3fee2 | |
| parent | 1745a2cd08d1aa7437ec3d080c9ca85434b54cf5 (diff) | |
| download | rust-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.rs | 6 | ||||
| -rw-r--r-- | src/librustc/middle/ty.rs | 10 | ||||
| -rw-r--r-- | src/librustc/middle/typeck/check/method.rs | 40 | ||||
| -rw-r--r-- | src/librustc/middle/typeck/check/mod.rs | 164 |
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) } } |
