]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_typeck/astconv.rs
improve unknown enum variant errors
[rust.git] / src / librustc_typeck / astconv.rs
index fba4414c1275c88237c39a8aa05f34ca33a76464..0c206b27f80589b91917fdfd82e4dfe2ef28ca79 100644 (file)
@@ -99,11 +99,6 @@ enum GenericArgPosition {
     MethodCall,
 }
 
-/// Dummy type used for the `Self` of a `TraitRef` created for converting
-/// a trait object, and which gets removed in `ExistentialTraitRef`.
-/// This type must not appear anywhere in other converted types.
-const TRAIT_OBJECT_DUMMY_SELF: ty::TyKind<'static> = ty::Infer(ty::FreshTy(0));
-
 impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
     pub fn ast_region_to_region(&self,
         lifetime: &hir::Lifetime,
@@ -595,7 +590,9 @@ fn create_substs_for_ast_path(&self,
             infer_types,
         );
 
-        let is_object = self_ty.map_or(false, |ty| ty.sty == TRAIT_OBJECT_DUMMY_SELF);
+        let is_object = self_ty.map_or(false, |ty| {
+            ty == self.tcx().types.trait_object_dummy_self
+        });
         let default_needs_object_self = |param: &ty::GenericParamDef| {
             if let GenericParamDefKind::Type { has_default, .. } = param.kind {
                 if is_object && has_default {
@@ -956,10 +953,10 @@ fn ast_path_to_ty(&self,
     }
 
     /// Transform a `PolyTraitRef` into a `PolyExistentialTraitRef` by
-    /// removing the dummy `Self` type (`TRAIT_OBJECT_DUMMY_SELF`).
+    /// removing the dummy `Self` type (`trait_object_dummy_self`).
     fn trait_ref_to_existential(&self, trait_ref: ty::TraitRef<'tcx>)
                                 -> ty::ExistentialTraitRef<'tcx> {
-        if trait_ref.self_ty().sty != TRAIT_OBJECT_DUMMY_SELF {
+        if trait_ref.self_ty() != self.tcx().types.trait_object_dummy_self {
             bug!("trait_ref_to_existential called on {:?} with non-dummy Self", trait_ref);
         }
         ty::ExistentialTraitRef::erase_self_ty(self.tcx(), trait_ref)
@@ -980,7 +977,7 @@ fn conv_object_ty_poly_trait_ref(&self,
         }
 
         let mut projection_bounds = Vec::new();
-        let dummy_self = tcx.mk_ty(TRAIT_OBJECT_DUMMY_SELF);
+        let dummy_self = self.tcx().types.trait_object_dummy_self;
         let (principal, potential_assoc_types) = self.instantiate_poly_trait_ref(
             &trait_bounds[0],
             dummy_self,
@@ -1030,7 +1027,7 @@ fn conv_object_ty_poly_trait_ref(&self,
                 }
                 ty::Predicate::Projection(pred) => {
                     // A `Self` within the original bound will be substituted with a
-                    // `TRAIT_OBJECT_DUMMY_SELF`, so check for that.
+                    // `trait_object_dummy_self`, so check for that.
                     let references_self =
                         pred.skip_binder().ty.walk().any(|t| t == dummy_self);
 
@@ -1130,7 +1127,7 @@ fn conv_object_ty_poly_trait_ref(&self,
             err.emit();
         }
 
-        // Erase the `dummy_self` (`TRAIT_OBJECT_DUMMY_SELF`) used above.
+        // Erase the `dummy_self` (`trait_object_dummy_self`) used above.
         let existential_principal = principal.map_bound(|trait_ref| {
             self.trait_ref_to_existential(trait_ref)
         });
@@ -1365,12 +1362,11 @@ pub fn associated_path_to_ty(
                     let msg = format!("expected type, found variant `{}`", assoc_ident);
                     tcx.sess.span_err(span, &msg);
                 } else if qself_ty.is_enum() {
-                    // Report as incorrect enum variant rather than ambiguous type.
                     let mut err = tcx.sess.struct_span_err(
-                        span,
-                        &format!("no variant `{}` on enum `{}`", &assoc_ident.as_str(), qself_ty),
+                        assoc_ident.span,
+                        &format!("no variant `{}` in enum `{}`", assoc_ident, qself_ty),
                     );
-                    // Check if it was a typo.
+
                     let adt_def = qself_ty.ty_adt_def().expect("enum is not an ADT");
                     if let Some(suggested_name) = find_best_match_for_name(
                         adt_def.variants.iter().map(|variant| &variant.ident.name),
@@ -1378,14 +1374,20 @@ pub fn associated_path_to_ty(
                         None,
                     ) {
                         err.span_suggestion(
-                            span,
-                            "did you mean",
-                            format!("{}::{}", qself_ty, suggested_name),
+                            assoc_ident.span,
+                            "there is a variant with a similar name",
+                            suggested_name.to_string(),
                             Applicability::MaybeIncorrect,
                         );
                     } else {
-                        err.span_label(span, "unknown variant");
+                        err.span_label(span, format!("variant not found in `{}`", qself_ty));
                     }
+
+                    if let Some(sp) = tcx.hir().span_if_local(adt_def.did) {
+                        let sp = tcx.sess.source_map().def_span(sp);
+                        err.span_label(sp, format!("variant `{}` not found here", assoc_ident));
+                    }
+
                     err.emit();
                 } else if !qself_ty.references_error() {
                     // Don't print `TyErr` to the user.