about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEllen <supbscripter@gmail.com>2022-05-05 17:44:54 +0100
committerEllen <supbscripter@gmail.com>2022-05-05 17:45:39 +0100
commitfea1d765033eada386ffc1684d47c00a48d104f1 (patch)
treefef19174b45842ee05a51064217311a101fed588
parent4208c53ed695ddb822b6510e3faa0a46e591060e (diff)
downloadrust-fea1d765033eada386ffc1684d47c00a48d104f1.tar.gz
rust-fea1d765033eada386ffc1684d47c00a48d104f1.zip
make `compare_generic_param_kinds` errors consistent
-rw-r--r--compiler/rustc_typeck/src/check/compare_method.rs166
-rw-r--r--src/test/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.rs18
-rw-r--r--src/test/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.stderr75
-rw-r--r--src/test/ui/const-generics/issues/issue-86820.rs9
-rw-r--r--src/test/ui/const-generics/issues/issue-86820.stderr21
-rw-r--r--src/test/ui/generic-associated-types/const_params_have_right_type.rs2
-rw-r--r--src/test/ui/generic-associated-types/const_params_have_right_type.stderr17
7 files changed, 142 insertions, 166 deletions
diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs
index c810be16bf8..590131e4f6a 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_typeck/src/check/compare_method.rs
@@ -7,10 +7,10 @@ use rustc_hir::intravisit;
 use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind};
 use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
 use rustc_infer::traits::util;
-use rustc_middle::ty;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::subst::{InternalSubsts, Subst};
 use rustc_middle::ty::util::ExplicitSelf;
+use rustc_middle::ty::{self, DefIdTree};
 use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt};
 use rustc_span::Span;
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
@@ -48,7 +48,7 @@ crate fn compare_impl_method<'tcx>(
         return;
     }
 
-    if let Err(_) = compare_generic_param_kinds(tcx, impl_m, trait_m, trait_item_span) {
+    if let Err(_) = compare_generic_param_kinds(tcx, impl_m, trait_m) {
         return;
     }
 
@@ -973,7 +973,6 @@ fn compare_generic_param_kinds<'tcx>(
     tcx: TyCtxt<'tcx>,
     impl_item: &ty::AssocItem,
     trait_item: &ty::AssocItem,
-    trait_item_span: Option<Span>,
 ) -> Result<(), ErrorGuaranteed> {
     assert_eq!(impl_item.kind, trait_item.kind);
 
@@ -986,123 +985,54 @@ fn compare_generic_param_kinds<'tcx>(
         })
     };
 
