Skip to content

Commit

Permalink
Suggest using type args directly
Browse files Browse the repository at this point in the history
when they are written wrongly using an equality constraint
  • Loading branch information
gurry committed Mar 16, 2024
1 parent dc2ffa4 commit d29a5a1
Show file tree
Hide file tree
Showing 11 changed files with 181 additions and 16 deletions.
17 changes: 14 additions & 3 deletions compiler/rustc_hir_analysis/src/astconv/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -920,11 +920,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
/// Emits an error regarding forbidden type binding associations
pub fn prohibit_assoc_ty_binding(
tcx: TyCtxt<'_>,
span: Span,
binding: &hir::TypeBinding<'_>,
segment: Option<(&hir::PathSegment<'_>, Span)>,
) {
tcx.dcx().emit_err(AssocTypeBindingNotAllowed {
span,
let mut err = tcx.dcx().create_err(AssocTypeBindingNotAllowed {
span: binding.span,
fn_trait_expansion: if let Some((segment, span)) = segment
&& segment.args().parenthesized == hir::GenericArgsParentheses::ParenSugar
{
Expand All @@ -936,6 +936,17 @@ pub fn prohibit_assoc_ty_binding(
None
},
});

if let Some((segment, _)) = segment
&& segment.args().parenthesized == hir::GenericArgsParentheses::No
&& let hir::TypeBindingKind::Equality { term: hir::Term::Ty(ty) } = binding.kind
&& let Ok(ty) = tcx.sess.source_map().span_to_snippet(ty.span)
{
let msg = format!("to use `{ty}` as a generic argument specify it directly");
err.span_suggestion_verbose(binding.span, msg, ty, Applicability::MaybeIncorrect);
}

err.emit();
}

pub(crate) fn fn_trait_to_string(
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/astconv/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ pub(crate) fn check_generic_arg_count(
if gen_pos != GenericArgPosition::Type
&& let Some(b) = gen_args.bindings.first()
{
prohibit_assoc_ty_binding(tcx, b.span, None);
prohibit_assoc_ty_binding(tcx, b, None);
}

let explicit_late_bound =
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_hir_analysis/src/astconv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
ty::BoundConstness::NotConst,
);
if let Some(b) = item_segment.args().bindings.first() {
prohibit_assoc_ty_binding(self.tcx(), b.span, Some((item_segment, span)));
prohibit_assoc_ty_binding(self.tcx(), b, Some((item_segment, span)));
}

args
Expand Down Expand Up @@ -599,7 +599,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
);

if let Some(b) = item_segment.args().bindings.first() {
prohibit_assoc_ty_binding(self.tcx(), b.span, Some((item_segment, span)));
prohibit_assoc_ty_binding(self.tcx(), b, Some((item_segment, span)));
}

args
Expand Down Expand Up @@ -738,7 +738,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
constness,
);
if let Some(b) = trait_segment.args().bindings.first() {
prohibit_assoc_ty_binding(self.tcx(), b.span, Some((trait_segment, span)));
prohibit_assoc_ty_binding(self.tcx(), b, Some((trait_segment, span)));
}
ty::TraitRef::new(self.tcx(), trait_def_id, generic_args)
}
Expand Down Expand Up @@ -1820,7 +1820,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
for segment in segments {
// Only emit the first error to avoid overloading the user with error messages.
if let Some(b) = segment.args().bindings.first() {
prohibit_assoc_ty_binding(self.tcx(), b.span, None);
prohibit_assoc_ty_binding(self.tcx(), b, None);
return true;
}
}
Expand Down
5 changes: 5 additions & 0 deletions tests/ui/associated-type-bounds/issue-102335-ty.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ error[E0229]: associated type bindings are not allowed here
|
LL | type A: S<C<i32 = u32> = ()>;
| ^^^^^^^^^ associated type not allowed here
|
help: to use `u32` as a generic argument specify it directly
|
LL | type A: S<C<u32> = ()>;
| ~~~

error: aborting due to 1 previous error

Expand Down
33 changes: 31 additions & 2 deletions tests/ui/associated-types/associated-types-eq-2.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,48 @@
// Test equality constraints on associated types. Check we get an error when an
// equality constraint is used in a qualified path.
// equality constraint is used outside of type parameter declarations

pub trait Foo {
type A;
fn boo(&self) -> <Self as Foo>::A;
}

struct Bar;
struct Qux;

impl Foo for isize {
type A = usize;
fn boo(&self) -> usize { 42 }
}

fn baz<I: Foo>(x: &<I as Foo<A=Bar>>::A) {}
fn baz<I: Foo>(_x: &<I as Foo<A=Bar>>::A) {}
//~^ ERROR associated type bindings are not allowed here


trait Tr1<T1> {
}

impl Tr1<T1 = String> for Bar {
//~^ ERROR associated type bindings are not allowed here
//~| ERROR trait takes 1 generic argument but 0 generic arguments were supplied
}

trait Tr3<T1, T2, T3> {
}

// E0229 is emitted only for the first erroneous equality
// constraint (T2) not for any subequent ones (e.g. T3)
impl Tr3<i32, T2 = Qux, T3 = usize> for Bar {
//~^ ERROR associated type bindings are not allowed here
//~| ERROR trait takes 3 generic arguments but 1 generic argument was supplied
}


struct Generic<T> { _t: T }

impl Tr3<i32, Qux, T3 = Generic<i32>> for Bar {
//~^ ERROR associated type bindings are not allowed here
//~| ERROR trait takes 3 generic arguments but 2 generic arguments were supplied
}


pub fn main() {}
101 changes: 96 additions & 5 deletions tests/ui/associated-types/associated-types-eq-2.stderr
Original file line number Diff line number Diff line change
@@ -1,9 +1,100 @@
error[E0229]: associated type bindings are not allowed here
--> $DIR/associated-types-eq-2.rs:16:30
--> $DIR/associated-types-eq-2.rs:17:31
|
LL | fn baz<I: Foo>(x: &<I as Foo<A=Bar>>::A) {}
| ^^^^^ associated type not allowed here
LL | fn baz<I: Foo>(_x: &<I as Foo<A=Bar>>::A) {}
| ^^^^^ associated type not allowed here
|
help: to use `Bar` as a generic argument specify it directly
|
LL | fn baz<I: Foo>(_x: &<I as Foo<Bar>>::A) {}
| ~~~

error[E0107]: trait takes 1 generic argument but 0 generic arguments were supplied
--> $DIR/associated-types-eq-2.rs:24:6
|
LL | impl Tr1<T1 = String> for Bar {
| ^^^ expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `T1`
--> $DIR/associated-types-eq-2.rs:21:7
|
LL | trait Tr1<T1> {
| ^^^ --
help: add missing generic argument
|
LL | impl Tr1<T1, T1 = String> for Bar {
| +++

error[E0229]: associated type bindings are not allowed here
--> $DIR/associated-types-eq-2.rs:24:10
|
LL | impl Tr1<T1 = String> for Bar {
| ^^^^^^^^^^^ associated type not allowed here
|
help: to use `String` as a generic argument specify it directly
|
LL | impl Tr1<String> for Bar {
| ~~~~~~

error[E0107]: trait takes 3 generic arguments but 1 generic argument was supplied
--> $DIR/associated-types-eq-2.rs:34:6
|
LL | impl Tr3<i32, T2 = Qux, T3 = usize> for Bar {
| ^^^ --- supplied 1 generic argument
| |
| expected 3 generic arguments
|
note: trait defined here, with 3 generic parameters: `T1`, `T2`, `T3`
--> $DIR/associated-types-eq-2.rs:29:7
|
LL | trait Tr3<T1, T2, T3> {
| ^^^ -- -- --
help: add missing generic arguments
|
LL | impl Tr3<i32, T2, T3, T2 = Qux, T3 = usize> for Bar {
| ++++++++

error[E0229]: associated type bindings are not allowed here
--> $DIR/associated-types-eq-2.rs:34:15
|
LL | impl Tr3<i32, T2 = Qux, T3 = usize> for Bar {
| ^^^^^^^^ associated type not allowed here
|
help: to use `Qux` as a generic argument specify it directly
|
LL | impl Tr3<i32, Qux, T3 = usize> for Bar {
| ~~~

error[E0107]: trait takes 3 generic arguments but 2 generic arguments were supplied
--> $DIR/associated-types-eq-2.rs:42:6
|
LL | impl Tr3<i32, Qux, T3 = Generic<i32>> for Bar {
| ^^^ --- --- supplied 2 generic arguments
| |
| expected 3 generic arguments
|
note: trait defined here, with 3 generic parameters: `T1`, `T2`, `T3`
--> $DIR/associated-types-eq-2.rs:29:7
|
LL | trait Tr3<T1, T2, T3> {
| ^^^ -- -- --
help: add missing generic argument
|
LL | impl Tr3<i32, Qux, T3, T3 = Generic<i32>> for Bar {
| ++++

error[E0229]: associated type bindings are not allowed here
--> $DIR/associated-types-eq-2.rs:42:20
|
LL | impl Tr3<i32, Qux, T3 = Generic<i32>> for Bar {
| ^^^^^^^^^^^^^^^^^ associated type not allowed here
|
help: to use `Generic<i32>` as a generic argument specify it directly
|
LL | impl Tr3<i32, Qux, Generic<i32>> for Bar {
| ~~~~~~~~~~~~

error: aborting due to 1 previous error
error: aborting due to 7 previous errors

For more information about this error, try `rustc --explain E0229`.
Some errors have detailed explanations: E0107, E0229.
For more information about an error, try `rustc --explain E0107`.
13 changes: 13 additions & 0 deletions tests/ui/error-codes/E0229.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ error[E0229]: associated type bindings are not allowed here
|
LL | fn baz<I>(x: &<I as Foo<A=Bar>>::A) {}
| ^^^^^ associated type not allowed here
|
help: to use `Bar` as a generic argument specify it directly
|
LL | fn baz<I>(x: &<I as Foo<Bar>>::A) {}
| ~~~

error[E0229]: associated type bindings are not allowed here
--> $DIR/E0229.rs:13:25
Expand All @@ -11,6 +16,10 @@ LL | fn baz<I>(x: &<I as Foo<A=Bar>>::A) {}
| ^^^^^ associated type not allowed here
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: to use `Bar` as a generic argument specify it directly
|
LL | fn baz<I>(x: &<I as Foo<Bar>>::A) {}
| ~~~

error[E0229]: associated type bindings are not allowed here
--> $DIR/E0229.rs:13:25
Expand All @@ -19,6 +28,10 @@ LL | fn baz<I>(x: &<I as Foo<A=Bar>>::A) {}
| ^^^^^ associated type not allowed here
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: to use `Bar` as a generic argument specify it directly
|
LL | fn baz<I>(x: &<I as Foo<Bar>>::A) {}
| ~~~

error[E0277]: the trait bound `I: Foo` is not satisfied
--> $DIR/E0229.rs:13:15
Expand Down
5 changes: 5 additions & 0 deletions tests/ui/generic-associated-types/issue-102335-gat.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ error[E0229]: associated type bindings are not allowed here
|
LL | type A: S<C<(), i32 = ()> = ()>;
| ^^^^^^^^ associated type not allowed here
|
help: to use `()` as a generic argument specify it directly
|
LL | type A: S<C<(), ()> = ()>;
| ~~

error: aborting due to 1 previous error

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ error[E0229]: associated type bindings are not allowed here
|
LL | fn bar(foo: Foo<Target = usize>) {}
| ^^^^^^^^^^^^^^ associated type not allowed here
|
help: to use `usize` as a generic argument specify it directly
|
LL | fn bar(foo: Foo<usize>) {}
| ~~~~~

error: aborting due to 1 previous error

Expand Down
3 changes: 2 additions & 1 deletion tests/ui/suggestions/issue-85347.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ use std::ops::Deref;
trait Foo {
type Bar<'a>: Deref<Target = <Self>::Bar<Target = Self>>;
//~^ ERROR associated type takes 1 lifetime argument but 0 lifetime arguments were supplied
//~| ERROR associated type bindings are not allowed here
//~| HELP add missing
//~| ERROR associated type bindings are not allowed here
//~| HELP to use `Self` as a generic argument specify it directly
}

fn main() {}
5 changes: 5 additions & 0 deletions tests/ui/suggestions/issue-85347.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ error[E0229]: associated type bindings are not allowed here
|
LL | type Bar<'a>: Deref<Target = <Self>::Bar<Target = Self>>;
| ^^^^^^^^^^^^^ associated type not allowed here
|
help: to use `Self` as a generic argument specify it directly
|
LL | type Bar<'a>: Deref<Target = <Self>::Bar<Self>>;
| ~~~~

error: aborting due to 2 previous errors

Expand Down

0 comments on commit d29a5a1

Please sign in to comment.