1
Fork 0

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"), E0786: include_str!("./error_codes/E0786.md"),
E0787: include_str!("./error_codes/E0787.md"), E0787: include_str!("./error_codes/E0787.md"),
E0788: include_str!("./error_codes/E0788.md"), E0788: include_str!("./error_codes/E0788.md"),
E0790: include_str!("./error_codes/E0790.md"),
; ;
// E0006, // merged with E0005 // E0006, // merged with E0005
// E0008, // cannot bind by-move into a pattern guard // 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: Erroneous code example:
```compile_fail,E0283 ```compile_fail,E0283
trait Generator { struct Foo;
fn create() -> u32;
}
struct Impl; impl Into<u32> for Foo {
fn into(self) -> u32 { 1 }
impl Generator for Impl {
fn create() -> u32 { 1 }
}
struct AnotherImpl;
impl Generator for AnotherImpl {
fn create() -> u32 { 2 }
} }
fn main() { fn main() {
let cont: u32 = Generator::create(); let foo = Foo;
// error, impossible to choose one of Generator trait implementation let bar: u32 = foo.into() * 1u32;
// Should it be Impl or AnotherImpl, maybe something else?
} }
``` ```
This error can be solved by adding type annotations that provide the missing 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 information to the compiler. In this case, the solution is to specify the
type: fully-qualified method:
``` ```
trait Generator { struct Foo;
fn create() -> u32;
}
struct AnotherImpl; impl Into<u32> for Foo {
fn into(self) -> u32 { 1 }
impl Generator for AnotherImpl {
fn create() -> u32 { 2 }
} }
fn main() { fn main() {
let gen1 = AnotherImpl::create(); let foo = Foo;
let bar: u32 = <Foo as Into<u32>>::into(foo) * 1u32;
// if there are multiple methods with same name (different traits)
let gen2 = <AnotherImpl as Generator>::create();
} }
``` ```

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] { pub fn blanket_impls(&self) -> &[DefId] {
self.blanket_impls.as_slice() self.blanket_impls.as_slice()
} }
pub fn non_blanket_impls(&self) -> &FxIndexMap<SimplifiedType, Vec<DefId>> {
&self.non_blanket_impls
}
} }
impl<'tcx> TraitDef { 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 err
} }

View file

@ -2,8 +2,8 @@ trait A {
const C: usize; const C: usize;
fn f() -> ([u8; A::C], [u8; A::C]); fn f() -> ([u8; A::C], [u8; A::C]);
//~^ ERROR: type annotations needed //~^ ERROR: E0790
//~| ERROR: type annotations needed //~| ERROR: E0790
} }
fn main() {} 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 --> $DIR/issue-63496.rs:4:21
| |
LL | const C: usize;
| --------------- `A::C` defined here
LL |
LL | fn f() -> ([u8; A::C], [u8; A::C]); LL | fn f() -> ([u8; A::C], [u8; A::C]);
| ^^^^ | ^^^^ cannot refer to the associated constant of trait
| |
| 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`
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 --> $DIR/issue-63496.rs:4:33
| |
LL | const C: usize;
| --------------- `A::C` defined here
LL |
LL | fn f() -> ([u8; A::C], [u8; A::C]); LL | fn f() -> ([u8; A::C], [u8; A::C]);
| ^^^^ | ^^^^ cannot refer to the associated constant of trait
| |
| 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`
error: aborting due to 2 previous errors 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 { trait Bar {
const X: usize; 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 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` | ^ ...because it contains this associated `const`
= help: consider moving `X` to another trait = 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 --> $DIR/issue-48027.rs:3:32
| |
LL | const X: usize;
| --------------- `Bar::X` defined here
LL | fn return_n(&self) -> [u8; Bar::X]; LL | fn return_n(&self) -> [u8; Bar::X];
| ^^^^^^ | ^^^^^^ cannot refer to the associated constant of trait
| |
| 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`
error: aborting due to 2 previous errors 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`. For more information about an error, try `rustc --explain E0038`.

View file

@ -12,5 +12,5 @@ impl Foo for isize {
pub fn main() { pub fn main() {
let x: isize = Foo::bar(); 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 --> $DIR/associated-types-unconstrained.rs:14:20
| |
LL | fn bar() -> isize;
| ------------------ `Foo::bar` defined here
...
LL | let x: isize = Foo::bar(); LL | let x: isize = Foo::bar();
| ^^^^^^^^ cannot infer type | ^^^^^^^^ cannot call associated function of trait
|
= note: cannot satisfy `_: Foo`
error: aborting due to previous error 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() { fn main() {
let cont: u32 = Generator::create(); //~ ERROR E0283 let cont: u32 = Generator::create(); //~ ERROR E0790
} }
fn buzz() { 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 --> $DIR/E0283.rs:30:21
| |
LL | fn create() -> u32;
| ------------------- `Generator::create` defined here
...
LL | let cont: u32 = Generator::create(); 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 error[E0283]: type annotations needed
--> $DIR/E0283.rs:35:24 --> $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 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]>(); const ARR_LEN: usize = Tt::const_val::<[i8; 123]>();
//~^ ERROR type annotations needed //~^ ERROR E0790
trait Tt { trait Tt {
const fn const_val<T: Sized>() -> usize { 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 { LL | const fn const_val<T: Sized>() -> usize {
| ^^^^^ functions in traits cannot be const | ^^^^^ 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 --> $DIR/issue-54954.rs:1:24
| |
LL | const ARR_LEN: usize = Tt::const_val::<[i8; 123]>(); LL | const ARR_LEN: usize = Tt::const_val::<[i8; 123]>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot call associated function of trait
| ...
= note: cannot satisfy `_: Tt` 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 error[E0080]: evaluation of constant value failed
--> $DIR/issue-54954.rs:11:15 --> $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 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`. For more information about an error, try `rustc --explain E0080`.

View file

@ -2,7 +2,7 @@ pub trait Foo: Sized {
const SIZE: usize; const SIZE: usize;
fn new(slice: &[u8; Foo::SIZE]) -> Self; fn new(slice: &[u8; Foo::SIZE]) -> Self;
//~^ ERROR: type annotations needed //~^ ERROR: E0790
} }
pub struct Bar<T: ?Sized>(T); 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)) LL | Foo(Box::new(*slice))
| ^^^ not a function, tuple struct or tuple variant | ^^^ 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 --> $DIR/issue-58022.rs:4:25
| |
LL | const SIZE: usize;
| ------------------ `Foo::SIZE` defined here
LL |
LL | fn new(slice: &[u8; Foo::SIZE]) -> Self; LL | fn new(slice: &[u8; Foo::SIZE]) -> Self;
| ^^^^^^^^^ | ^^^^^^^^^ cannot refer to the associated constant of trait
| |
| 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`
error: aborting due to 2 previous errors error: aborting due to 2 previous errors
Some errors have detailed explanations: E0283, E0423. Some errors have detailed explanations: E0423, E0790.
For more information about an error, try `rustc --explain E0283`. For more information about an error, try `rustc --explain E0423`.

View file

@ -22,7 +22,7 @@ mod base {
pub fn foo() { pub fn foo() {
let _f: base::Foo = base::HasNew::new(); let _f: base::Foo = base::HasNew::new();
//~^ ERROR type annotations needed //~^ ERROR E0790
} }
fn main() { } 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 --> $DIR/static-method-generic-inference.rs:24:25
| |
LL | fn new() -> T;
| -------------- `HasNew::new` defined here
...
LL | let _f: base::Foo = base::HasNew::new(); 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 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`.