Add E0790 as more specific variant of E0283

This commit is contained in:
aticu 2022-06-12 17:46:57 +02:00
parent 96c2df810b
commit 1cbacc0c8a
21 changed files with 354 additions and 92 deletions

View File

@ -492,6 +492,7 @@ E0785: include_str!("./error_codes/E0785.md"),
E0786: include_str!("./error_codes/E0786.md"),
E0787: include_str!("./error_codes/E0787.md"),
E0788: include_str!("./error_codes/E0788.md"),
E0790: include_str!("./error_codes/E0790.md"),
;
// E0006, // merged with E0005
// E0008, // cannot bind by-move into a pattern guard

View File

@ -3,48 +3,31 @@ An implementation cannot be chosen unambiguously because of lack of information.
Erroneous code example:
```compile_fail,E0283
trait Generator {
fn create() -> u32;
}
struct Foo;
struct Impl;
impl Generator for Impl {
fn create() -> u32 { 1 }
}
struct AnotherImpl;
impl Generator for AnotherImpl {
fn create() -> u32 { 2 }
impl Into<u32> for Foo {
fn into(self) -> u32 { 1 }
}
fn main() {
let cont: u32 = Generator::create();
// error, impossible to choose one of Generator trait implementation
// Should it be Impl or AnotherImpl, maybe something else?
let foo = Foo;
let bar: u32 = foo.into() * 1u32;
}
```
This error can be solved by adding type annotations that provide the missing
information to the compiler. In this case, the solution is to use a concrete
type:
information to the compiler. In this case, the solution is to specify the
fully-qualified method:
```
trait Generator {
fn create() -> u32;
}
struct Foo;
struct AnotherImpl;
impl Generator for AnotherImpl {
fn create() -> u32 { 2 }
impl Into<u32> for Foo {
fn into(self) -> u32 { 1 }
}
fn main() {
let gen1 = AnotherImpl::create();
// if there are multiple methods with same name (different traits)
let gen2 = <AnotherImpl as Generator>::create();
let foo = Foo;
let bar: u32 = <Foo as Into<u32>>::into(foo) * 1u32;
}
```

View File

@ -0,0 +1,51 @@
You need to specify a specific implementation of the trait in order to call the
method.
Erroneous code example:
```compile_fail,E0790
trait Generator {
fn create() -> u32;
}
struct Impl;
impl Generator for Impl {
fn create() -> u32 { 1 }
}
struct AnotherImpl;
impl Generator for AnotherImpl {
fn create() -> u32 { 2 }
}
fn main() {
let cont: u32 = Generator::create();
// error, impossible to choose one of Generator trait implementation
// Should it be Impl or AnotherImpl, maybe something else?
}
```
This error can be solved by adding type annotations that provide the missing
information to the compiler. In this case, the solution is to use a concrete
type:
```
trait Generator {
fn create() -> u32;
}
struct AnotherImpl;
impl Generator for AnotherImpl {
fn create() -> u32 { 2 }
}
fn main() {
let gen1 = AnotherImpl::create();
// if there are multiple methods with same name (different traits)
let gen2 = <AnotherImpl as Generator>::create();
}
```

View File

@ -74,6 +74,10 @@ impl TraitImpls {
pub fn blanket_impls(&self) -> &[DefId] {
self.blanket_impls.as_slice()
}
pub fn non_blanket_impls(&self) -> &FxIndexMap<SimplifiedType, Vec<DefId>> {
&self.non_blanket_impls
}
}
impl<'tcx> TraitDef {

View File