-    let get_param_span = |param: &ty::GenericParamDef| match tcx.hir().get_if_local(param.def_id) {
-        Some(hir::Node::GenericParam(hir::GenericParam { span, .. })) => Some(span),
-        _ => None,
-    };
+    for (param_impl, param_trait) in
+        iter::zip(ty_const_params_of(impl_item.def_id), ty_const_params_of(trait_item.def_id))
+    {
+        use GenericParamDefKind::*;
+        if match (&param_impl.kind, &param_trait.kind) {
+            (Const { .. }, Const { .. })
+                if tcx.type_of(param_impl.def_id) != tcx.type_of(param_trait.def_id) =>
+            {
+                true
+            }
+            (Const { .. }, Type { .. }) | (Type { .. }, Const { .. }) => true,
+            // this is exhaustive so that anyone adding new generic param kinds knows
+            // to make sure this error is reported for them.
+            (Const { .. }, Const { .. }) | (Type { .. }, Type { .. }) => false,
+            (Lifetime { .. }, _) | (_, Lifetime { .. }) => unreachable!(),
+        } {
+            let make_param_message = |prefix: &str, param: &ty::GenericParamDef| match param.kind {
+                Const { .. } => {
+                    format!("{} const parameter with type `{}`", prefix, tcx.type_of(param.def_id))
+                }
+                Type { .. } => format!("{} type parameter", prefix),
+                Lifetime { .. } => unreachable!(),
+            };
 
-    let get_param_ident = |param: &ty::GenericParamDef| match tcx.hir().get_if_local(param.def_id) {
-        Some(hir::Node::GenericParam(hir::GenericParam { name, .. })) => match name {
-            hir::ParamName::Plain(ident) => Some(ident),
-            _ => None,
-        },
-        other => bug!(
-            "expected GenericParam, found {:?}",
-            other.map_or_else(|| "nothing".to_string(), |n| format!("{:?}", n))
-        ),
-    };
+            let param_impl_span = tcx.def_span(param_impl.def_id);
+            let param_trait_span = tcx.def_span(param_trait.def_id);
 
-    let ty_const_params_impl = ty_const_params_of(impl_item.def_id);
-    let ty_const_params_trait = ty_const_params_of(trait_item.def_id);
-    let assoc_item_str = assoc_item_kind_str(&impl_item);
+            let mut err = struct_span_err!(
+                tcx.sess,
+                param_impl_span,
+                E0053,
+                "{} `{}` has an incompatible generic parameter for trait: `{}`",
+                assoc_item_kind_str(&impl_item),
+                trait_item.name,
+                &tcx.def_path_str(tcx.parent(trait_item.def_id))
+            );
 
-    for (param_impl, param_trait) in iter::zip(ty_const_params_impl, ty_const_params_trait) {
-        use GenericParamDefKind::*;
-        match (&param_impl.kind, &param_trait.kind) {
-            (Const { .. }, Const { .. }) => {
-                let impl_ty = tcx.type_of(param_impl.def_id);
-                let trait_ty = tcx.type_of(param_trait.def_id);
-                if impl_ty != trait_ty {
-                    let param_impl_span = get_param_span(param_impl).unwrap();
-                    let param_impl_ident = get_param_ident(param_impl);
-                    let param_trait_span = get_param_span(param_trait);
-
-                    let mut err = struct_span_err!(
-                        tcx.sess,
-                        *param_impl_span,
-                        E0053,
-                        "{} `{}` has an incompatible const parameter type for trait",
-                        assoc_item_str,
-                        trait_item.name,
-                    );
-                    err.span_note(
-                        param_trait_span.map_or_else(
-                            || trait_item_span.unwrap_or(*param_impl_span),
-                            |span| *span,
-                        ),
-                        &format!(
-                            "the const parameter{} has type `{}`, but the declaration \
-                                      in trait `{}` has type `{}`",
-                            &param_impl_ident
-                                .map_or_else(|| "".to_string(), |ident| format!(" `{ident}`")),
-                            impl_ty,
-                            tcx.def_path_str(trait_item.def_id),
-                            trait_ty
-                        ),
-                    );
-                    let reported = err.emit();
-                    return Err(reported);
-                }
-            }
-            (Const { .. }, Type { .. }) => {
-                let impl_ty = tcx.type_of(param_impl.def_id);
-                let param_impl_span = get_param_span(param_impl).unwrap();
-                let param_impl_ident = get_param_ident(param_impl);
-                let param_trait_span = get_param_span(param_trait);
-
-                let mut err = struct_span_err!(
-                    tcx.sess,
-                    *param_impl_span,
-                    E0053,
-                    "{} `{}` has an incompatible generic parameter for trait",
-                    assoc_item_str,
-                    trait_item.name,
-                );
-                err.span_note(
-                    param_trait_span
-                        .map_or_else(|| trait_item_span.unwrap_or(*param_impl_span), |span| *span),
-                    &format!(
-                        "the trait impl specifies{} a const parameter of type `{}`, but the declaration \
-                                       in trait `{}` requires it is a type parameter",
-                        &param_impl_ident
-                            .map_or_else(|| "".to_string(), |ident| format!(" `{ident}` is")),
-                        impl_ty,
-                        tcx.def_path_str(trait_item.def_id),
-                    ),
-                );
-                let reported = err.emit();
-                return Err(reported);
-            }
-            (Type { .. }, Const { .. }) => {
-                let trait_ty = tcx.type_of(param_trait.def_id);
-                let param_impl_span = get_param_span(param_impl).unwrap();
-                let param_impl_ident = get_param_ident(param_impl);
-                let param_trait_span = get_param_span(param_trait);
-
-                let mut err = struct_span_err!(
-                    tcx.sess,
-                    *param_impl_span,
-                    E0053,
-                    "{} `{}` has an incompatible generic parameter for trait",
-                    assoc_item_str,
-                    trait_item.name,
-                );
-                err.span_note(
-                    param_trait_span
-                        .map_or_else(|| trait_item_span.unwrap_or(*param_impl_span), |span| *span),
-                    &format!(
-                        "the trait impl specifies{} a type parameter, but the declaration \
-                                       in trait `{}` requires it is a const parameter of type `{}`",
-                        &param_impl_ident
-                            .map_or_else(|| "".to_string(), |ident| format!(" `{ident}` is")),
-                        tcx.def_path_str(trait_item.def_id),
-                        trait_ty,
-                    ),
-                );
-                let reported = err.emit();
-                return Err(reported);
-            }
-            _ => (),
+            let trait_header_span = tcx.def_ident_span(tcx.parent(trait_item.def_id)).unwrap();
+            err.span_label(trait_header_span, "");
+            err.span_label(param_trait_span, make_param_message("expected", param_trait));
+
+            let impl_header_span =
+                tcx.sess.source_map().guess_head_span(tcx.def_span(tcx.parent(impl_item.def_id)));
+            err.span_label(impl_header_span, "");
+            err.span_label(param_impl_span, make_param_message("found", param_impl));
+
+            let reported = err.emit();
+            return Err(reported);
         }
     }
 
@@ -1228,7 +1158,7 @@ crate fn compare_ty_impl<'tcx>(
     let _: Result<(), ErrorGuaranteed> = (|| {
         compare_number_of_generics(tcx, impl_ty, impl_ty_span, trait_ty, trait_item_span)?;
 
-        compare_generic_param_kinds(tcx, impl_ty, trait_ty, trait_item_span)?;
+        compare_generic_param_kinds(tcx, impl_ty, trait_ty)?;
 
         let sp = tcx.def_span(impl_ty.def_id);
         compare_type_predicate_entailment(tcx, impl_ty, sp, trait_ty, impl_trait_ref)?;
diff --git a/src/test/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.rs b/src/test/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.rs
index fd57060d5e7..5c9323261a9 100644
--- a/src/test/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.rs
+++ b/src/test/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.rs
@@ -19,7 +19,23 @@ trait Uwu {
 }
 impl Uwu for () {
     fn baz<const N: i32>() {}
-    //~^ error: method `baz` has an incompatible const parameter type for trait
+    //~^ error: method `baz` has an incompatible generic parameter for trait
+}
+
+trait Aaaaaa {
+    fn bbbb<const N: u32, T>() {}
+}
+impl Aaaaaa for () {
+    fn bbbb<T, const N: u32>() {}
+    //~^ error: method `bbbb` has an incompatible generic parameter for trait
+}
+
+trait Names {
+    fn abcd<T, const N: u32>() {}
+}
+impl Names for () {
+    fn abcd<const N: u32, T>() {}
+    //~^ error: method `abcd` has an incompatible generic parameter for trait
 }
 
 fn main() {}
diff --git a/src/test/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.stderr b/src/test/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.stderr
index cea8f4e50b0..a1ec8adec76 100644
--- a/src/test/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.stderr
+++ b/src/test/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.stderr
@@ -1,39 +1,68 @@
-error[E0053]: method `foo` has an incompatible generic parameter for trait
+error[E0053]: method `foo` has an incompatible generic parameter for trait: `Trait`
   --> $DIR/mismatched_ty_const_in_trait_impl.rs:5:12
    |
-LL |     fn foo<const M: u64>() {}
-   |            ^^^^^^^^^^^^
-   |
-note: the trait impl specifies `M` is a const parameter of type `u64`, but the declaration in trait `Trait::foo` requires it is a type parameter
-  --> $DIR/mismatched_ty_const_in_trait_impl.rs:2:12
-   |
+LL | trait Trait {
+   |       -----
 LL |     fn foo<U>() {}
-   |            ^
+   |            - expected type parameter
+LL | }
+LL | impl Trait for () {
+   | -----------------
+LL |     fn foo<const M: u64>() {}
+   |            ^^^^^^^^^^^^ found const parameter with type `u64`
 
-error[E0053]: method `bar` has an incompatible generic parameter for trait
+error[E0053]: method `bar` has an incompatible generic parameter for trait: `Other`
   --> $DIR/mismatched_ty_const_in_trait_impl.rs:13:12
    |
-LL |     fn bar<T>() {}
-   |            ^
-   |
-note: the trait impl specifies `T` is a type parameter, but the declaration in trait `Other::bar` requires it is a const parameter of type `u8`
-  --> $DIR/mismatched_ty_const_in_trait_impl.rs:10:12
-   |
+LL | trait Other {
+   |       -----
 LL |     fn bar<const M: u8>() {}
-   |            ^^^^^^^^^^^
+   |            ----------- expected const parameter with type `u8`
+LL | }
+LL | impl Other for () {
+   | -----------------
+LL |     fn bar<T>() {}
+   |            ^ found type parameter
 
-error[E0053]: method `baz` has an incompatible const parameter type for trait
+error[E0053]: method `baz` has an incompatible generic parameter for trait: `Uwu`
   --> $DIR/mismatched_ty_const_in_trait_impl.rs:21:12
    |
+LL | trait Uwu {
+   |       ---
+LL |     fn baz<const N: u32>() {}
+   |            ------------ expected const parameter with type `u32`
+LL | }
+LL | impl Uwu for () {
+   | ---------------
 LL |     fn baz<const N: i32>() {}
-   |            ^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^ found const parameter with type `i32`
+
+error[E0053]: method `bbbb` has an incompatible generic parameter for trait: `Aaaaaa`
+  --> $DIR/mismatched_ty_const_in_trait_impl.rs:29:13
    |
-note: the const parameter `N` has type `i32`, but the declaration in trait `Uwu::baz` has type `u32`
-  --> $DIR/mismatched_ty_const_in_trait_impl.rs:18:12
+LL | trait Aaaaaa {
+   |       ------
+LL |     fn bbbb<const N: u32, T>() {}
+   |             ------------ expected const parameter with type `u32`
+LL | }
+LL | impl Aaaaaa for () {
+   | ------------------
+LL |     fn bbbb<T, const N: u32>() {}
+   |             ^ found type parameter
+
+error[E0053]: method `abcd` has an incompatible generic parameter for trait: `Names`
+  --> $DIR/mismatched_ty_const_in_trait_impl.rs:37:13
    |
-LL |     fn baz<const N: u32>() {}
-   |            ^^^^^^^^^^^^
+LL | trait Names {
+   |       -----
+LL |     fn abcd<T, const N: u32>() {}
+   |             - expected type parameter
+LL | }
+LL | impl Names for () {
+   | -----------------
+LL |     fn abcd<const N: u32, T>() {}
+   |             ^^^^^^^^^^^^ found const parameter with type `u32`
 
-error: aborting due to 3 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0053`.
diff --git a/src/test/ui/const-generics/issues/issue-86820.rs b/src/test/ui/const-generics/issues/issue-86820.rs
index 04650403c6b..9bcb8e1aeed 100644
--- a/src/test/ui/const-generics/issues/issue-86820.rs
+++ b/src/test/ui/const-generics/issues/issue-86820.rs
@@ -1,6 +1,6 @@
 // Regression test for the ICE described in #86820.
 
-#![allow(unused,dead_code)]
+#![allow(unused, dead_code)]
 use std::ops::BitAnd;
 
 const C: fn() = || is_set();
@@ -9,13 +9,12 @@ fn is_set() {
 }
 
 trait Bits {
-    fn bit<const I : u8>(self) -> bool;
-    //~^ NOTE: the const parameter `I` has type `usize`, but the declaration in trait `Bits::bit` has type `u8`
+    fn bit<const I: u8>(self) -> bool;
 }
 
 impl Bits for u8 {
-    fn bit<const I : usize>(self) -> bool {
-    //~^ ERROR: method `bit` has an incompatible const parameter type for trait [E0053]
+    fn bit<const I: usize>(self) -> bool {
+        //~^ ERROR: method `bit` has an incompatible generic parameter for trait: `Bits` [E0053]
         let i = 1 << I;
         let mask = u8::from(i);
         mask & self == mask
diff --git a/src/test/ui/const-generics/issues/issue-86820.stderr b/src/test/ui/const-generics/issues/issue-86820.stderr
index f7b8d80eeca..4d54d654c12 100644
--- a/src/test/ui/const-generics/issues/issue-86820.stderr
+++ b/src/test/ui/const-generics/issues/issue-86820.stderr
@@ -1,14 +1,15 @@
-error[E0053]: method `bit` has an incompatible const parameter type for trait
-  --> $DIR/issue-86820.rs:17:12
+error[E0053]: method `bit` has an incompatible generic parameter for trait: `Bits`
+  --> $DIR/issue-86820.rs:16:12
    |
-LL |     fn bit<const I : usize>(self) -> bool {
-   |            ^^^^^^^^^^^^^^^
-   |
-note: the const parameter `I` has type `usize`, but the declaration in trait `Bits::bit` has type `u8`
-  --> $DIR/issue-86820.rs:12:12
-   |
-LL |     fn bit<const I : u8>(self) -> bool;
-   |            ^^^^^^^^^^^^
+LL | trait Bits {
+   |       ----
+LL |     fn bit<const I: u8>(self) -> bool;
+   |            ----------- expected const parameter with type `u8`
+...
+LL | impl Bits for u8 {
+   | ----------------
+LL |     fn bit<const I: usize>(self) -> bool {
+   |            ^^^^^^^^^^^^^^ found const parameter with type `usize`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/generic-associated-types/const_params_have_right_type.rs b/src/test/ui/generic-associated-types/const_params_have_right_type.rs
index 138d332eed4..6bed8e3aff9 100644
--- a/src/test/ui/generic-associated-types/const_params_have_right_type.rs
+++ b/src/test/ui/generic-associated-types/const_params_have_right_type.rs
@@ -6,7 +6,7 @@ trait Trait {
 
 impl Trait for () {
     type Foo<const N: u64> = u32;
-    //~^ error: type `Foo` has an incompatible const parameter type
+    //~^ error: type `Foo` has an incompatible generic parameter for trait
 }
 
 fn main() {}
diff --git a/src/test/ui/generic-associated-types/const_params_have_right_type.stderr b/src/test/ui/generic-associated-types/const_params_have_right_type.stderr
index 4ec6c19f54b..9b8eddaff41 100644
--- a/src/test/ui/generic-associated-types/const_params_have_right_type.stderr
+++ b/src/test/ui/generic-associated-types/const_params_have_right_type.stderr
@@ -1,14 +1,15 @@
-error[E0053]: type `Foo` has an incompatible const parameter type for trait
+error[E0053]: type `Foo` has an incompatible generic parameter for trait: `Trait`
   --> $DIR/const_params_have_right_type.rs:8:14
    |
-LL |     type Foo<const N: u64> = u32;
-   |              ^^^^^^^^^^^^
-   |
-note: the const parameter `N` has type `u64`, but the declaration in trait `Trait::Foo` has type `u8`
-  --> $DIR/const_params_have_right_type.rs:4:14
-   |
+LL | trait Trait {
+   |       -----
 LL |     type Foo<const N: u8>;
-   |              ^^^^^^^^^^^
+   |              ----------- expected const parameter with type `u8`
+...
+LL | impl Trait for () {
+   | -----------------
+LL |     type Foo<const N: u64> = u32;
+   |              ^^^^^^^^^^^^ found const parameter with type `u64`
 
 error: aborting due to previous error