From b0931a0a0f8ff10befa1e3037b670badca52a65f Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 20 Aug 2014 09:12:16 -0700 Subject: [PATCH] librustc: When checking static method calls to unboxed closures, look at the right trait and take the method name into account. Closes #16599. --- src/librustc/middle/ty.rs | 49 ++++++++++++----- src/librustc/middle/typeck/check/method.rs | 53 +++++++++---------- src/librustc/middle/typeck/check/mod.rs | 37 +++++++++++++ src/librustc/middle/typeck/check/regionck.rs | 2 +- src/librustc/middle/typeck/check/vtable.rs | 3 +- ...nboxed-closures-static-call-wrong-trait.rs | 17 ++++++ .../unboxed-closures-static-call-fn-once.rs | 17 ++++++ 7 files changed, 134 insertions(+), 44 deletions(-) create mode 100644 src/test/compile-fail/unboxed-closures-static-call-wrong-trait.rs create mode 100644 src/test/run-pass/unboxed-closures-static-call-fn-once.rs diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index ae96937757f0e..f9043ca337fc0 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -19,7 +19,8 @@ use middle::def; use middle::dependency_format; use middle::freevars::CaptureModeMap; use middle::freevars; -use middle::lang_items::{FnMutTraitLangItem, OpaqueStructLangItem}; +use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem}; +use middle::lang_items::{FnOnceTraitLangItem, OpaqueStructLangItem}; use middle::lang_items::{TyDescStructLangItem, TyVisitorTraitLangItem}; use middle::mem_categorization as mc; use middle::resolve; @@ -1205,6 +1206,24 @@ pub enum UnboxedClosureKind { FnOnceUnboxedClosureKind, } +impl UnboxedClosureKind { + pub fn trait_did(&self, cx: &ctxt) -> ast::DefId { + let result = match *self { + FnUnboxedClosureKind => cx.lang_items.require(FnTraitLangItem), + FnMutUnboxedClosureKind => { + cx.lang_items.require(FnMutTraitLangItem) + } + FnOnceUnboxedClosureKind => { + cx.lang_items.require(FnOnceTraitLangItem) + } + }; + match result { + Ok(trait_did) => trait_did, + Err(err) => cx.sess.fatal(err.as_slice()), + } + } +} + pub fn mk_ctxt(s: Session, dm: resolve::DefMap, named_region_map: resolve_lifetime::NamedRegionMap, @@ -3195,19 +3214,23 @@ impl AutoRef { } } -pub fn method_call_type_param_defs(tcx: &ctxt, origin: typeck::MethodOrigin) - -> VecPerParamSpace { +pub fn method_call_type_param_defs(typer: &T, + origin: typeck::MethodOrigin) + -> VecPerParamSpace + where T: mc::Typer { match origin { typeck::MethodStatic(did) => { - ty::lookup_item_type(tcx, did).generics.types.clone() - } - typeck::MethodStaticUnboxedClosure(_) => { - match tcx.lang_items.require(FnMutTraitLangItem) { - Ok(def_id) => { - lookup_trait_def(tcx, def_id).generics.types.clone() - } - Err(s) => tcx.sess.fatal(s.as_slice()), - } + ty::lookup_item_type(typer.tcx(), did).generics.types.clone() + } + typeck::MethodStaticUnboxedClosure(did) => { + let def_id = typer.unboxed_closures() + .borrow() + .find(&did) + .expect("method_call_type_param_defs: didn't \ + find unboxed closure") + .kind + .trait_did(typer.tcx()); + lookup_trait_def(typer.tcx(), def_id).generics.types.clone() } typeck::MethodParam(typeck::MethodParam{ trait_id: trt_id, @@ -3219,7 +3242,7 @@ pub fn method_call_type_param_defs(tcx: &ctxt, origin: typeck::MethodOrigin) method_num: n_mth, .. }) => { - match ty::trait_item(tcx, trt_id, n_mth) { + match ty::trait_item(typer.tcx(), trt_id, n_mth) { ty::MethodTraitItem(method) => method.generics.types.clone(), } } diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 1e3ea095704bf..245bbe396fd0d 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -534,6 +534,11 @@ impl<'a> LookupContext<'a> { ty::MethodTraitItem(method) => method, }; + // Make sure it has the right name! + if method.ident.name != self.m_name { + return + } + let vcx = self.fcx.vtable_context(); let region_params = vec!(vcx.infcx.next_region_var(MiscVariable(self.span))); @@ -562,38 +567,28 @@ impl<'a> LookupContext<'a> { fn push_unboxed_closure_call_candidates_if_applicable( &mut self, closure_did: DefId) { - let trait_dids = [ - self.tcx().lang_items.fn_trait(), - self.tcx().lang_items.fn_mut_trait(), - self.tcx().lang_items.fn_once_trait() - ]; - for optional_trait_did in trait_dids.iter() { - let trait_did = match *optional_trait_did { - Some(trait_did) => trait_did, - None => continue, - }; - - match self.tcx().unboxed_closures.borrow().find(&closure_did) { - None => {} // Fall through to try inherited. - Some(closure) => { - self.push_unboxed_closure_call_candidate_if_applicable( - trait_did, - closure_did, - &closure.closure_type); - return - } + match self.tcx().unboxed_closures.borrow().find(&closure_did) { + None => {} // Fall through to try inherited. + Some(closure) => { + let tcx = self.tcx(); + self.push_unboxed_closure_call_candidate_if_applicable( + closure.kind.trait_did(tcx), + closure_did, + &closure.closure_type); + return } + } - match self.fcx.inh.unboxed_closures.borrow().find(&closure_did) { - Some(closure) => { - self.push_unboxed_closure_call_candidate_if_applicable( - trait_did, - closure_did, - &closure.closure_type); - return - } - None => {} + match self.fcx.inh.unboxed_closures.borrow().find(&closure_did) { + Some(closure) => { + let tcx = self.tcx(); + self.push_unboxed_closure_call_candidate_if_applicable( + closure.kind.trait_did(tcx), + closure_did, + &closure.closure_type); + return } + None => {} } self.tcx().sess.bug("didn't find unboxed closure type in tcx map or \ diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 7896316a47229..c7a63710ef3ec 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -79,7 +79,10 @@ type parameter). use middle::const_eval; use middle::def; +use middle::freevars; use middle::lang_items::IteratorItem; +use middle::mem_categorization::McResult; +use middle::mem_categorization; use middle::pat_util::pat_id_map; use middle::pat_util; use middle::subst; @@ -110,6 +113,7 @@ use middle::typeck::no_params; use middle::typeck::{require_same_types, vtable_map}; use middle::typeck::{MethodCall, MethodMap}; use middle::typeck::{TypeAndSubsts}; +use middle::typeck; use middle::lang_items::TypeIdLangItem; use lint; use util::common::{block_query, indenter, loop_query}; @@ -261,6 +265,39 @@ pub struct FnCtxt<'a> { ccx: &'a CrateCtxt<'a>, } +impl<'a> mem_categorization::Typer for FnCtxt<'a> { + fn tcx<'a>(&'a self) -> &'a ty::ctxt { + self.ccx.tcx + } + fn node_ty(&self, id: ast::NodeId) -> McResult { + self.ccx.tcx.node_ty(id) + } + fn node_method_ty(&self, method_call: typeck::MethodCall) + -> Option { + self.ccx.tcx.node_method_ty(method_call) + } + fn adjustments<'a>(&'a self) -> &'a RefCell> { + self.ccx.tcx.adjustments() + } + fn is_method_call(&self, id: ast::NodeId) -> bool { + self.ccx.tcx.is_method_call(id) + } + fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option { + self.ccx.tcx.temporary_scope(rvalue_id) + } + fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> ty::UpvarBorrow { + self.ccx.tcx.upvar_borrow(upvar_id) + } + fn capture_mode(&self, closure_expr_id: ast::NodeId) + -> freevars::CaptureMode { + self.ccx.tcx.capture_mode(closure_expr_id) + } + fn unboxed_closures<'a>(&'a self) + -> &'a RefCell> { + &self.inh.unboxed_closures + } +} + impl<'a> Inherited<'a> { fn new(tcx: &'a ty::ctxt, param_env: ty::ParameterEnvironment) diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index 8e41c9463f6b8..3813dd7964244 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -263,7 +263,7 @@ impl<'a> Rcx<'a> { impl<'fcx> mc::Typer for Rcx<'fcx> { fn tcx<'a>(&'a self) -> &'a ty::ctxt { - self.fcx.tcx() + self.fcx.ccx.tcx } fn node_ty(&self, id: ast::NodeId) -> mc::McResult { diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 1aa469b15ba15..0708846af2a59 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -774,7 +774,8 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { Some(method) => { debug!("vtable resolution on parameter bounds for method call {}", ex.repr(fcx.tcx())); - let type_param_defs = ty::method_call_type_param_defs(cx.tcx, method.origin); + let type_param_defs = + ty::method_call_type_param_defs(fcx, method.origin); let substs = fcx.method_ty_substs(ex.id); let vcx = fcx.vtable_context(); let vtbls = lookup_vtables(&vcx, ex.span, diff --git a/src/test/compile-fail/unboxed-closures-static-call-wrong-trait.rs b/src/test/compile-fail/unboxed-closures-static-call-wrong-trait.rs new file mode 100644 index 0000000000000..871889f26dfd2 --- /dev/null +++ b/src/test/compile-fail/unboxed-closures-static-call-wrong-trait.rs @@ -0,0 +1,17 @@ +// 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. + +#![feature(unboxed_closures)] + +fn main() { + let mut_ = |&mut: x| x; + mut_.call_once((0i, )); //~ ERROR type `closure` does not implement +} + diff --git a/src/test/run-pass/unboxed-closures-static-call-fn-once.rs b/src/test/run-pass/unboxed-closures-static-call-fn-once.rs new file mode 100644 index 0000000000000..beab82e804bf7 --- /dev/null +++ b/src/test/run-pass/unboxed-closures-static-call-fn-once.rs @@ -0,0 +1,17 @@ +// 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. + +#![feature(unboxed_closures)] + +fn main() { + let onetime = |: x| x; + onetime.call_once((0i,)); +} +