@ -2104,6 +2104,98 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
);
}
}
if let (Some(body_id), Some(ty::subst::GenericArgKind::Type(_))) =
(body_id, subst.map(|subst| subst.unpack()))
{
struct FindExprBySpan<'hir> {
span: Span,
result: Option<&'hir hir::Expr<'hir>>,
}
impl<'v> hir::intravisit::Visitor<'v> for FindExprBySpan<'v> {
fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
if self.span == ex.span {
self.result = Some(ex);
} else {
hir::intravisit::walk_expr(self, ex);
}
}
}
let mut expr_finder = FindExprBySpan { span, result: None };
expr_finder.visit_expr(&self.tcx.hir().body(body_id).value);
if let Some(hir::Expr {
kind: hir::ExprKind::Path(hir::QPath::Resolved(None, path)), .. }
) = expr_finder.result
&& let [
..,
trait_path_segment @ hir::PathSegment {
res: Some(rustc_hir::def::Res::Def(rustc_hir::def::DefKind::Trait, trait_id)),
..
},
hir::PathSegment {
ident: assoc_item_name,
res: Some(rustc_hir::def::Res::Def(_, item_id)),
..
}
] = path.segments
&& data.trait_ref.def_id == *trait_id
&& self.tcx.trait_of_item(item_id) == Some(*trait_id)
&& !self.is_tainted_by_errors()
{
let (verb, noun) = match self.tcx.associated_item(item_id).kind {
ty::AssocKind::Const => ("refer to the", "constant"),
ty::AssocKind::Fn => ("call", "function"),
ty::AssocKind::Type => ("refer to the", "type"), // this is already covered by E0223, but this single match arm doesn't hurt here
};
// Replace the more general E0283 with a more specific error
err.cancel();
err = self.tcx.sess.struct_span_err_with_code(
span,
&format!(
"cannot {verb} associated {noun} on trait without specifying the corresponding `impl` type",
),
rustc_errors::error_code!(E0790),
);
if let Some(local_def_id) = data.trait_ref.def_id.as_local()
&& let Some(hir::Node::Item(hir::Item { ident: trait_name, kind: hir::ItemKind::Trait(_, _, _, _, trait_item_refs), .. })) = self.tcx.hir().find_by_def_id(local_def_id)
&& let Some(method_ref) = trait_item_refs.iter().find(|item_ref| item_ref.ident == *assoc_item_name) {
err.span_label(method_ref.span, format!("`{}::{}` defined here", trait_name, assoc_item_name));
}
err.span_label(span, format!("cannot {verb} associated {noun} of trait"));
let trait_impls = self.tcx.trait_impls_of(data.trait_ref.def_id);
if trait_impls.blanket_impls().is_empty()
&& let Some((impl_ty, _)) = trait_impls.non_blanket_impls().iter().next()
&& let Some(impl_def_id) = impl_ty.def() {
let message = if trait_impls.non_blanket_impls().len() == 1 {
"use the fully-qualified path to the only available implementation".to_string()
} else {
format!(
"use a fully-qualified path to a specific available implementation ({} found)",
trait_impls.non_blanket_impls().len()
)
};
err.multipart_suggestion(
message,
vec![
(trait_path_segment.ident.span.shrink_to_lo(), format!("<{} as ", self.tcx.def_path(impl_def_id).to_string_no_crate_verbose())),
(trait_path_segment.ident.span.shrink_to_hi(), format!(">"))
],
Applicability::MaybeIncorrect
);
}
}
};
err
}

View File

@ -2,8 +2,8 @@ trait A {
const C: usize;
fn f() -> ([u8; A::C], [u8; A::C]);
//~^ ERROR: type annotations needed
//~| ERROR: type annotations needed
//~^ ERROR: E0790
//~| ERROR: E0790
}
fn main() {}

View File

