diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 18c19352a603..67f330536b85 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 f594690f77f0..4c96d476caa2 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> { 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 65a58d345ccf..b368250b32d9 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(|_| "".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) { + 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) { 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)); } @@ -671,6 +673,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 9914ae7ed893..37739eb655fb 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>, &'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 d63e5a3fe93a..4950ea319271 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,