Skip to content

Commit

Permalink
librustc: When checking static method calls to unboxed closures, look at
Browse files Browse the repository at this point in the history
the right trait and take the method name into account.

Closes #16599.
  • Loading branch information
pcwalton committed Aug 20, 2014
1 parent 3f5d0b5 commit b0931a0
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 44 deletions.
49 changes: 36 additions & 13 deletions src/librustc/middle/ty.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -3195,19 +3214,23 @@ impl AutoRef {
}
}

pub fn method_call_type_param_defs(tcx: &ctxt, origin: typeck::MethodOrigin)
-> VecPerParamSpace<TypeParameterDef> {
pub fn method_call_type_param_defs<T>(typer: &T,
origin: typeck::MethodOrigin)
-> VecPerParamSpace<TypeParameterDef>
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,
Expand All @@ -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(),
}
}
Expand Down
53 changes: 24 additions & 29 deletions src/librustc/middle/typeck/check/method.rs
Expand Up @@ -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)));
Expand Down Expand Up @@ -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 \
Expand Down
37 changes: 37 additions & 0 deletions src/librustc/middle/typeck/check/mod.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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};
Expand Down Expand Up @@ -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<ty::t> {
self.ccx.tcx.node_ty(id)
}
fn node_method_ty(&self, method_call: typeck::MethodCall)
-> Option<ty::t> {
self.ccx.tcx.node_method_ty(method_call)
}
fn adjustments<'a>(&'a self) -> &'a RefCell<NodeMap<ty::AutoAdjustment>> {
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<ast::NodeId> {
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<DefIdMap<ty::UnboxedClosure>> {
&self.inh.unboxed_closures
}
}

impl<'a> Inherited<'a> {
fn new(tcx: &'a ty::ctxt,
param_env: ty::ParameterEnvironment)
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/typeck/check/regionck.rs
Expand Up @@ -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<ty::t> {
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/middle/typeck/check/vtable.rs
Expand Up @@ -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,
Expand Down
17 changes: 17 additions & 0 deletions 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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
}

17 changes: 17 additions & 0 deletions 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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,));
}

5 comments on commit b0931a0

@bors
Copy link
Contributor

@bors bors commented on b0931a0 Aug 21, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

saw approval from huonw
at pcwalton@b0931a0

@bors
Copy link
Contributor

@bors bors commented on b0931a0 Aug 21, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merging pcwalton/rust/unboxed-closures-wrong-trait = b0931a0 into auto

@bors
Copy link
Contributor

@bors bors commented on b0931a0 Aug 21, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pcwalton/rust/unboxed-closures-wrong-trait = b0931a0 merged ok, testing candidate = 6f1b1a6

@bors
Copy link
Contributor

@bors bors commented on b0931a0 Aug 21, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fast-forwarding master to auto = 6f1b1a6

Please sign in to comment.