@ -1,27 +1,21 @@
error[E0283]: type annotations needed
error[E0790]: cannot refer to the associated constant on trait without specifying the corresponding `impl` type
--> $DIR/issue-63496.rs:4:21
|
LL | const C: usize;
| --------------- `A::C` defined here
LL |
LL | fn f() -> ([u8; A::C], [u8; A::C]);
| ^^^^
| |
| cannot infer type
| help: use the fully qualified path to an implementation: `<Type as A>::C`
|
= note: cannot satisfy `_: A`
= note: associated constants cannot be accessed directly on a `trait`, they can only be accessed through a specific `impl`
| ^^^^ cannot refer to the associated constant of trait
error[E0283]: type annotations needed
error[E0790]: cannot refer to the associated constant on trait without specifying the corresponding `impl` type
--> $DIR/issue-63496.rs:4:33
|
LL | const C: usize;
| --------------- `A::C` defined here
LL |
LL | fn f() -> ([u8; A::C], [u8; A::C]);
| ^^^^
| |
| cannot infer type
| help: use the fully qualified path to an implementation: `<Type as A>::C`
|
= note: cannot satisfy `_: A`
= note: associated constants cannot be accessed directly on a `trait`, they can only be accessed through a specific `impl`
| ^^^^ cannot refer to the associated constant of trait
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0283`.
For more information about this error, try `rustc --explain E0790`.

View File

@ -1,6 +1,6 @@
trait Bar {
const X: usize;
fn return_n(&self) -> [u8; Bar::X]; //~ ERROR: type annotations needed
fn return_n(&self) -> [u8; Bar::X]; //~ ERROR: E0790
}
impl dyn Bar {} //~ ERROR: the trait `Bar` cannot be made into an object

View File

@ -13,19 +13,15 @@ LL | const X: usize;
| ^ ...because it contains this associated `const`
= help: consider moving `X` to another trait
error[E0283]: type annotations needed
error[E0790]: cannot refer to the associated constant on trait without specifying the corresponding `impl` type
--> $DIR/issue-48027.rs:3:32
|
LL | const X: usize;
| --------------- `Bar::X` defined here
LL | fn return_n(&self) -> [u8; Bar::X];
| ^^^^^^
| |
| cannot infer type
| help: use the fully qualified path to an implementation: `<Type as Bar>::X`
|
= note: cannot satisfy `_: Bar`
= note: associated constants cannot be accessed directly on a `trait`, they can only be accessed through a specific `impl`
| ^^^^^^ cannot refer to the associated constant of trait
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0038, E0283.
Some errors have detailed explanations: E0038, E0790.
For more information about an error, try `rustc --explain E0038`.

View File

@ -12,5 +12,5 @@ impl Foo for isize {
pub fn main() {
let x: isize = Foo::bar();
//~^ ERROR type annotations needed
//~^ ERROR E0790
}

View File

@ -1,11 +1,12 @@
error[E0283]: type annotations needed
error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type
--> $DIR/associated-types-unconstrained.rs:14:20
|
LL | fn bar() -> isize;
| ------------------ `Foo::bar` defined here
...
LL | let x: isize = Foo::bar();
| ^^^^^^^^ cannot infer type
|
= note: cannot satisfy `_: Foo`
| ^^^^^^^^ cannot call associated function of trait
error: aborting due to previous error
For more information about this error, try `rustc --explain E0283`.
For more information about this error, try `rustc --explain E0790`.

View File

@ -27,7 +27,7 @@ impl Generator for AnotherImpl {
}
fn main() {
let cont: u32 = Generator::create(); //~ ERROR E0283
let cont: u32 = Generator::create(); //~ ERROR E0790
}
fn buzz() {

View File

@ -1,10 +1,16 @@
error[E0283]: type annotations needed
error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type
--> $DIR/E0283.rs:30:21
|
LL | fn create() -> u32;
| ------------------- `Generator::create` defined here
...
LL | let cont: u32 = Generator::create();
| ^^^^^^^^^^^^^^^^^ cannot infer type
| ^^^^^^^^^^^^^^^^^ cannot call associated function of trait
|
= note: cannot satisfy `_: Generator`
help: use a fully-qualified path to a specific available implementation (2 found)
|
LL | let cont: u32 = <::Impl as Generator>::create();
| ++++++++++ +
error[E0283]: type annotations needed
--> $DIR/E0283.rs:35:24
@ -27,4 +33,5 @@ LL | let bar = <Impl as Into<T>>::into(foo_impl) * 1u32;
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0283`.
Some errors have detailed explanations: E0283, E0790.
For more information about an error, try `rustc --explain E0283`.

