diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index aabbe8ac276d7..b38684a63e410 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -386,7 +386,8 @@ pub fn from_fn_attrs<'ll, 'tcx>( ) { let span = cx .tcx - .get_attr(instance.def_id(), sym::target_feature) + .get_attrs(instance.def_id(), sym::target_feature) + .next() .map_or_else(|| cx.tcx.def_span(instance.def_id()), |a| a.span); let msg = format!( "the target features {} must all be either enabled or disabled together", diff --git a/compiler/rustc_error_messages/locales/en-US/middle.ftl b/compiler/rustc_error_messages/locales/en-US/middle.ftl new file mode 100644 index 0000000000000..ed834886453ce --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/middle.ftl @@ -0,0 +1,17 @@ +middle_drop_check_overflow = + overflow while adding drop-check rules for {$ty} + .note = overflowed on {$overflow_ty} + +middle_opaque_hidden_type_mismatch = + concrete type differs from previous defining opaque type use + .label = expected `{$self_ty}`, got `{$other_ty}` + +middle_conflict_types = + this expression supplies two conflicting concrete types for the same opaque type + +middle_previous_use_here = + previous use here + +middle_limit_invalid = + `limit` must be a non-negative integer + .label = {$error_str} diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 5281a287b0dbe..b6e0f3faa73cb 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -47,6 +47,7 @@ fluent_messages! { interface => "../locales/en-US/interface.ftl", infer => "../locales/en-US/infer.ftl", lint => "../locales/en-US/lint.ftl", + middle => "../locales/en-US/middle.ftl", monomorphize => "../locales/en-US/monomorphize.ftl", metadata => "../locales/en-US/metadata.ftl", parser => "../locales/en-US/parser.ftl", diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index e359d50c4e9e5..38a02cb1d7ce9 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -823,6 +823,14 @@ pub fn is_builtin_only_local(name: Symbol) -> bool { BUILTIN_ATTRIBUTE_MAP.get(&name).map_or(false, |attr| attr.only_local) } +pub fn is_valid_for_get_attr(name: Symbol) -> bool { + BUILTIN_ATTRIBUTE_MAP.get(&name).map_or(false, |attr| match attr.duplicates { + WarnFollowing | ErrorFollowing | ErrorPreceding | FutureWarnFollowing + | FutureWarnPreceding => true, + DuplicatesOk | WarnFollowingWordOnly => false, + }) +} + pub static BUILTIN_ATTRIBUTE_MAP: LazyLock> = LazyLock::new(|| { let mut map = FxHashMap::default(); diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index e44c9291f8483..bdaa0ee88eba1 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -151,7 +151,7 @@ pub use active::{Features, ACTIVE_FEATURES, INCOMPATIBLE_FEATURES}; pub use builtin_attrs::AttributeDuplicates; pub use builtin_attrs::{ deprecated_attributes, find_gated_cfg, is_builtin_attr_name, is_builtin_only_local, - AttributeGate, AttributeTemplate, AttributeType, BuiltinAttribute, GatedCfg, - BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP, + is_valid_for_get_attr, AttributeGate, AttributeTemplate, AttributeType, BuiltinAttribute, + GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP, }; pub use removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES}; diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs new file mode 100644 index 0000000000000..18b31a75bcc0d --- /dev/null +++ b/compiler/rustc_middle/src/error.rs @@ -0,0 +1,50 @@ +use rustc_macros::SessionDiagnostic; +use rustc_span::Span; + +use crate::ty::Ty; + +#[derive(SessionDiagnostic)] +#[diag(middle::drop_check_overflow, code = "E0320")] +#[note] +pub struct DropCheckOverflow<'tcx> { + #[primary_span] + pub span: Span, + pub ty: Ty<'tcx>, + pub overflow_ty: Ty<'tcx>, +} + +#[derive(SessionDiagnostic)] +#[diag(middle::opaque_hidden_type_mismatch)] +pub struct OpaqueHiddenTypeMismatch<'tcx> { + pub self_ty: Ty<'tcx>, + pub other_ty: Ty<'tcx>, + #[primary_span] + #[label] + pub other_span: Span, + #[subdiagnostic] + pub sub: TypeMismatchReason, +} + +#[derive(SessionSubdiagnostic)] +pub enum TypeMismatchReason { + #[label(middle::conflict_types)] + ConflictType { + #[primary_span] + span: Span, + }, + #[note(middle::previous_use_here)] + PreviousUse { + #[primary_span] + span: Span, + }, +} + +#[derive(SessionDiagnostic)] +#[diag(middle::limit_invalid)] +pub struct LimitInvalid<'a> { + #[primary_span] + pub span: Span, + #[label] + pub value_span: Span, + pub error_str: &'a str, +} diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index be9e5865e541c..1e3a6bcfc7d32 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -86,6 +86,7 @@ pub mod query; pub mod arena; #[macro_use] pub mod dep_graph; +pub(crate) mod error; pub mod hir; pub mod infer; pub mod lint; diff --git a/compiler/rustc_middle/src/middle/limits.rs b/compiler/rustc_middle/src/middle/limits.rs index acced0492efe9..53c4d92678490 100644 --- a/compiler/rustc_middle/src/middle/limits.rs +++ b/compiler/rustc_middle/src/middle/limits.rs @@ -10,6 +10,7 @@ //! just peeks and looks for that attribute. use crate::bug; +use crate::error::LimitInvalid; use crate::ty; use rustc_ast::Attribute; use rustc_session::Session; @@ -56,9 +57,6 @@ fn get_limit(krate_attrs: &[Attribute], sess: &Session, name: Symbol, default: u match s.as_str().parse() { Ok(n) => return Limit::new(n), Err(e) => { - let mut err = - sess.struct_span_err(attr.span, "`limit` must be a non-negative integer"); - let value_span = attr .meta() .and_then(|meta| meta.name_value_literal_span()) @@ -74,9 +72,7 @@ fn get_limit(krate_attrs: &[Attribute], sess: &Session, name: Symbol, default: u IntErrorKind::Zero => bug!("zero is a valid `limit`"), kind => bug!("unimplemented IntErrorKind variant: {:?}", kind), }; - - err.span_label(value_span, error_str); - err.emit(); + sess.emit_err(LimitInvalid { span: attr.span, value_span, error_str }); } } } diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index 1f9b474ade12b..0e6cacb9fd0f8 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -5,11 +5,11 @@ //! The providers for the queries defined here can be found in //! `rustc_traits`. +use crate::error::DropCheckOverflow; use crate::infer::canonical::{Canonical, QueryResponse}; use crate::ty::error::TypeError; use crate::ty::subst::GenericArg; use crate::ty::{self, Ty, TyCtxt}; -use rustc_errors::struct_span_err; use rustc_span::source_map::Span; use std::iter::FromIterator; @@ -117,15 +117,7 @@ pub struct DropckOutlivesResult<'tcx> { impl<'tcx> DropckOutlivesResult<'tcx> { pub fn report_overflows(&self, tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) { if let Some(overflow_ty) = self.overflows.get(0) { - let mut err = struct_span_err!( - tcx.sess, - span, - E0320, - "overflow while adding drop-check rules for {}", - ty, - ); - err.note(&format!("overflowed on {}", overflow_ty)); - err.emit(); + tcx.sess.emit_err(DropCheckOverflow { span, ty, overflow_ty: *overflow_ty }); } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 8235a05fb53f1..a3f7880b9a568 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -15,6 +15,7 @@ pub use self::AssocItemContainer::*; pub use self::BorrowKind::*; pub use self::IntVarValue::*; pub use self::Variance::*; +use crate::error::{OpaqueHiddenTypeMismatch, TypeMismatchReason}; use crate::metadata::ModChild; use crate::middle::privacy::AccessLevels; use crate::mir::{Body, GeneratorLayout}; @@ -1179,20 +1180,17 @@ pub struct OpaqueHiddenType<'tcx> { impl<'tcx> OpaqueHiddenType<'tcx> { pub fn report_mismatch(&self, other: &Self, tcx: TyCtxt<'tcx>) { // Found different concrete types for the opaque type. - let mut err = tcx.sess.struct_span_err( - other.span, - "concrete type differs from previous defining opaque type use", - ); - err.span_label(other.span, format!("expected `{}`, got `{}`", self.ty, other.ty)); - if self.span == other.span { - err.span_label( - self.span, - "this expression supplies two conflicting concrete types for the same opaque type", - ); + let sub_diag = if self.span == other.span { + TypeMismatchReason::ConflictType { span: self.span } } else { - err.span_note(self.span, "previous use here"); - } - err.emit(); + TypeMismatchReason::PreviousUse { span: self.span } + }; + tcx.sess.emit_err(OpaqueHiddenTypeMismatch { + self_ty: self.ty, + other_ty: other.ty, + other_span: other.span, + sub: sub_diag, + }); } } @@ -2269,7 +2267,11 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn get_attr(self, did: DefId, attr: Symbol) -> Option<&'tcx ast::Attribute> { - self.get_attrs(did, attr).next() + if cfg!(debug_assertions) && !rustc_feature::is_valid_for_get_attr(attr) { + bug!("get_attr: unexpected called with DefId `{:?}`, attr `{:?}`", did, attr); + } else { + self.get_attrs(did, attr).next() + } } /// Determines whether an item is annotated with an attribute. diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 46135caa9bce8..43893263be138 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -1459,7 +1459,7 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L def.destructor(tcx); // force the destructor to be evaluated if vs.is_empty() { - if let Some(attr) = tcx.get_attr(def_id.to_def_id(), sym::repr) { + if let Some(attr) = tcx.get_attrs(def_id.to_def_id(), sym::repr).next() { struct_span_err!( tcx.sess, attr.span, diff --git a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs index cddb0ce2346ad..4359124646df1 100644 --- a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs @@ -749,23 +749,45 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { fn suggest_moving_args_from_assoc_fn_to_trait_for_method_call( &self, err: &mut Diagnostic, - trait_: DefId, + trait_def_id: DefId, expr: &'tcx hir::Expr<'tcx>, msg: String, num_assoc_fn_excess_args: usize, num_trait_generics_except_self: usize, ) { - if let hir::ExprKind::MethodCall(_, receiver, args, ..) = expr.kind { - assert_eq!(args.len(), 0); - if num_assoc_fn_excess_args == num_trait_generics_except_self { - if let Some(gen_args) = self.gen_args.span_ext() - && let Ok(gen_args) = self.tcx.sess.source_map().span_to_snippet(gen_args) - && let Ok(receiver) = self.tcx.sess.source_map().span_to_snippet(receiver.span) { - let sugg = format!("{}::{}::{}({})", self.tcx.item_name(trait_), gen_args, self.tcx.item_name(self.def_id), receiver); - err.span_suggestion(expr.span, msg, sugg, Applicability::MaybeIncorrect); - } - } + let sm = self.tcx.sess.source_map(); + let hir::ExprKind::MethodCall(_, rcvr, args, _) = expr.kind else { return; }; + if num_assoc_fn_excess_args != num_trait_generics_except_self { + return; } + let Some(gen_args) = self.gen_args.span_ext() else { return; }; + let Ok(generics) = sm.span_to_snippet(gen_args) else { return; }; + let Ok(rcvr) = sm.span_to_snippet( + rcvr.span.find_ancestor_inside(expr.span).unwrap_or(rcvr.span) + ) else { return; }; + let Ok(rest) = + (match args { + [] => Ok(String::new()), + [arg] => sm.span_to_snippet( + arg.span.find_ancestor_inside(expr.span).unwrap_or(arg.span), + ), + [first, .., last] => { + let first_span = + first.span.find_ancestor_inside(expr.span).unwrap_or(first.span); + let last_span = + last.span.find_ancestor_inside(expr.span).unwrap_or(last.span); + sm.span_to_snippet(first_span.to(last_span)) + } + }) else { return; }; + let comma = if args.len() > 0 { ", " } else { "" }; + let trait_path = self.tcx.def_path_str(trait_def_id); + let method_name = self.tcx.item_name(self.def_id); + err.span_suggestion( + expr.span, + msg, + format!("{trait_path}::{generics}::{method_name}({rcvr}{comma}{rest})"), + Applicability::MaybeIncorrect, + ); } /// Suggests to remove redundant argument(s): diff --git a/library/core/src/bool.rs b/library/core/src/bool.rs index f7a8aa0d92156..7667a65083769 100644 --- a/library/core/src/bool.rs +++ b/library/core/src/bool.rs @@ -6,6 +6,12 @@ impl bool { /// Returns `Some(t)` if the `bool` is [`true`](../std/keyword.true.html), /// or `None` otherwise. /// + /// Arguments passed to `then_some` are eagerly evaluated; if you are + /// passing the result of a function call, it is recommended to use + /// [`then`], which is lazily evaluated. + /// + /// [`then`]: bool::then + /// /// # Examples /// /// ``` diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs index 47455760a4bd7..6c9e7574e1746 100644 --- a/library/core/src/slice/iter/macros.rs +++ b/library/core/src/slice/iter/macros.rs @@ -64,7 +64,7 @@ macro_rules! iterator { // backwards by `n`. `n` must not exceed `self.len()`. macro_rules! zst_shrink { ($self: ident, $n: ident) => { - $self.end = $self.end.wrapping_byte_offset(-$n); + $self.end = $self.end.wrapping_byte_sub($n); } } @@ -82,7 +82,7 @@ macro_rules! iterator { // returning the old start. // Unsafe because the offset must not exceed `self.len()`. #[inline(always)] - unsafe fn post_inc_start(&mut self, offset: isize) -> * $raw_mut T { + unsafe fn post_inc_start(&mut self, offset: usize) -> * $raw_mut T { if mem::size_of::() == 0 { zst_shrink!(self, offset); self.ptr.as_ptr() @@ -90,7 +90,7 @@ macro_rules! iterator { let old = self.ptr.as_ptr(); // SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`, // so this new pointer is inside `self` and thus guaranteed to be non-null. - self.ptr = unsafe { NonNull::new_unchecked(self.ptr.as_ptr().offset(offset)) }; + self.ptr = unsafe { NonNull::new_unchecked(self.ptr.as_ptr().add(offset)) }; old } } @@ -99,7 +99,7 @@ macro_rules! iterator { // returning the new end. // Unsafe because the offset must not exceed `self.len()`. #[inline(always)] - unsafe fn pre_dec_end(&mut self, offset: isize) -> * $raw_mut T { + unsafe fn pre_dec_end(&mut self, offset: usize) -> * $raw_mut T { if mem::size_of::() == 0 { zst_shrink!(self, offset); self.ptr.as_ptr() @@ -107,7 +107,7 @@ macro_rules! iterator { // SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`, // which is guaranteed to not overflow an `isize`. Also, the resulting pointer // is in bounds of `slice`, which fulfills the other requirements for `offset`. - self.end = unsafe { self.end.offset(-offset) }; + self.end = unsafe { self.end.sub(offset) }; self.end } } @@ -180,7 +180,7 @@ macro_rules! iterator { } // SAFETY: We are in bounds. `post_inc_start` does the right thing even for ZSTs. unsafe { - self.post_inc_start(n as isize); + self.post_inc_start(n); Some(next_unchecked!(self)) } } @@ -189,7 +189,7 @@ macro_rules! iterator { fn advance_by(&mut self, n: usize) -> Result<(), usize> { let advance = cmp::min(len!(self), n); // SAFETY: By construction, `advance` does not exceed `self.len()`. - unsafe { self.post_inc_start(advance as isize) }; + unsafe { self.post_inc_start(advance) }; if advance == n { Ok(()) } else { Err(advance) } } @@ -375,7 +375,7 @@ macro_rules! iterator { } // SAFETY: We are in bounds. `pre_dec_end` does the right thing even for ZSTs. unsafe { - self.pre_dec_end(n as isize); + self.pre_dec_end(n); Some(next_back_unchecked!(self)) } } @@ -384,7 +384,7 @@ macro_rules! iterator { fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { let advance = cmp::min(len!(self), n); // SAFETY: By construction, `advance` does not exceed `self.len()`. - unsafe { self.pre_dec_end(advance as isize) }; + unsafe { self.pre_dec_end(advance) }; if advance == n { Ok(()) } else { Err(advance) } } } diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs index 8b025da2a46ed..c6c03c0b0db96 100644 --- a/library/core/src/slice/sort.rs +++ b/library/core/src/slice/sort.rs @@ -365,12 +365,12 @@ where if count > 0 { macro_rules! left { () => { - l.add(*start_l as usize) + l.add(usize::from(*start_l)) }; } macro_rules! right { () => { - r.sub((*start_r as usize) + 1) + r.sub(usize::from(*start_r) + 1) }; } @@ -458,7 +458,7 @@ where // the last block, so the `l.offset` calls are valid. unsafe { end_l = end_l.sub(1); - ptr::swap(l.add(*end_l as usize), r.sub(1)); + ptr::swap(l.add(usize::from(*end_l)), r.sub(1)); r = r.sub(1); } } @@ -471,7 +471,7 @@ where // SAFETY: See the reasoning in [remaining-elements-safety]. unsafe { end_r = end_r.sub(1); - ptr::swap(l, r.sub((*end_r as usize) + 1)); + ptr::swap(l, r.sub(usize::from(*end_r) + 1)); l = l.add(1); } } diff --git a/src/test/ui/attributes/issue-100631.rs b/src/test/ui/attributes/issue-100631.rs new file mode 100644 index 0000000000000..0fefcf83fd516 --- /dev/null +++ b/src/test/ui/attributes/issue-100631.rs @@ -0,0 +1,8 @@ +// issue #100631, make sure `TyCtxt::get_attr` only called by case that compiler +// can reasonably deal with multiple attributes. +// `repr` will use `TyCtxt::get_attrs` since it's `DuplicatesOk`. +#[repr(C)] //~ ERROR: unsupported representation for zero-variant enum [E0084] +#[repr(C)] +enum Foo {} + +fn main() {} diff --git a/src/test/ui/attributes/issue-100631.stderr b/src/test/ui/attributes/issue-100631.stderr new file mode 100644 index 0000000000000..caa5351ddc7aa --- /dev/null +++ b/src/test/ui/attributes/issue-100631.stderr @@ -0,0 +1,12 @@ +error[E0084]: unsupported representation for zero-variant enum + --> $DIR/issue-100631.rs:4:1 + | +LL | #[repr(C)] + | ^^^^^^^^^^ +LL | #[repr(C)] +LL | enum Foo {} + | -------- zero-variant enum + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0084`. diff --git a/src/test/ui/suggestions/issue-101421.rs b/src/test/ui/suggestions/issue-101421.rs new file mode 100644 index 0000000000000..b615997d1a9a7 --- /dev/null +++ b/src/test/ui/suggestions/issue-101421.rs @@ -0,0 +1,12 @@ +pub trait Ice { + fn f(&self, _: ()); +} + +impl Ice for () { + fn f(&self, _: ()) {} +} + +fn main() { + ().f::<()>(()); + //~^ ERROR this associated function takes 0 generic arguments but 1 generic argument was supplied +} diff --git a/src/test/ui/suggestions/issue-101421.stderr b/src/test/ui/suggestions/issue-101421.stderr new file mode 100644 index 0000000000000..f8e1efb88202e --- /dev/null +++ b/src/test/ui/suggestions/issue-101421.stderr @@ -0,0 +1,17 @@ +error[E0107]: this associated function takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/issue-101421.rs:10:8 + | +LL | ().f::<()>(()); + | ^------ help: remove these generics + | | + | expected 0 generic arguments + | +note: associated function defined here, with 0 generic parameters + --> $DIR/issue-101421.rs:2:8 + | +LL | fn f(&self, _: ()); + | ^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0107`. diff --git a/src/test/ui/suggestions/move-generic-to-trait-in-method-with-params.rs b/src/test/ui/suggestions/move-generic-to-trait-in-method-with-params.rs new file mode 100644 index 0000000000000..2f540060a349d --- /dev/null +++ b/src/test/ui/suggestions/move-generic-to-trait-in-method-with-params.rs @@ -0,0 +1,18 @@ +// Generalizes the suggestion introduced in #100838 + +trait Foo { + fn bar(&self, _: T); +} + +impl Foo for i32 { + fn bar(&self, x: i32) { + println!("{}", self + x); + } +} + +fn main() { + 1.bar::(0); + //~^ ERROR this associated function takes 0 generic arguments but 1 generic argument was supplied + //~| HELP consider moving this generic argument to the `Foo` trait, which takes up to 1 argument + //~| HELP remove these generics +} diff --git a/src/test/ui/suggestions/move-generic-to-trait-in-method-with-params.stderr b/src/test/ui/suggestions/move-generic-to-trait-in-method-with-params.stderr new file mode 100644 index 0000000000000..9557220f6bb5e --- /dev/null +++ b/src/test/ui/suggestions/move-generic-to-trait-in-method-with-params.stderr @@ -0,0 +1,24 @@ +error[E0107]: this associated function takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/move-generic-to-trait-in-method-with-params.rs:14:7 + | +LL | 1.bar::(0); + | ^^^ expected 0 generic arguments + | +note: associated function defined here, with 0 generic parameters + --> $DIR/move-generic-to-trait-in-method-with-params.rs:4:8 + | +LL | fn bar(&self, _: T); + | ^^^ +help: consider moving this generic argument to the `Foo` trait, which takes up to 1 argument + | +LL | Foo::::bar(1, 0); + | ~~~~~~~~~~~~~~~~~~~~~ +help: remove these generics + | +LL - 1.bar::(0); +LL + 1.bar(0); + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0107`.