about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_typeck/astconv.rs12
-rw-r--r--src/librustc_typeck/check/method/mod.rs14
-rw-r--r--src/librustc_typeck/check/method/suggest.rs70
-rw-r--r--src/librustc_typeck/check/mod.rs53
-rw-r--r--src/librustc_typeck/lib.rs4
5 files changed, 84 insertions, 69 deletions
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 18c19352a60..67f330536b8 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -1277,7 +1277,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                                      ref_id: ast::NodeId,
                                      span: Span,
                                      ty: Ty<'tcx>,
-                                     ty_hir: &hir::Ty,
+                                     qself: &hir::Ty,
                                      ty_path_def: Def,
                                      item_segment: &hir::PathSegment)
                                      -> (Ty<'tcx>, Def)
@@ -1292,11 +1292,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
         // Check if we have an enum variant here.
         if let ty::Adt(adt_def, _) = ty.sty {
             if adt_def.is_enum() {
-                if allow_type_alias_enum_variants(tcx, ty_hir, span) {
-                    let variant_def = adt_def.variants.iter().find(|vd| {
-                        tcx.hygienic_eq(assoc_name, vd.ident, adt_def.did)
-                    });
-                    if let Some(variant_def) = variant_def {
+                let variant_def = adt_def.variants.iter().find(|vd| {
+                    tcx.hygienic_eq(assoc_name, vd.ident, adt_def.did)
+                });
+                if let Some(variant_def) = variant_def {
+                    if allow_type_alias_enum_variants(tcx, qself, span) {
                         let def = Def::Variant(variant_def.did);
                         return (ty, def);
                     }
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index f594690f77f..4c96d476caa 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -8,7 +8,7 @@ mod suggest;
 
 pub use self::MethodError::*;
 pub use self::CandidateSource::*;
-pub use self::suggest::TraitInfo;
+pub use self::suggest::{SelfSource, TraitInfo};
 
 use check::FnCtxt;
 use namespace::Namespace;
@@ -361,7 +361,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         span: Span,
                         method_name: ast::Ident,
                         self_ty: Ty<'tcx>,
-                        self_ty_hir: &hir::Ty,
+                        qself: &hir::Ty,
                         expr_id: ast::NodeId)
                         -> Result<Def, MethodError<'tcx>> {
         debug!("resolve_ufcs: method_name={:?} self_ty={:?} expr_id={:?}",
@@ -375,11 +375,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // Check if we have an enum variant here.
         if let ty::Adt(adt_def, _) = self_ty.sty {
             if adt_def.is_enum() {
-                if allow_type_alias_enum_variants(tcx, self_ty_hir, span) {
-                    let variant_def = adt_def.variants.iter().find(|vd| {
-                        tcx.hygienic_eq(method_name, vd.ident, adt_def.did)
-                    });
-                    if let Some(variant_def) = variant_def {
+                let variant_def = adt_def.variants.iter().find(|vd| {
+                    tcx.hygienic_eq(method_name, vd.ident, adt_def.did)
+                });
+                if let Some(variant_def) = variant_def {
+                    if allow_type_alias_enum_variants(tcx, qself, span) {
                         let def = Def::VariantCtor(variant_def.did, variant_def.ctor_kind);
                         return Ok(def);
                     }
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 65a58d345cc..b368250b32d 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -6,7 +6,7 @@ use errors::{Applicability, DiagnosticBuilder};
 use middle::lang_items::FnOnceTraitLangItem;
 use namespace::Namespace;
 use rustc_data_structures::sync::Lrc;
-use rustc::hir::{self, Node};
+use rustc::hir::{self, ExprKind, Node, QPath};
 use rustc::hir::def::Def;
 use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, DefId};
 use rustc::hir::map as hir_map;
@@ -60,13 +60,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    pub fn report_method_error(&self,
-                               span: Span,
-                               rcvr_ty: Ty<'tcx>,
-                               item_name: ast::Ident,
-                               rcvr_expr: Option<&hir::Expr>,
-                               error: MethodError<'tcx>,
-                               args: Option<&'gcx [hir::Expr]>) {
+    pub fn report_method_error<'b>(&self,
+                                   span: Span,
+                                   rcvr_ty: Ty<'tcx>,
+                                   item_name: ast::Ident,
+                                   source: SelfSource<'b>,
+                                   error: MethodError<'tcx>,
+                                   args: Option<&'gcx [hir::Expr]>) {
         // Avoid suggestions when we don't know what's going on.
         if rcvr_ty.references_error() {
             return;
@@ -212,10 +212,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         .filter_map(|info|
                             self.associated_item(info.def_id, item_name, Namespace::Value)
                         );
-                    if let (true, false, Some(expr), Some(_)) = (actual.is_numeric(),
-                                                                 actual.has_concrete_skeleton(),
-                                                                 rcvr_expr,
-                                                                 candidates.next()) {
+                    if let (true, false, SelfSource::MethodCall(expr), Some(_)) =
+                           (actual.is_numeric(),
+                            actual.has_concrete_skeleton(),
+                            source,
+                            candidates.next()) {
                         let mut err = struct_span_err!(
                             tcx.sess,
                             span,
@@ -231,7 +232,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                             "f32"
                         };
                         match expr.node {
-                            hir::ExprKind::Lit(ref lit) => {
+                            ExprKind::Lit(ref lit) => {
                                 // numeric literal
                                 let snippet = tcx.sess.source_map().span_to_snippet(lit.span)
                                     .unwrap_or_else(|_| "<numeric literal>".to_owned());
@@ -247,9 +248,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                                     Applicability::MaybeIncorrect,
                                 );
                             }
-                            hir::ExprKind::Path(ref qpath) => {
+                            ExprKind::Path(ref qpath) => {
                                 // local binding
-                                if let &hir::QPath::Resolved(_, ref path) = &qpath {
+                                if let &QPath::Resolved(_, ref path) = &qpath {
                                     if let hir::def::Def::Local(node_id) = path.def {
                                         let span = tcx.hir().span(node_id);
                                         let snippet = tcx.sess.source_map().span_to_snippet(span)
@@ -294,7 +295,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     } else {
                         let mut err = struct_span_err!(
                             tcx.sess,
-                            span,
+                            item_name.span,
                             E0599,
                             "no {} named `{}` found for type `{}` in the current scope",
                             item_kind,
@@ -302,7 +303,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                             ty_str
                         );
                         if let Some(suggestion) = suggestion {
-                            err.note(&format!("did you mean `{}::{}`?", ty_str, suggestion));
+                            // enum variant
+                            err.help(&format!("did you mean `{}`?", suggestion));
                         }
                         err
                     }
@@ -326,7 +328,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
                 // If the method name is the name of a field with a function or closure type,
                 // give a helping note that it has to be called as `(x.f)(...)`.
-                if let Some(expr) = rcvr_expr {
+                if let SelfSource::MethodCall(expr) = source {
                     for (ty, _) in self.autoderef(span, rcvr_ty) {
                         if let ty::Adt(def, substs) = ty.sty {
                             if !def.is_enum() {
@@ -377,10 +379,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         }
                     }
 
-                    if let Some(expr) = rcvr_expr {
+                    if let SelfSource::MethodCall(expr) = source {
                         if let Ok(expr_string) = tcx.sess.source_map().span_to_snippet(expr.span) {
                             report_function!(expr.span, expr_string);
-                        } else if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) =
+                        } else if let ExprKind::Path(QPath::Resolved(_, ref path)) =
                             expr.node
                         {
                             if let Some(segment) = path.segments.last() {
@@ -396,7 +398,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     err.span_label(span, "this is an associated function, not a method");
                 }
                 if static_sources.len() == 1 {
-                    if let Some(expr) = rcvr_expr {
+                    if let SelfSource::MethodCall(expr) = source {
                         err.span_suggestion_with_applicability(expr.span.to(span),
                                             "use associated function syntax instead",
                                             format!("{}::{}",
@@ -433,7 +435,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                                   span,
                                                   rcvr_ty,
                                                   item_name,
-                                                  rcvr_expr,
+                                                  source,
                                                   out_of_scope_traits);
                 }
 
@@ -571,18 +573,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    fn suggest_traits_to_import(&self,
-                                err: &mut DiagnosticBuilder,
-                                span: Span,
-                                rcvr_ty: Ty<'tcx>,
-                                item_name: ast::Ident,
-                                rcvr_expr: Option<&hir::Expr>,
-                                valid_out_of_scope_traits: Vec<DefId>) {
+    fn suggest_traits_to_import<'b>(&self,
+                                    err: &mut DiagnosticBuilder,
+                                    span: Span,
+                                    rcvr_ty: Ty<'tcx>,
+                                    item_name: ast::Ident,
+                                    source: SelfSource<'b>,
+                                    valid_out_of_scope_traits: Vec<DefId>) {
         if self.suggest_valid_traits(err, valid_out_of_scope_traits) {
             return;
         }
 
-        let type_is_local = self.type_derefs_to_local(span, rcvr_ty, rcvr_expr);
+        let type_is_local = self.type_derefs_to_local(span, rcvr_ty, source);
 
         // There are no traits implemented, so lets suggest some traits to
         // implement, by finding ones that have the item name, and are
@@ -663,7 +665,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         // This occurs for UFCS desugaring of `T::method`, where there is no
         // receiver expression for the method call, and thus no autoderef.
-        if rcvr_expr.is_none() {
+        if let SelfSource::QPath(_) = source {
             return is_local(self.resolve_type_vars_with_obligations(rcvr_ty));
         }
 
@@ -672,6 +674,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 }
 
 #[derive(Copy, Clone)]
+pub enum SelfSource<'a> {
+    QPath(&'a hir::Ty),
+    MethodCall(&'a hir::Expr /* rcvr */),
+}
+
+#[derive(Copy, Clone)]
 pub struct TraitInfo {
     pub def_id: DefId,
 }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 9914ae7ed89..37739eb655f 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -142,7 +142,7 @@ use self::autoderef::Autoderef;
 use self::callee::DeferredCallResolution;
 use self::coercion::{CoerceMany, DynamicCoerceMany};
 pub use self::compare_method::{compare_impl_method, compare_const_impl};
-use self::method::MethodCallee;
+use self::method::{MethodCallee, SelfSource};
 use self::TupleArgumentsFlag::*;
 
 /// The type of a local binding, including the revealed type for anon types.
@@ -3244,7 +3244,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     self.report_method_error(span,
                                              rcvr_t,
                                              segment.ident,
-                                             Some(rcvr),
+                                             SelfSource::MethodCall(rcvr),
                                              error,
                                              Some(args));
                 }
@@ -4558,7 +4558,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                        span: Span)
                                        -> (Def, Option<Ty<'tcx>>, &'b [hir::PathSegment])
     {
-        let (ty, ty_hir, item_segment) = match *qpath {
+        let (ty, qself, item_segment) = match *qpath {
             hir::QPath::Resolved(ref opt_qself, ref path) => {
                 return (path.def,
                         opt_qself.as_ref().map(|qself| self.to_ty(qself)),
@@ -4575,7 +4575,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             return (*cached_def, Some(ty), slice::from_ref(&**item_segment))
         }
         let item_name = item_segment.ident;
-        let def = match self.resolve_ufcs(span, item_name, ty, ty_hir, node_id) {
+        let def = match self.resolve_ufcs(span, item_name, ty, qself, node_id) {
             Ok(def) => def,
             Err(error) => {
                 let def = match error {
@@ -4583,7 +4583,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     _ => Def::Err,
                 };
                 if item_name.name != keywords::Invalid.name() {
-                    self.report_method_error(span, ty, item_name, None, error, None);
+                    self.report_method_error(span,
+                                             ty,
+                                             item_name,
+                                             SelfSource::QPath(qself),
+                                             error,
+                                             None);
                 }
                 def
             }
@@ -5114,7 +5119,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
             // Case 2. Reference to a variant constructor.
             Def::VariantCtor(def_id, ..) => {
-                if tcx.features().type_alias_enum_variants {
+                if self.tcx.features().type_alias_enum_variants {
                     let adt_def = self_ty.and_then(|t| t.ty_adt_def());
                     let (generics_def_id, index) = if let Some(adt_def) = adt_def {
                         debug_assert!(adt_def.is_enum());
@@ -5192,16 +5197,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             node_id,
         );
 
+        let tcx = self.tcx;
+
         let path_segs = self.def_ids_for_path_segments(segments, self_ty, def);
 
         let mut user_self_ty = None;
         match def {
             Def::Method(def_id) |
             Def::AssociatedConst(def_id) => {
-                let container = self.tcx.associated_item(def_id).container;
+                let container = tcx.associated_item(def_id).container;
                 match container {
                     ty::TraitContainer(trait_did) => {
-                        callee::check_legal_trait_for_method_call(self.tcx, span, trait_did)
+                        callee::check_legal_trait_for_method_call(tcx, span, trait_did)
                     }
                     ty::ImplContainer(impl_def_id) => {
                         if segments.len() == 1 {
@@ -5231,7 +5238,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             match def {
                 Def::VariantCtor(_, _) if self_ty.is_some() => true,
                 _ => false,
-            };
+            }
         } else {
             false
         };
@@ -5249,7 +5256,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             Def::Local(nid) | Def::Upvar(nid, ..) => {
                 let ty = self.local_ty(span, nid).decl_ty;
                 let ty = self.normalize_associated_types_in(span, &ty);
-                self.write_ty(self.tcx.hir().node_to_hir_id(node_id), ty);
+                self.write_ty(tcx.hir().node_to_hir_id(node_id), ty);
                 return (ty, def);
             }
             _ => {}
@@ -5265,13 +5272,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let mut infer_args_for_err = FxHashSet::default();
         for &PathSeg(def_id, index) in &path_segs {
             let seg = &segments[index];
-            let generics = self.tcx.generics_of(def_id);
+            let generics = tcx.generics_of(def_id);
             // Argument-position `impl Trait` is treated as a normal generic
             // parameter internally, but we don't allow users to specify the
             // parameter's value explicitly, so we have to do some error-
             // checking here.
             let suppress_errors = AstConv::check_generic_arg_count_for_call(
-                self.tcx,
+                tcx,
                 span,
                 &generics,
                 &seg,
@@ -5284,7 +5291,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         }
 
         let has_self = path_segs.last().map(|PathSeg(def_id, _)| {
-            self.tcx.generics_of(*def_id).has_self
+            tcx.generics_of(*def_id).has_self
         }).unwrap_or(false);
 
         let mut new_def = def;
@@ -5297,10 +5304,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     Some(adt_def) if adt_def.has_ctor() => {
                         let variant = adt_def.non_enum_variant();
                         new_def = Def::StructCtor(variant.did, variant.ctor_kind);
-                        (variant.did, self.tcx.type_of(variant.did))
+                        (variant.did, tcx.type_of(variant.did))
                     }
                     _ => {
-                        let mut err = self.tcx.sess.struct_span_err(span,
+                        let mut err = tcx.sess.struct_span_err(span,
                             "the `Self` constructor can only be used with tuple or unit structs");
                         if let Some(adt_def) = adt_def {
                             match adt_def.adt_kind() {
@@ -5318,14 +5325,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         }
                         err.emit();
 
-                        (impl_def_id, self.tcx.types.err)
+                        (impl_def_id, tcx.types.err)
                     }
                 }
             }
             Def::VariantCtor(_, _) if self_ty.is_some() => {
                 let def_id = def.def_id();
 
-                let ty = self.tcx.type_of(def_id);
+                let ty = tcx.type_of(def_id);
                 if tcx.features().type_alias_enum_variants {
                     if let Some(self_ty) = self_ty {
                         match ty.ty_adt_def() {
@@ -5343,13 +5350,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
                 // The things we are substituting into the type should not contain
                 // escaping late-bound regions, and nor should the base type scheme.
-                let ty = self.tcx.type_of(def_id);
+                let ty = tcx.type_of(def_id);
                 (def_id, ty)
             }
         };
 
         let substs = AstConv::create_substs_for_generic_args(
-            self.tcx,
+            tcx,
             def_id,
             &[][..],
             has_self,
@@ -5395,10 +5402,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                             // If we have a default, then we it doesn't matter that we're not
                             // inferring the type arguments: we provide the default where any
                             // is missing.
-                            let default = self.tcx.type_of(param.def_id);
+                            let default = tcx.type_of(param.def_id);
                             self.normalize_ty(
                                 span,
-                                default.subst_spanned(self.tcx, substs.unwrap(), Some(span))
+                                default.subst_spanned(tcx, substs.unwrap(), Some(span))
                             ).into()
                         } else {
                             // If no type arguments were provided, we have to infer them.
@@ -5415,7 +5422,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         assert!(!ty.has_escaping_bound_vars());
 
         // First, store the "user substs" for later.
-        let hir_id = self.tcx.hir().node_to_hir_id(node_id);
+        let hir_id = tcx.hir().node_to_hir_id(node_id);
         self.write_user_substs_from_substs(hir_id, substs, user_self_ty);
 
         // Add all the obligations that are required, substituting and
@@ -5434,7 +5441,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             // is inherent, there is no `Self` parameter, instead, the impl needs
             // type parameters, which we can infer by unifying the provided `Self`
             // with the substituted impl type.
-            let ty = self.tcx.type_of(impl_def_id);
+            let ty = tcx.type_of(impl_def_id);
 
             let impl_ty = self.instantiate_type_scheme(span, &substs, &ty);
             match self.at(&self.misc(span), self.param_env).sup(impl_ty, self_ty) {
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index d63e5a3fe93..4950ea31927 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -132,12 +132,12 @@ pub struct TypeAndSubsts<'tcx> {
 }
 
 fn allow_type_alias_enum_variants<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                                                  ty_hir: &hir::Ty,
+                                                  qself: &hir::Ty,
                                                   span: Span) -> bool {
     let allow_feature = tcx.features().type_alias_enum_variants;
     if !allow_feature {
         // Only print error if we know the type is an alias.
-        if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) = ty_hir.node {
+        if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) = qself.node {
             if let Def::TyAlias(_) = path.def {
                 let mut err = tcx.sess.struct_span_err(
                     span,