Skip to content

Commit

Permalink
Autoderef when suggesting to call (self.field)
Browse files Browse the repository at this point in the history
Fixes #32128
  • Loading branch information
jonas-schievink committed Apr 3, 2016
1 parent c0b8c43 commit da9c43a
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 18 deletions.
54 changes: 36 additions & 18 deletions src/librustc_typeck/check/method/suggest.rs
Expand Up @@ -14,14 +14,15 @@
use CrateCtxt;

use astconv::AstConv;
use check::{self, FnCtxt};
use check::{self, FnCtxt, UnresolvedTypeAction, autoderef};
use front::map as hir_map;
use rustc::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TypeFoldable};
use middle::cstore::{self, CrateStore};
use middle::def::Def;
use middle::def_id::DefId;
use middle::lang_items::FnOnceTraitLangItem;
use rustc::ty::subst::Substs;
use rustc::ty::LvaluePreference;
use rustc::traits::{Obligation, SelectionContext};
use util::nodemap::{FnvHashSet};

Expand Down Expand Up @@ -50,23 +51,40 @@ fn is_fn_ty<'a, 'tcx>(ty: &Ty<'tcx>, fcx: &FnCtxt<'a, 'tcx>, span: Span) -> bool
if let Ok(fn_once_trait_did) =
cx.lang_items.require(FnOnceTraitLangItem) {
let infcx = fcx.infcx();
infcx.probe(|_| {
let fn_once_substs =
Substs::new_trait(vec![infcx.next_ty_var()],
Vec::new(),
ty);
let trait_ref =
ty::TraitRef::new(fn_once_trait_did,
cx.mk_substs(fn_once_substs));
let poly_trait_ref = trait_ref.to_poly_trait_ref();
let obligation = Obligation::misc(span,
fcx.body_id,
poly_trait_ref
.to_predicate());
let mut selcx = SelectionContext::new(infcx);

return selcx.evaluate_obligation(&obligation)
})
let (_, _, opt_is_fn) = autoderef(fcx,
span,
ty,
|| None,
UnresolvedTypeAction::Ignore,
LvaluePreference::NoPreference,
|ty, _| {
infcx.probe(|_| {
let fn_once_substs =
Substs::new_trait(vec![infcx.next_ty_var()],
Vec::new(),
ty);
let trait_ref =
ty::TraitRef::new(fn_once_trait_did,
cx.mk_substs(fn_once_substs));
let poly_trait_ref = trait_ref.to_poly_trait_ref();
let obligation = Obligation::misc(span,
fcx.body_id,
poly_trait_ref
.to_predicate());
let mut selcx = SelectionContext::new(infcx);

if selcx.evaluate_obligation(&obligation) {
Some(true)
} else {
None
}
})
});

match opt_is_fn {
Some(result) => result,
None => false,
}
} else {
false
}
Expand Down
25 changes: 25 additions & 0 deletions src/test/compile-fail/issue-32128.rs
@@ -0,0 +1,25 @@
// Copyright 2016 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.

struct Example {
example: Box<Fn(i32) -> i32>
}

fn main() {
let demo = Example {
example: Box::new(|x| {
x + 1
})
};

demo.example(1); //~ ERROR no method named `example`
//~^ NOTE use `(demo.example)(...)`
// (demo.example)(1);
}

0 comments on commit da9c43a

Please sign in to comment.