View File

@ -0,0 +1,53 @@
mod inner {
pub trait MyTrait {
const MY_ASSOC_CONST: ();
fn my_fn();
}
pub struct MyStruct;
impl MyTrait for MyStruct {
const MY_ASSOC_CONST: () = ();
fn my_fn() {}
}
fn call() {
MyTrait::my_fn(); //~ ERROR E0790
}
fn use_const() {
let _ = MyTrait::MY_ASSOC_CONST; //~ ERROR E0790
}
}
fn call_inner() {
inner::MyTrait::my_fn(); //~ ERROR E0790
}
fn use_const_inner() {
let _ = inner::MyTrait::MY_ASSOC_CONST; //~ ERROR E0790
}
trait MyTrait2 {
fn my_fn();
}
struct Impl1;
impl MyTrait2 for Impl1 {
fn my_fn() {}
}
struct Impl2;
impl MyTrait2 for Impl2 {
fn my_fn() {}
}
fn call_multiple_impls() {
MyTrait2::my_fn(); //~ ERROR E0790
}
fn main() {}

View File

@ -0,0 +1,73 @@
error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type
--> $DIR/E0790.rs:17:9
|
LL | fn my_fn();
| ----------- `MyTrait::my_fn` defined here
...
LL | MyTrait::my_fn();
| ^^^^^^^^^^^^^^ cannot call associated function of trait
|
help: use the fully-qualified path to the only available implementation
|
LL | <::inner::MyStruct as MyTrait>::my_fn();
| +++++++++++++++++++++ +
error[E0790]: cannot refer to the associated constant on trait without specifying the corresponding `impl` type
--> $DIR/E0790.rs:21:17
|
LL | const MY_ASSOC_CONST: ();
| ------------------------- `MyTrait::MY_ASSOC_CONST` defined here
...
LL | let _ = MyTrait::MY_ASSOC_CONST;
| ^^^^^^^^^^^^^^^^^^^^^^^ cannot refer to the associated constant of trait
|
help: use the fully-qualified path to the only available implementation
|
LL | let _ = <::inner::MyStruct as MyTrait>::MY_ASSOC_CONST;
| +++++++++++++++++++++ +
error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type
--> $DIR/E0790.rs:26:5
|
LL | fn my_fn();
| ----------- `MyTrait::my_fn` defined here
...
LL | inner::MyTrait::my_fn();
| ^^^^^^^^^^^^^^^^^^^^^ cannot call associated function of trait
|
help: use the fully-qualified path to the only available implementation
|
LL | inner::<::inner::MyStruct as MyTrait>::my_fn();
| +++++++++++++++++++++ +
error[E0790]: cannot refer to the associated constant on trait without specifying the corresponding `impl` type
--> $DIR/E0790.rs:30:13
|
LL | const MY_ASSOC_CONST: ();
| ------------------------- `MyTrait::MY_ASSOC_CONST` defined here
...
LL | let _ = inner::MyTrait::MY_ASSOC_CONST;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot refer to the associated constant of trait
|
help: use the fully-qualified path to the only available implementation
|
LL | let _ = inner::<::inner::MyStruct as MyTrait>::MY_ASSOC_CONST;
| +++++++++++++++++++++ +
error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type
--> $DIR/E0790.rs:50:5
|
LL | fn my_fn();
| ----------- `MyTrait2::my_fn` defined here
...
LL | MyTrait2::my_fn();
| ^^^^^^^^^^^^^^^ cannot call associated function of trait
|
help: use a fully-qualified path to a specific available implementation (2 found)
|
LL | <::Impl1 as MyTrait2>::my_fn();
| +++++++++++ +
error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0790`.

View File

@ -1,5 +1,5 @@
const ARR_LEN: usize = Tt::const_val::<[i8; 123]>();
//~^ ERROR type annotations needed
//~^ ERROR E0790
trait Tt {
const fn const_val<T: Sized>() -> usize {

View File

@ -4,13 +4,17 @@ error[E0379]: functions in traits cannot be declared const
LL | const fn const_val<T: Sized>() -> usize {
| ^^^^^ functions in traits cannot be const
error[E0283]: type annotations needed
error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type
--> $DIR/issue-54954.rs:1:24
|
LL | const ARR_LEN: usize = Tt::const_val::<[i8; 123]>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type
|
= note: cannot satisfy `_: Tt`
LL | const ARR_LEN: usize = Tt::const_val::<[i8; 123]>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot call associated function of trait
...
LL | / const fn const_val<T: Sized>() -> usize {
LL | |
LL | | core::mem::size_of::<T>()
LL | | }
| |_____- `Tt::const_val` defined here
error[E0080]: evaluation of constant value failed
--> $DIR/issue-54954.rs:11:15
@ -26,5 +30,5 @@ LL | fn f(z: [f32; ARR_LEN]) -> [f32; ARR_LEN] {
error: aborting due to 4 previous errors
Some errors have detailed explanations: E0080, E0283, E0379.
Some errors have detailed explanations: E0080, E0379, E0790.
For more information about an error, try `rustc --explain E0080`.

View File

@ -2,7 +2,7 @@ pub trait Foo: Sized {
const SIZE: usize;
fn new(slice: &[u8; Foo::SIZE]) -> Self;
//~^ ERROR: type annotations needed
//~^ ERROR: E0790
}
pub struct Bar<T: ?Sized>(T);

View File

@ -4,19 +4,16 @@ error[E0423]: expected function, tuple struct or tuple variant, found trait `Foo
LL | Foo(Box::new(*slice))
| ^^^ not a function, tuple struct or tuple variant
error[E0283]: type annotations needed
error[E0790]: cannot refer to the associated constant on trait without specifying the corresponding `impl` type
--> $DIR/issue-58022.rs:4:25
|
LL | const SIZE: usize;
| ------------------ `Foo::SIZE` defined here
LL |
LL | fn new(slice: &[u8; Foo::SIZE]) -> Self;
| ^^^^^^^^^
| |
| cannot infer type
| help: use the fully qualified path to an implementation: `<Type as Foo>::SIZE`
|
= note: cannot satisfy `_: Foo`
= note: associated constants cannot be accessed directly on a `trait`, they can only be accessed through a specific `impl`
| ^^^^^^^^^ cannot refer to the associated constant of trait
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0283, E0423.
For more information about an error, try `rustc --explain E0283`.
Some errors have detailed explanations: E0423, E0790.
For more information about an error, try `rustc --explain E0423`.

View File

@ -22,7 +22,7 @@ mod base {
pub fn foo() {
let _f: base::Foo = base::HasNew::new();
//~^ ERROR type annotations needed
//~^ ERROR E0790
}
fn main() { }

View File

@ -1,11 +1,17 @@
error[E0283]: type annotations needed
error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type
--> $DIR/static-method-generic-inference.rs:24:25
|
LL | fn new() -> T;
| -------------- `HasNew::new` defined here
...
LL | let _f: base::Foo = base::HasNew::new();
| ^^^^^^^^^^^^^^^^^ cannot infer type
| ^^^^^^^^^^^^^^^^^ cannot call associated function of trait
|
= note: cannot satisfy `_: HasNew<Foo>`
help: use the fully-qualified path to the only available implementation
|
LL | let _f: base::Foo = base::<::base::Foo as HasNew>::new();
| +++++++++++++++ +
error: aborting due to previous error
For more information about this error, try `rustc --explain E0283`.
For more information about this error, try `rustc --explain E0790`.