diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 55f0ef4fd57b6..b3ddd3869cb9f 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -299,15 +299,7 @@ fn item_to_def_like(cdata: Cmd, item: rbml::Doc, did: ast::DefId) -> DefLike { Constant => { // Check whether we have an associated const item. if item_sort(item) == Some('C') { - // Check whether the associated const is from a trait or impl. - // See the comment for methods below. - let provenance = if reader::maybe_get_doc( - item, tag_item_trait_parent_sort).is_some() { - def::FromTrait(item_require_parent_item(cdata, item)) - } else { - def::FromImpl(item_require_parent_item(cdata, item)) - }; - DlDef(def::DefAssociatedConst(did, provenance)) + DlDef(def::DefAssociatedConst(did)) } else { // Regular const item. DlDef(def::DefConst(did)) @@ -319,18 +311,7 @@ fn item_to_def_like(cdata: Cmd, item: rbml::Doc, did: ast::DefId) -> DefLike { Fn => DlDef(def::DefFn(did, false)), CtorFn => DlDef(def::DefFn(did, true)), Method | StaticMethod => { - // def_static_method carries an optional field of its enclosing - // trait or enclosing impl (if this is an inherent static method). - // So we need to detect whether this is in a trait or not, which - // we do through the mildly hacky way of checking whether there is - // a trait_parent_sort. - let provenance = if reader::maybe_get_doc( - item, tag_item_trait_parent_sort).is_some() { - def::FromTrait(item_require_parent_item(cdata, item)) - } else { - def::FromImpl(item_require_parent_item(cdata, item)) - }; - DlDef(def::DefMethod(did, provenance)) + DlDef(def::DefMethod(did)) } Type => { if item_sort(item) == Some('t') { diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 9889ea92215a4..5c3b0a1c2d246 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -444,9 +444,7 @@ impl tr for def::Def { fn tr(&self, dcx: &DecodeContext) -> def::Def { match *self { def::DefFn(did, is_ctor) => def::DefFn(did.tr(dcx), is_ctor), - def::DefMethod(did, p) => { - def::DefMethod(did.tr(dcx), p.map(|did2| did2.tr(dcx))) - } + def::DefMethod(did) => def::DefMethod(did.tr(dcx)), def::DefSelfTy(opt_did, impl_ids) => { def::DefSelfTy(opt_did.map(|did| did.tr(dcx)), impl_ids.map(|(nid1, nid2)| { (dcx.tr_id(nid1), @@ -456,9 +454,7 @@ impl tr for def::Def { def::DefForeignMod(did) => { def::DefForeignMod(did.tr(dcx)) } def::DefStatic(did, m) => { def::DefStatic(did.tr(dcx), m) } def::DefConst(did) => { def::DefConst(did.tr(dcx)) } - def::DefAssociatedConst(did, p) => { - def::DefAssociatedConst(did.tr(dcx), p.map(|did2| did2.tr(dcx))) - } + def::DefAssociatedConst(did) => def::DefAssociatedConst(did.tr(dcx)), def::DefLocal(nid) => { def::DefLocal(dcx.tr_id(nid)) } def::DefVariant(e_did, v_did, is_s) => { def::DefVariant(e_did.tr(dcx), v_did.tr(dcx), is_s) diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index baaf6b6a0401d..9667312b37057 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -650,7 +650,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, } } Some(def::DefConst(did)) | - Some(def::DefAssociatedConst(did, _)) => { + Some(def::DefAssociatedConst(did)) => { if let Some(expr) = const_eval::lookup_const_by_id(v.tcx, did, Some(e.id)) { let inner = v.global_expr(Mode::Const, expr); @@ -696,10 +696,17 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, v.add_qualif(ConstQualif::NON_ZERO_SIZED); true } - Some(def::DefMethod(did, def::FromImpl(_))) | Some(def::DefFn(did, _)) => { v.handle_const_fn_call(e, did, node_ty) } + Some(def::DefMethod(did)) => { + match v.tcx.impl_or_trait_item(did).container() { + ty::ImplContainer(_) => { + v.handle_const_fn_call(e, did, node_ty) + } + ty::TraitContainer(_) => false + } + } _ => false }; if !is_const { diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 12dd12f746fd4..f17cb673a5f2d 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -442,7 +442,7 @@ impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> { ast::PatIdent(..) | ast::PatEnum(..) | ast::PatQPath(..) => { let def = self.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()); match def { - Some(DefAssociatedConst(did, _)) | + Some(DefAssociatedConst(did)) | Some(DefConst(did)) => match lookup_const_by_id(self.tcx, did, Some(pat.id)) { Some(const_expr) => { const_expr_to_pat(self.tcx, const_expr, pat.span).map(|new_pat| { diff --git a/src/librustc/middle/check_static_recursion.rs b/src/librustc/middle/check_static_recursion.rs index 55a9a91930045..77bb53a77bc94 100644 --- a/src/librustc/middle/check_static_recursion.rs +++ b/src/librustc/middle/check_static_recursion.rs @@ -238,7 +238,7 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> { ast::ExprPath(..) => { match self.def_map.borrow().get(&e.id).map(|d| d.base_def) { Some(DefStatic(def_id, _)) | - Some(DefAssociatedConst(def_id, _)) | + Some(DefAssociatedConst(def_id)) | Some(DefConst(def_id)) if ast_util::is_local(def_id) => { match self.ast_map.get(def_id.node) { diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index 298126be2fd4b..fd1c8d4892a10 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -41,7 +41,7 @@ fn lookup_const<'a>(tcx: &'a ty::ctxt, e: &Expr) -> Option<&'a Expr> { let opt_def = tcx.def_map.borrow().get(&e.id).map(|d| d.full_def()); match opt_def { Some(def::DefConst(def_id)) | - Some(def::DefAssociatedConst(def_id, _)) => { + Some(def::DefAssociatedConst(def_id)) => { lookup_const_by_id(tcx, def_id, Some(e.id)) } Some(def::DefVariant(enum_def, variant_def, _)) => { @@ -929,10 +929,10 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>, (lookup_const_by_id(tcx, def_id, Some(e.id)), None) } } - Some(def::DefAssociatedConst(def_id, provenance)) => { + Some(def::DefAssociatedConst(def_id)) => { if ast_util::is_local(def_id) { - match provenance { - def::FromTrait(trait_id) => match tcx.map.find(def_id.node) { + match tcx.impl_or_trait_item(def_id).container() { + ty::TraitContainer(trait_id) => match tcx.map.find(def_id.node) { Some(ast_map::NodeTraitItem(ti)) => match ti.node { ast::ConstTraitItem(ref ty, _) => { if let ExprTypeChecked = ty_hint { @@ -950,7 +950,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>, }, _ => (None, None) }, - def::FromImpl(_) => match tcx.map.find(def_id.node) { + ty::ImplContainer(_) => match tcx.map.find(def_id.node) { Some(ast_map::NodeImplItem(ii)) => match ii.node { ast::ConstImplItem(ref ty, ref expr) => { (Some(&**expr), Some(&**ty)) diff --git a/src/librustc/middle/def.rs b/src/librustc/middle/def.rs index bce246fa4af86..36c6630c8227b 100644 --- a/src/librustc/middle/def.rs +++ b/src/librustc/middle/def.rs @@ -9,7 +9,6 @@ // except according to those terms. pub use self::Def::*; -pub use self::MethodProvenance::*; use middle::privacy::LastPrivate; use middle::subst::ParamSpace; @@ -28,7 +27,7 @@ pub enum Def { DefForeignMod(ast::DefId), DefStatic(ast::DefId, bool /* is_mutbl */), DefConst(ast::DefId), - DefAssociatedConst(ast::DefId /* const */, MethodProvenance), + DefAssociatedConst(ast::DefId), DefLocal(ast::NodeId), DefVariant(ast::DefId /* enum */, ast::DefId /* variant */, bool /* is_structure */), DefTy(ast::DefId, bool /* is_enum */), @@ -51,7 +50,7 @@ pub enum Def { DefStruct(ast::DefId), DefRegion(ast::NodeId), DefLabel(ast::NodeId), - DefMethod(ast::DefId /* method */, MethodProvenance), + DefMethod(ast::DefId), } /// The result of resolving a path. @@ -112,23 +111,6 @@ pub struct Export { pub def_id: ast::DefId, // The definition of the target. } -#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub enum MethodProvenance { - FromTrait(ast::DefId), - FromImpl(ast::DefId), -} - -impl MethodProvenance { - pub fn map(self, f: F) -> MethodProvenance where - F: FnOnce(ast::DefId) -> ast::DefId, - { - match self { - FromTrait(did) => FromTrait(f(did)), - FromImpl(did) => FromImpl(f(did)) - } - } -} - impl Def { pub fn local_node_id(&self) -> ast::NodeId { let def_id = self.def_id(); @@ -141,7 +123,7 @@ impl Def { DefFn(id, _) | DefMod(id) | DefForeignMod(id) | DefStatic(id, _) | DefVariant(_, id, _) | DefTy(id, _) | DefAssociatedTy(_, id) | DefTyParam(_, _, id, _) | DefUse(id) | DefStruct(id) | DefTrait(id) | - DefMethod(id, _) | DefConst(id) | DefAssociatedConst(id, _) | + DefMethod(id) | DefConst(id) | DefAssociatedConst(id) | DefSelfTy(Some(id), None)=> { id } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 2473cf8bbbdb8..ffd09326abc35 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -33,7 +33,6 @@ use metadata::{csearch, decoder}; use middle::{cfg, def, infer, pat_util, stability, traits}; -use middle::def::*; use middle::subst::Substs; use middle::ty::{self, Ty}; use middle::const_eval::{eval_const_expr_partial, ConstVal}; @@ -2251,34 +2250,73 @@ impl LintPass for UnconditionalRecursion { } } - // Check if the method call `id` refers to method `method`. + // Check if the expression `id` performs a call to `method`. fn expr_refers_to_this_method(tcx: &ty::ctxt, method: &ty::Method, id: ast::NodeId) -> bool { - let method_call = ty::MethodCall::expr(id); - let callee = match tcx.tables.borrow().method_map.get(&method_call) { - Some(&m) => m, - None => return false - }; - let callee_item = tcx.impl_or_trait_item(callee.def_id); + let tables = tcx.tables.borrow(); + + // Check for method calls and overloaded operators. + if let Some(m) = tables.method_map.get(&ty::MethodCall::expr(id)) { + if method_call_refers_to_method(tcx, method, m.def_id, m.substs, id) { + return true; + } + } + + // Check for overloaded autoderef method calls. + if let Some(&ty::AdjustDerefRef(ref adj)) = tables.adjustments.get(&id) { + for i in 0..adj.autoderefs { + let method_call = ty::MethodCall::autoderef(id, i as u32); + if let Some(m) = tables.method_map.get(&method_call) { + if method_call_refers_to_method(tcx, method, m.def_id, m.substs, id) { + return true; + } + } + } + } + + // Check for calls to methods via explicit paths (e.g. `T::method()`). + match tcx.map.get(id) { + ast_map::NodeExpr(&ast::Expr { node: ast::ExprCall(ref callee, _), .. }) => { + match tcx.def_map.borrow().get(&callee.id).map(|d| d.full_def()) { + Some(def::DefMethod(def_id)) => { + let no_substs = &ty::ItemSubsts::empty(); + let ts = tables.item_substs.get(&callee.id).unwrap_or(no_substs); + method_call_refers_to_method(tcx, method, def_id, &ts.substs, id) + } + _ => false + } + } + _ => false + } + } + + // Check if the method call to the method with the ID `callee_id` + // and instantiated with `callee_substs` refers to method `method`. + fn method_call_refers_to_method<'tcx>(tcx: &ty::ctxt<'tcx>, + method: &ty::Method, + callee_id: ast::DefId, + callee_substs: &Substs<'tcx>, + expr_id: ast::NodeId) -> bool { + let callee_item = tcx.impl_or_trait_item(callee_id); match callee_item.container() { // This is an inherent method, so the `def_id` refers // directly to the method definition. ty::ImplContainer(_) => { - callee.def_id == method.def_id + callee_id == method.def_id } // A trait method, from any number of possible sources. // Attempt to select a concrete impl before checking. ty::TraitContainer(trait_def_id) => { - let trait_substs = callee.substs.clone().method_to_trait(); + let trait_substs = callee_substs.clone().method_to_trait(); let trait_substs = tcx.mk_substs(trait_substs); let trait_ref = ty::TraitRef::new(trait_def_id, trait_substs); let trait_ref = ty::Binder(trait_ref); - let span = tcx.map.span(id); + let span = tcx.map.span(expr_id); let obligation = - traits::Obligation::new(traits::ObligationCause::misc(span, id), + traits::Obligation::new(traits::ObligationCause::misc(span, expr_id), trait_ref.to_poly_trait_predicate()); let param_env = ty::ParameterEnvironment::for_item(tcx, method.def_id.node); @@ -2289,12 +2327,12 @@ impl LintPass for UnconditionalRecursion { // If `T` is `Self`, then this call is inside // a default method definition. Ok(Some(traits::VtableParam(_))) => { - let self_ty = callee.substs.self_ty(); + let self_ty = callee_substs.self_ty(); let on_self = self_ty.map_or(false, |t| t.is_self()); // We can only be recurring in a default // method if we're being called literally // on the `Self` type. - on_self && callee.def_id == method.def_id + on_self && callee_id == method.def_id } // The `impl` is known, so we check that with a @@ -2454,7 +2492,7 @@ impl LintPass for MutableTransmutes { ast::ExprPath(..) => (), _ => return None } - if let DefFn(did, _) = cx.tcx.resolve_expr(expr) { + if let def::DefFn(did, _) = cx.tcx.resolve_expr(expr) { if !def_id_is_transmute(cx, did) { return None; } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 27195d9635d73..656d6a3661470 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -545,14 +545,12 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { match trait_item.node { ast::ConstTraitItem(..) => { - let def = DefAssociatedConst(local_def(trait_item.id), - FromTrait(local_def(item.id))); + let def = DefAssociatedConst(local_def(trait_item.id)); // NB: not DefModifiers::IMPORTABLE name_bindings.define_value(def, trait_item.span, DefModifiers::PUBLIC); } ast::MethodTraitItem(..) => { - let def = DefMethod(local_def(trait_item.id), - FromTrait(local_def(item.id))); + let def = DefMethod(local_def(trait_item.id)); // NB: not DefModifiers::IMPORTABLE name_bindings.define_value(def, trait_item.span, DefModifiers::PUBLIC); } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index fa9c7a2038c80..c1f8af1562db3 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3448,7 +3448,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // Look for a method in the current self type's impl module. if let Some(module) = get_module(self, path.span, &name_path) { if let Some(binding) = module.children.borrow().get(&name) { - if let Some(DefMethod(did, _)) = binding.def_for_namespace(ValueNS) { + if let Some(DefMethod(did)) = binding.def_for_namespace(ValueNS) { if is_static_method(self, did) { return StaticMethod(path_names_to_string(&path, 0)) } diff --git a/src/librustc_trans/save/dump_csv.rs b/src/librustc_trans/save/dump_csv.rs index f1f39d43ee414..1fbec6f66cfdf 100644 --- a/src/librustc_trans/save/dump_csv.rs +++ b/src/librustc_trans/save/dump_csv.rs @@ -719,7 +719,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { let def_map = self.tcx.def_map.borrow(); let def = def_map.get(&id).unwrap().full_def(); match def { - def::DefMethod(did, _) => { + def::DefMethod(did) => { let ti = self.tcx.impl_or_trait_item(did); if let ty::MethodTraitItem(m) = ti { if m.explicit_self == ty::StaticExplicitSelfCategory { diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 8d3be7c8c6070..796850ad6f28b 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -551,12 +551,12 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { scope: self.enclosing_scope(id), })) } - def::DefMethod(decl_id, provenence) => { + def::DefMethod(decl_id) => { let sub_span = self.span_utils.sub_span_for_meth_name(path.span); let def_id = if decl_id.krate == ast::LOCAL_CRATE { let ti = self.tcx.impl_or_trait_item(decl_id); - match provenence { - def::FromTrait(def_id) => { + match ti.container() { + ty::TraitContainer(def_id) => { self.tcx.trait_items(def_id) .iter() .find(|mr| { @@ -564,7 +564,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { }) .map(|mr| mr.def_id()) } - def::FromImpl(def_id) => { + ty::ImplContainer(def_id) => { let impl_items = self.tcx.impl_items.borrow(); Some(impl_items.get(&def_id) .unwrap() diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index 0f75c1f8ab65a..a60217be40988 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -159,16 +159,27 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr) let def_id = inline::maybe_instantiate_inline(bcx.ccx(), did); Callee { bcx: bcx, data: Intrinsic(def_id.node, substs), ty: expr_ty } } - def::DefFn(did, _) | def::DefMethod(did, def::FromImpl(_)) => { + def::DefFn(did, _) => { fn_callee(bcx, trans_fn_ref(bcx.ccx(), did, ExprId(ref_expr.id), bcx.fcx.param_substs)) } - def::DefMethod(meth_did, def::FromTrait(trait_did)) => { - fn_callee(bcx, meth::trans_static_method_callee(bcx.ccx(), - meth_did, - trait_did, - ref_expr.id, - bcx.fcx.param_substs)) + def::DefMethod(meth_did) => { + let method_item = bcx.tcx().impl_or_trait_item(meth_did); + let fn_datum = match method_item.container() { + ty::ImplContainer(_) => { + trans_fn_ref(bcx.ccx(), meth_did, + ExprId(ref_expr.id), + bcx.fcx.param_substs) + } + ty::TraitContainer(trait_did) => { + meth::trans_static_method_callee(bcx.ccx(), + meth_did, + trait_did, + ref_expr.id, + bcx.fcx.param_substs) + } + }; + fn_callee(bcx, fn_datum) } def::DefVariant(tid, vid, _) => { let vinfo = bcx.tcx().enum_variant_with_id(tid, vid); diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index bd9c4a171773c..71ba4d73dace0 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -229,7 +229,7 @@ pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ast::ExprPath(..) => { let def = ccx.tcx().def_map.borrow().get(&expr.id).unwrap().full_def(); match def { - def::DefConst(def_id) | def::DefAssociatedConst(def_id, _) => { + def::DefConst(def_id) | def::DefAssociatedConst(def_id) => { if !ccx.tcx().tables.borrow().adjustments.contains_key(&expr.id) { debug!("get_const_expr_as_global ({:?}): found const {:?}", expr.id, def_id); @@ -802,7 +802,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, def::DefFn(..) | def::DefMethod(..) => { expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val } - def::DefConst(def_id) | def::DefAssociatedConst(def_id, _) => { + def::DefConst(def_id) | def::DefAssociatedConst(def_id) => { const_deref_ptr(cx, get_const_val(cx, def_id, e)) } def::DefVariant(enum_did, variant_did, _) => { @@ -846,9 +846,9 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let def = cx.tcx().def_map.borrow()[&callee.id].full_def(); let arg_vals = map_list(args); match def { - def::DefFn(did, _) | def::DefMethod(did, _) => { + def::DefFn(did, _) | def::DefMethod(did) => { const_fn_call(cx, ExprId(callee.id), did, &arg_vals, param_substs) - }, + } def::DefStruct(_) => { if ety.is_simd(cx.tcx()) { C_vector(&arg_vals[..]) @@ -856,7 +856,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let repr = adt::represent_type(cx, ety); adt::trans_const(cx, &*repr, 0, &arg_vals[..]) } - }, + } def::DefVariant(enum_did, variant_did, _) => { let repr = adt::represent_type(cx, ety); let vinfo = cx.tcx().enum_variant_with_id(enum_did, variant_did); @@ -864,14 +864,14 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, &*repr, vinfo.disr_val, &arg_vals[..]) - }, + } _ => cx.sess().span_bug(e.span, "expected a struct, variant, or const fn def"), } }, ast::ExprMethodCall(_, _, ref args) => { let arg_vals = map_list(args); let method_call = ty::MethodCall::expr(e.id); - let method_did = cx.tcx().tables.borrow().method_map[&method_call].def_id; + let method_did = cx.tcx().tables.borrow().method_map[&method_call].def_id; const_fn_call(cx, MethodCallKey(method_call), method_did, &arg_vals, param_substs) }, diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 2dae1aca8351d..619447df3c551 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -1293,14 +1293,22 @@ pub fn trans_def_fn_unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, match def { def::DefFn(did, _) | - def::DefStruct(did) | def::DefVariant(_, did, _) | - def::DefMethod(did, def::FromImpl(_)) => { + def::DefStruct(did) | def::DefVariant(_, did, _) => { callee::trans_fn_ref(ccx, did, ExprId(ref_expr.id), param_substs) } - def::DefMethod(impl_did, def::FromTrait(trait_did)) => { - meth::trans_static_method_callee(ccx, impl_did, - trait_did, ref_expr.id, - param_substs) + def::DefMethod(method_did) => { + match ccx.tcx().impl_or_trait_item(method_did).container() { + ty::ImplContainer(_) => { + callee::trans_fn_ref(ccx, method_did, + ExprId(ref_expr.id), + param_substs) + } + ty::TraitContainer(trait_did) => { + meth::trans_static_method_callee(ccx, method_did, + trait_did, ref_expr.id, + param_substs) + } + } } _ => { ccx.tcx().sess.span_bug(ref_expr.span, &format!( diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index e3f55cca9ee51..fd5d8d8d1961f 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -334,19 +334,14 @@ pub fn resolve_ufcs<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let pick = try!(probe::probe(fcx, span, mode, method_name, self_ty, expr_id)); let def_id = pick.item.def_id(); let mut lp = LastMod(AllPublic); - let container_def_id = pick.item.container().id(); - let provenance = match pick.kind { - probe::InherentImplPick => { - if pick.item.vis() != ast::Public { - lp = LastMod(DependsOn(def_id)); - } - def::FromImpl(container_def_id) + if let probe::InherentImplPick = pick.kind { + if pick.item.vis() != ast::Public { + lp = LastMod(DependsOn(def_id)); } - _ => def::FromTrait(container_def_id) - }; + } let def_result = match pick.item { - ty::ImplOrTraitItem::MethodTraitItem(..) => def::DefMethod(def_id, provenance), - ty::ImplOrTraitItem::ConstTraitItem(..) => def::DefAssociatedConst(def_id, provenance), + ty::ImplOrTraitItem::MethodTraitItem(..) => def::DefMethod(def_id), + ty::ImplOrTraitItem::ConstTraitItem(..) => def::DefAssociatedConst(def_id), ty::ImplOrTraitItem::TypeTraitItem(..) => { fcx.tcx().sess.span_bug(span, "resolve_ufcs: probe picked associated type"); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 819f443729796..6851fb4667015 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4447,9 +4447,9 @@ fn type_scheme_and_predicates_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, (ty::TypeScheme { generics: ty::Generics::empty(), ty: typ }, ty::GenericPredicates::empty()) } - def::DefFn(id, _) | def::DefMethod(id, _) | + def::DefFn(id, _) | def::DefMethod(id) | def::DefStatic(id, _) | def::DefVariant(_, id, _) | - def::DefStruct(id) | def::DefConst(id) | def::DefAssociatedConst(id, _) => { + def::DefStruct(id) | def::DefConst(id) | def::DefAssociatedConst(id) => { (fcx.tcx().lookup_item_type(id), fcx.tcx().lookup_predicates(id)) } def::DefTrait(_) | @@ -4555,7 +4555,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, assert!(!segments.is_empty()); - let mut ufcs_method = None; + let mut ufcs_associated = None; let mut segment_spaces: Vec<_>; match def { // Case 1 and 1b. Reference to a *type* or *enum variant*. @@ -4582,12 +4582,13 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } // Case 3. Reference to a method. - def::DefMethod(_, provenance) => { - match provenance { - def::FromTrait(trait_did) => { + def::DefMethod(def_id) => { + let container = fcx.tcx().impl_or_trait_item(def_id).container(); + match container { + ty::TraitContainer(trait_did) => { callee::check_legal_trait_for_method_call(fcx.ccx, span, trait_did) } - def::FromImpl(_) => {} + ty::ImplContainer(_) => {} } if segments.len() >= 2 { @@ -4598,16 +4599,17 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // `::method` will end up here, and so can `T::method`. let self_ty = opt_self_ty.expect("UFCS sugared method missing Self"); segment_spaces = vec![Some(subst::FnSpace)]; - ufcs_method = Some((provenance, self_ty)); + ufcs_associated = Some((container, self_ty)); } } - def::DefAssociatedConst(_, provenance) => { - match provenance { - def::FromTrait(trait_did) => { + def::DefAssociatedConst(def_id) => { + let container = fcx.tcx().impl_or_trait_item(def_id).container(); + match container { + ty::TraitContainer(trait_did) => { callee::check_legal_trait_for_method_call(fcx.ccx, span, trait_did) } - def::FromImpl(_) => {} + ty::ImplContainer(_) => {} } if segments.len() >= 2 { @@ -4615,7 +4617,10 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, segment_spaces.push(Some(subst::TypeSpace)); segment_spaces.push(None); } else { + // `::CONST` will end up here, and so can `T::CONST`. + let self_ty = opt_self_ty.expect("UFCS sugared const missing Self"); segment_spaces = vec![None]; + ufcs_associated = Some((container, self_ty)); } } @@ -4637,7 +4642,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // In `>::method`, `A` and `B` are mandatory, but // `opt_self_ty` can also be Some for `Foo::method`, where Foo's // type parameters are not mandatory. - let require_type_space = opt_self_ty.is_some() && ufcs_method.is_none(); + let require_type_space = opt_self_ty.is_some() && ufcs_associated.is_none(); debug!("segment_spaces={:?}", segment_spaces); @@ -4707,7 +4712,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let ty_substituted = fcx.instantiate_type_scheme(span, &substs, &type_scheme.ty); - if let Some((def::FromImpl(impl_def_id), self_ty)) = ufcs_method { + if let Some((ty::ImplContainer(impl_def_id), self_ty)) = ufcs_associated { // In the case of `Foo::method` and `>::method`, if `method` // is inherent, there is no `Self` parameter, instead, the impl needs // type parameters, which we can infer by unifying the provided `Self` diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index e80fd360e04fd..31cd8ce1b53e5 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -107,7 +107,7 @@ fn try_inline_def(cx: &DocContext, tcx: &ty::ctxt, record_extern_fqn(cx, did, clean::TypeStatic); clean::StaticItem(build_static(cx, tcx, did, mtbl)) } - def::DefConst(did) | def::DefAssociatedConst(did, _) => { + def::DefConst(did) | def::DefAssociatedConst(did) => { record_extern_fqn(cx, did, clean::TypeConst); clean::ConstantItem(build_const(cx, tcx, did)) } diff --git a/src/test/compile-fail/lint-unconditional-recursion.rs b/src/test/compile-fail/lint-unconditional-recursion.rs index 47bb7f948a786..6e3a00746f3e6 100644 --- a/src/test/compile-fail/lint-unconditional-recursion.rs +++ b/src/test/compile-fail/lint-unconditional-recursion.rs @@ -41,6 +41,7 @@ fn quz() -> bool { //~ ERROR function cannot return without recurring } } +// Trait method calls. trait Foo { fn bar(&self) { //~ ERROR function cannot return without recurring self.bar() //~ NOTE recursive call site @@ -53,14 +54,79 @@ impl Foo for Box { self.bar() //~ NOTE recursive call site } } +} + +// Trait method call with integer fallback after method resolution. +impl Foo for i32 { + fn bar(&self) { //~ ERROR function cannot return without recurring + 0.bar() //~ NOTE recursive call site + } +} + +impl Foo for u32 { + fn bar(&self) { + 0.bar() + } +} +// Trait method calls via paths. +trait Foo2 { + fn bar(&self) { //~ ERROR function cannot return without recurring + Foo2::bar(self) //~ NOTE recursive call site + } +} + +impl Foo2 for Box { + fn bar(&self) { //~ ERROR function cannot return without recurring + loop { + Foo2::bar(self) //~ NOTE recursive call site + } + } } struct Baz; impl Baz { + // Inherent method call. fn qux(&self) { //~ ERROR function cannot return without recurring self.qux(); //~ NOTE recursive call site } + + // Inherent method call via path. + fn as_ref(&self) -> &Self { //~ ERROR function cannot return without recurring + Baz::as_ref(self) //~ NOTE recursive call site + } +} + +// Trait method calls to impls via paths. +impl Default for Baz { + fn default() -> Baz { //~ ERROR function cannot return without recurring + let x = Default::default(); //~ NOTE recursive call site + x + } +} + +// Overloaded operators. +impl std::ops::Deref for Baz { + type Target = (); + fn deref(&self) -> &() { //~ ERROR function cannot return without recurring + &**self //~ NOTE recursive call site + } +} + +impl std::ops::Index for Baz { + type Output = Baz; + fn index(&self, x: usize) -> &Baz { //~ ERROR function cannot return without recurring + &self[x] //~ NOTE recursive call site + } +} + +// Overloaded autoderef. +struct Quux; +impl std::ops::Deref for Quux { + type Target = Baz; + fn deref(&self) -> &Baz { //~ ERROR function cannot return without recurring + self.as_ref() //~ NOTE recursive call site + } } fn all_fine() {