Rollup merge of #122120 - fmease:sugg-assoc-ty-bound-on-eq-bound, r=compiler-errors
Suggest associated type bounds on problematic associated equality bounds Fixes #105056. TL;DR: Suggest `Trait<Ty: Bound>` on `Trait<Ty = Bound>` in Rust >=2021. ~~Blocked on #122055 (stabilization of `associated_type_bounds`), I'd say.~~ (merged)
This commit is contained in:
commit
ff8cdc9e14
10 changed files with 287 additions and 99 deletions
|
@ -2289,21 +2289,15 @@ pub enum ImplItemKind<'hir> {
|
||||||
Type(&'hir Ty<'hir>),
|
Type(&'hir Ty<'hir>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bind a type to an associated type (i.e., `A = Foo`).
|
/// An associated item binding.
|
||||||
///
|
///
|
||||||
/// Bindings like `A: Debug` are represented as a special type `A =
|
/// ### Examples
|
||||||
/// $::Debug` that is understood by the HIR ty lowering code.
|
|
||||||
///
|
///
|
||||||
/// FIXME(alexreg): why have a separate type for the binding case,
|
/// * `Trait<A = Ty, B = Ty>`
|
||||||
/// wouldn't it be better to make the `ty` field an enum like the
|
/// * `Trait<G<Ty> = Ty>`
|
||||||
/// following?
|
/// * `Trait<A: Bound>`
|
||||||
///
|
/// * `Trait<C = { Ct }>` (under feature `associated_const_equality`)
|
||||||
/// ```ignore (pseudo-rust)
|
/// * `Trait<f(): Bound>` (under feature `return_type_notation`)
|
||||||
/// enum TypeBindingKind {
|
|
||||||
/// Equals(...),
|
|
||||||
/// Binding(...),
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||||
pub struct TypeBinding<'hir> {
|
pub struct TypeBinding<'hir> {
|
||||||
pub hir_id: HirId,
|
pub hir_id: HirId,
|
||||||
|
@ -2336,7 +2330,7 @@ impl<'hir> From<AnonConst> for Term<'hir> {
|
||||||
pub enum TypeBindingKind<'hir> {
|
pub enum TypeBindingKind<'hir> {
|
||||||
/// E.g., `Foo<Bar: Send>`.
|
/// E.g., `Foo<Bar: Send>`.
|
||||||
Constraint { bounds: &'hir [GenericBound<'hir>] },
|
Constraint { bounds: &'hir [GenericBound<'hir>] },
|
||||||
/// E.g., `Foo<Bar = ()>`, `Foo<Bar = ()>`
|
/// E.g., `Foo<Bar = ()>`.
|
||||||
Equality { term: Term<'hir> },
|
Equality { term: Term<'hir> },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,85 @@ use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamNa
|
||||||
use super::HirTyLowerer;
|
use super::HirTyLowerer;
|
||||||
|
|
||||||
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
|
/// Prohibit or lint against *bare* trait object types depending on the edition.
|
||||||
|
///
|
||||||
|
/// *Bare* trait object types are ones that aren't preceeded by the keyword `dyn`.
|
||||||
|
/// In edition 2021 and onward we emit a hard error for them.
|
||||||
|
pub(super) fn prohibit_or_lint_bare_trait_object_ty(
|
||||||
|
&self,
|
||||||
|
self_ty: &hir::Ty<'_>,
|
||||||
|
in_path: bool,
|
||||||
|
) {
|
||||||
|
let tcx = self.tcx();
|
||||||
|
|
||||||
|
let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
|
||||||
|
self_ty.kind
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let needs_bracket = in_path
|
||||||
|
&& !tcx
|
||||||
|
.sess
|
||||||
|
.source_map()
|
||||||
|
.span_to_prev_source(self_ty.span)
|
||||||
|
.ok()
|
||||||
|
.is_some_and(|s| s.trim_end().ends_with('<'));
|
||||||
|
|
||||||
|
let is_global = poly_trait_ref.trait_ref.path.is_global();
|
||||||
|
|
||||||
|
let mut sugg = vec![(
|
||||||
|
self_ty.span.shrink_to_lo(),
|
||||||
|
format!(
|
||||||
|
"{}dyn {}",
|
||||||
|
if needs_bracket { "<" } else { "" },
|
||||||
|
if is_global { "(" } else { "" },
|
||||||
|
),
|
||||||
|
)];
|
||||||
|
|
||||||
|
if is_global || needs_bracket {
|
||||||
|
sugg.push((
|
||||||
|
self_ty.span.shrink_to_hi(),
|
||||||
|
format!(
|
||||||
|
"{}{}",
|
||||||
|
if is_global { ")" } else { "" },
|
||||||
|
if needs_bracket { ">" } else { "" },
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if self_ty.span.edition().at_least_rust_2021() {
|
||||||
|
let msg = "trait objects must include the `dyn` keyword";
|
||||||
|
let label = "add `dyn` keyword before this trait";
|
||||||
|
let mut diag =
|
||||||
|
rustc_errors::struct_span_code_err!(tcx.dcx(), self_ty.span, E0782, "{}", msg);
|
||||||
|
if self_ty.span.can_be_used_for_suggestions()
|
||||||
|
&& !self.maybe_suggest_impl_trait(self_ty, &mut diag)
|
||||||
|
{
|
||||||
|
// FIXME: Only emit this suggestion if the trait is object safe.
|
||||||
|
diag.multipart_suggestion_verbose(label, sugg, Applicability::MachineApplicable);
|
||||||
|
}
|
||||||
|
// Check if the impl trait that we are considering is an impl of a local trait.
|
||||||
|
self.maybe_suggest_blanket_trait_impl(self_ty, &mut diag);
|
||||||
|
self.maybe_suggest_assoc_ty_bound(self_ty, &mut diag);
|
||||||
|
diag.stash(self_ty.span, StashKey::TraitMissingMethod);
|
||||||
|
} else {
|
||||||
|
let msg = "trait objects without an explicit `dyn` are deprecated";
|
||||||
|
tcx.node_span_lint(BARE_TRAIT_OBJECTS, self_ty.hir_id, self_ty.span, msg, |lint| {
|
||||||
|
if self_ty.span.can_be_used_for_suggestions() {
|
||||||
|
lint.multipart_suggestion_verbose(
|
||||||
|
"if this is an object-safe trait, use `dyn`",
|
||||||
|
sugg,
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
self.maybe_suggest_blanket_trait_impl(self_ty, lint);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Make sure that we are in the condition to suggest the blanket implementation.
|
/// Make sure that we are in the condition to suggest the blanket implementation.
|
||||||
pub(super) fn maybe_lint_blanket_trait_impl<G: EmissionGuarantee>(
|
fn maybe_suggest_blanket_trait_impl<G: EmissionGuarantee>(
|
||||||
&self,
|
&self,
|
||||||
self_ty: &hir::Ty<'_>,
|
self_ty: &hir::Ty<'_>,
|
||||||
diag: &mut Diag<'_, G>,
|
diag: &mut Diag<'_, G>,
|
||||||
|
@ -75,9 +152,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Make sure that we are in the condition to suggest `impl Trait`.
|
/// Make sure that we are in the condition to suggest `impl Trait`.
|
||||||
fn maybe_lint_impl_trait(&self, self_ty: &hir::Ty<'_>, diag: &mut Diag<'_>) -> bool {
|
fn maybe_suggest_impl_trait(&self, self_ty: &hir::Ty<'_>, diag: &mut Diag<'_>) -> bool {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id;
|
let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id;
|
||||||
|
// FIXME: If `type_alias_impl_trait` is enabled, also look for `Trait0<Ty = Trait1>`
|
||||||
|
// and suggest `Trait0<Ty = impl Trait1>`.
|
||||||
let (sig, generics, owner) = match tcx.hir_node_by_def_id(parent_id) {
|
let (sig, generics, owner) = match tcx.hir_node_by_def_id(parent_id) {
|
||||||
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, generics, _), .. }) => {
|
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, generics, _), .. }) => {
|
||||||
(sig, generics, None)
|
(sig, generics, None)
|
||||||
|
@ -186,71 +265,37 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) {
|
fn maybe_suggest_assoc_ty_bound(&self, self_ty: &hir::Ty<'_>, diag: &mut Diag<'_>) {
|
||||||
let tcx = self.tcx();
|
let mut parents = self.tcx().hir().parent_iter(self_ty.hir_id);
|
||||||
if let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
|
|
||||||
self_ty.kind
|
if let Some((_, hir::Node::TypeBinding(binding))) = parents.next()
|
||||||
|
&& let hir::TypeBindingKind::Equality { term: hir::Term::Ty(obj_ty) } = binding.kind
|
||||||
{
|
{
|
||||||
let needs_bracket = in_path
|
if let Some((_, hir::Node::TraitRef(..))) = parents.next()
|
||||||
&& !tcx
|
&& let Some((_, hir::Node::Ty(ty))) = parents.next()
|
||||||
.sess
|
&& let hir::TyKind::TraitObject(..) = ty.kind
|
||||||
.source_map()
|
{
|
||||||
.span_to_prev_source(self_ty.span)
|
// Assoc ty bounds aren't permitted inside trait object types.
|
||||||
.ok()
|
return;
|
||||||
.is_some_and(|s| s.trim_end().ends_with('<'));
|
|
||||||
|
|
||||||
let is_global = poly_trait_ref.trait_ref.path.is_global();
|
|
||||||
|
|
||||||
let mut sugg = Vec::from_iter([(
|
|
||||||
self_ty.span.shrink_to_lo(),
|
|
||||||
format!(
|
|
||||||
"{}dyn {}",
|
|
||||||
if needs_bracket { "<" } else { "" },
|
|
||||||
if is_global { "(" } else { "" },
|
|
||||||
),
|
|
||||||
)]);
|
|
||||||
|
|
||||||
if is_global || needs_bracket {
|
|
||||||
sugg.push((
|
|
||||||
self_ty.span.shrink_to_hi(),
|
|
||||||
format!(
|
|
||||||
"{}{}",
|
|
||||||
if is_global { ")" } else { "" },
|
|
||||||
if needs_bracket { ">" } else { "" },
|
|
||||||
),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if self_ty.span.edition().at_least_rust_2021() {
|
let lo = if binding.gen_args.span_ext.is_dummy() {
|
||||||
let msg = "trait objects must include the `dyn` keyword";
|
binding.ident.span
|
||||||
let label = "add `dyn` keyword before this trait";
|
|
||||||
let mut diag =
|
|
||||||
rustc_errors::struct_span_code_err!(tcx.dcx(), self_ty.span, E0782, "{}", msg);
|
|
||||||
if self_ty.span.can_be_used_for_suggestions()
|
|
||||||
&& !self.maybe_lint_impl_trait(self_ty, &mut diag)
|
|
||||||
{
|
|
||||||
diag.multipart_suggestion_verbose(
|
|
||||||
label,
|
|
||||||
sugg,
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// check if the impl trait that we are considering is a impl of a local trait
|
|
||||||
self.maybe_lint_blanket_trait_impl(self_ty, &mut diag);
|
|
||||||
diag.stash(self_ty.span, StashKey::TraitMissingMethod);
|
|
||||||
} else {
|
} else {
|
||||||
let msg = "trait objects without an explicit `dyn` are deprecated";
|
binding.gen_args.span_ext
|
||||||
tcx.node_span_lint(BARE_TRAIT_OBJECTS, self_ty.hir_id, self_ty.span, msg, |lint| {
|
};
|
||||||
if self_ty.span.can_be_used_for_suggestions() {
|
let hi = obj_ty.span;
|
||||||
lint.multipart_suggestion_verbose(
|
|
||||||
"if this is an object-safe trait, use `dyn`",
|
if !lo.eq_ctxt(hi) {
|
||||||
sugg,
|
return;
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
self.maybe_lint_blanket_trait_impl(self_ty, lint);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
diag.span_suggestion_verbose(
|
||||||
|
lo.between(hi),
|
||||||
|
"you might have meant to write a bound here",
|
||||||
|
": ",
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2339,12 +2339,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
hir::TyKind::TraitObject(bounds, lifetime, repr) => {
|
hir::TyKind::TraitObject(bounds, lifetime, repr) => {
|
||||||
self.maybe_lint_bare_trait(hir_ty, in_path);
|
self.prohibit_or_lint_bare_trait_object_ty(hir_ty, in_path);
|
||||||
|
|
||||||
let repr = match repr {
|
let repr = match repr {
|
||||||
TraitObjectSyntax::Dyn | TraitObjectSyntax::None => ty::Dyn,
|
TraitObjectSyntax::Dyn | TraitObjectSyntax::None => ty::Dyn,
|
||||||
TraitObjectSyntax::DynStar => ty::DynStar,
|
TraitObjectSyntax::DynStar => ty::DynStar,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.lower_trait_object_ty(
|
self.lower_trait_object_ty(
|
||||||
hir_ty.span,
|
hir_ty.span,
|
||||||
hir_ty.hir_id,
|
hir_ty.hir_id,
|
||||||
|
|
|
@ -14,10 +14,6 @@ parse_array_index_offset_of = array indexing not supported in offset_of
|
||||||
|
|
||||||
parse_assignment_else_not_allowed = <assignment> ... else {"{"} ... {"}"} is not allowed
|
parse_assignment_else_not_allowed = <assignment> ... else {"{"} ... {"}"} is not allowed
|
||||||
|
|
||||||
parse_assoc_lifetime = associated lifetimes are not supported
|
|
||||||
.label = the lifetime is given here
|
|
||||||
.help = if you meant to specify a trait object, write `dyn Trait + 'lifetime`
|
|
||||||
|
|
||||||
parse_associated_static_item_not_allowed = associated `static` items are not allowed
|
parse_associated_static_item_not_allowed = associated `static` items are not allowed
|
||||||
|
|
||||||
parse_async_block_in_2015 = `async` blocks are only allowed in Rust 2018 or later
|
parse_async_block_in_2015 = `async` blocks are only allowed in Rust 2018 or later
|
||||||
|
@ -445,6 +441,12 @@ parse_lifetime_in_borrow_expression = borrow expressions cannot be annotated wit
|
||||||
.suggestion = remove the lifetime annotation
|
.suggestion = remove the lifetime annotation
|
||||||
.label = annotated with lifetime here
|
.label = annotated with lifetime here
|
||||||
|
|
||||||
|
parse_lifetime_in_eq_constraint = lifetimes are not permitted in this context
|
||||||
|
.label = lifetime is not allowed here
|
||||||
|
.context_label = this introduces an associated item binding
|
||||||
|
.help = if you meant to specify a trait object, write `dyn /* Trait */ + {$lifetime}`
|
||||||
|
.colon_sugg = you might have meant to write a bound here
|
||||||
|
|
||||||
parse_lone_slash = invalid trailing slash in literal
|
parse_lone_slash = invalid trailing slash in literal
|
||||||
.label = {parse_lone_slash}
|
.label = {parse_lone_slash}
|
||||||
|
|
||||||
|
|
|
@ -2631,13 +2631,22 @@ pub(crate) struct GenericsInPath {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(parse_assoc_lifetime)]
|
#[diag(parse_lifetime_in_eq_constraint)]
|
||||||
#[help]
|
#[help]
|
||||||
pub(crate) struct AssocLifetime {
|
pub(crate) struct LifetimeInEqConstraint {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
|
||||||
#[label]
|
#[label]
|
||||||
pub lifetime: Span,
|
pub span: Span,
|
||||||
|
pub lifetime: Ident,
|
||||||
|
#[label(parse_context_label)]
|
||||||
|
pub binding_label: Span,
|
||||||
|
#[suggestion(
|
||||||
|
parse_colon_sugg,
|
||||||
|
style = "verbose",
|
||||||
|
applicability = "maybe-incorrect",
|
||||||
|
code = ": "
|
||||||
|
)]
|
||||||
|
pub colon_sugg: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
|
|
|
@ -718,7 +718,11 @@ impl<'a> Parser<'a> {
|
||||||
let bounds = self.parse_generic_bounds()?;
|
let bounds = self.parse_generic_bounds()?;
|
||||||
AssocConstraintKind::Bound { bounds }
|
AssocConstraintKind::Bound { bounds }
|
||||||
} else if self.eat(&token::Eq) {
|
} else if self.eat(&token::Eq) {
|
||||||
self.parse_assoc_equality_term(ident, self.prev_token.span)?
|
self.parse_assoc_equality_term(
|
||||||
|
ident,
|
||||||
|
gen_args.as_ref(),
|
||||||
|
self.prev_token.span,
|
||||||
|
)?
|
||||||
} else {
|
} else {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
};
|
};
|
||||||
|
@ -753,11 +757,13 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse the term to the right of an associated item equality constraint.
|
/// Parse the term to the right of an associated item equality constraint.
|
||||||
/// That is, parse `<term>` in `Item = <term>`.
|
///
|
||||||
/// Right now, this only admits types in `<term>`.
|
/// That is, parse `$term` in `Item = $term` where `$term` is a type or
|
||||||
|
/// a const expression (wrapped in curly braces if complex).
|
||||||
fn parse_assoc_equality_term(
|
fn parse_assoc_equality_term(
|
||||||
&mut self,
|
&mut self,
|
||||||
ident: Ident,
|
ident: Ident,
|
||||||
|
gen_args: Option<&GenericArgs>,
|
||||||
eq: Span,
|
eq: Span,
|
||||||
) -> PResult<'a, AssocConstraintKind> {
|
) -> PResult<'a, AssocConstraintKind> {
|
||||||
let arg = self.parse_generic_arg(None)?;
|
let arg = self.parse_generic_arg(None)?;
|
||||||
|
@ -769,9 +775,15 @@ impl<'a> Parser<'a> {
|
||||||
c.into()
|
c.into()
|
||||||
}
|
}
|
||||||
Some(GenericArg::Lifetime(lt)) => {
|
Some(GenericArg::Lifetime(lt)) => {
|
||||||
let guar =
|
let guar = self.dcx().emit_err(errors::LifetimeInEqConstraint {
|
||||||
self.dcx().emit_err(errors::AssocLifetime { span, lifetime: lt.ident.span });
|
span: lt.ident.span,
|
||||||
self.mk_ty(span, ast::TyKind::Err(guar)).into()
|
lifetime: lt.ident,
|
||||||
|
binding_label: span,
|
||||||
|
colon_sugg: gen_args
|
||||||
|
.map_or(ident.span, |args| args.span())
|
||||||
|
.between(lt.ident.span),
|
||||||
|
});
|
||||||
|
self.mk_ty(lt.ident.span, ast::TyKind::Err(guar)).into()
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
let after_eq = eq.shrink_to_hi();
|
let after_eq = eq.shrink_to_hi();
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
// Regression test for issue #105056.
|
||||||
|
//@ edition: 2021
|
||||||
|
|
||||||
|
fn f(_: impl Trait<T = Copy>) {}
|
||||||
|
//~^ ERROR trait objects must include the `dyn` keyword
|
||||||
|
//~| HELP add `dyn` keyword before this trait
|
||||||
|
//~| HELP you might have meant to write a bound here
|
||||||
|
//~| ERROR the trait `Copy` cannot be made into an object
|
||||||
|
|
||||||
|
fn g(_: impl Trait<T = std::fmt::Debug + Eq>) {}
|
||||||
|
//~^ ERROR trait objects must include the `dyn` keyword
|
||||||
|
//~| HELP add `dyn` keyword before this trait
|
||||||
|
//~| HELP you might have meant to write a bound here
|
||||||
|
//~| ERROR only auto traits can be used as additional traits in a trait object
|
||||||
|
//~| HELP consider creating a new trait
|
||||||
|
//~| ERROR the trait `Eq` cannot be made into an object
|
||||||
|
|
||||||
|
fn h(_: impl Trait<T<> = 'static + for<'a> Fn(&'a ())>) {}
|
||||||
|
//~^ ERROR trait objects must include the `dyn` keyword
|
||||||
|
//~| HELP add `dyn` keyword before this trait
|
||||||
|
//~| HELP you might have meant to write a bound here
|
||||||
|
|
||||||
|
// Don't suggest assoc ty bound in trait object types, that's not valid:
|
||||||
|
type Obj = dyn Trait<T = Clone>;
|
||||||
|
//~^ ERROR trait objects must include the `dyn` keyword
|
||||||
|
//~| HELP add `dyn` keyword before this trait
|
||||||
|
|
||||||
|
trait Trait { type T; }
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,91 @@
|
||||||
|
error[E0038]: the trait `Copy` cannot be made into an object
|
||||||
|
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:4:20
|
||||||
|
|
|
||||||
|
LL | fn f(_: impl Trait<T = Copy>) {}
|
||||||
|
| ^^^^^^^^ `Copy` cannot be made into an object
|
||||||
|
|
|
||||||
|
= note: the trait cannot be made into an object because it requires `Self: Sized`
|
||||||
|
= note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
|
||||||
|
|
||||||
|
error[E0225]: only auto traits can be used as additional traits in a trait object
|
||||||
|
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:10:42
|
||||||
|
|
|
||||||
|
LL | fn g(_: impl Trait<T = std::fmt::Debug + Eq>) {}
|
||||||
|
| --------------- ^^ additional non-auto trait
|
||||||
|
| |
|
||||||
|
| first non-auto trait
|
||||||
|
|
|
||||||
|
= help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Debug + Eq {}`
|
||||||
|
= note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
|
||||||
|
|
||||||
|
error[E0038]: the trait `Eq` cannot be made into an object
|
||||||
|
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:10:24
|
||||||
|
|
|
||||||
|
LL | fn g(_: impl Trait<T = std::fmt::Debug + Eq>) {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^ `Eq` cannot be made into an object
|
||||||
|
|
|
||||||
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
|
||||||
|
--> $SRC_DIR/core/src/cmp.rs:LL:COL
|
||||||
|
|
|
||||||
|
= note: the trait cannot be made into an object because it uses `Self` as a type parameter
|
||||||
|
|
||||||
|
error[E0782]: trait objects must include the `dyn` keyword
|
||||||
|
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:4:24
|
||||||
|
|
|
||||||
|
LL | fn f(_: impl Trait<T = Copy>) {}
|
||||||
|
| ^^^^
|
||||||
|
|
|
||||||
|
help: add `dyn` keyword before this trait
|
||||||
|
|
|
||||||
|
LL | fn f(_: impl Trait<T = dyn Copy>) {}
|
||||||
|
| +++
|
||||||
|
help: you might have meant to write a bound here
|
||||||
|
|
|
||||||
|
LL | fn f(_: impl Trait<T: Copy>) {}
|
||||||
|
| ~
|
||||||
|
|
||||||
|
error[E0782]: trait objects must include the `dyn` keyword
|
||||||
|
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:10:24
|
||||||
|
|
|
||||||
|
LL | fn g(_: impl Trait<T = std::fmt::Debug + Eq>) {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: add `dyn` keyword before this trait
|
||||||
|
|
|
||||||
|
LL | fn g(_: impl Trait<T = dyn std::fmt::Debug + Eq>) {}
|
||||||
|
| +++
|
||||||
|
help: you might have meant to write a bound here
|
||||||
|
|
|
||||||
|
LL | fn g(_: impl Trait<T: std::fmt::Debug + Eq>) {}
|
||||||
|
| ~
|
||||||
|
|
||||||
|
error[E0782]: trait objects must include the `dyn` keyword
|
||||||
|
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:18:26
|
||||||
|
|
|
||||||
|
LL | fn h(_: impl Trait<T<> = 'static + for<'a> Fn(&'a ())>) {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: add `dyn` keyword before this trait
|
||||||
|
|
|
||||||
|
LL | fn h(_: impl Trait<T<> = dyn 'static + for<'a> Fn(&'a ())>) {}
|
||||||
|
| +++
|
||||||
|
help: you might have meant to write a bound here
|
||||||
|
|
|
||||||
|
LL | fn h(_: impl Trait<T<>: 'static + for<'a> Fn(&'a ())>) {}
|
||||||
|
| ~
|
||||||
|
|
||||||
|
error[E0782]: trait objects must include the `dyn` keyword
|
||||||
|
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:24:26
|
||||||
|
|
|
||||||
|
LL | type Obj = dyn Trait<T = Clone>;
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
help: add `dyn` keyword before this trait
|
||||||
|
|
|
||||||
|
LL | type Obj = dyn Trait<T = dyn Clone>;
|
||||||
|
| +++
|
||||||
|
|
||||||
|
error: aborting due to 7 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0038, E0225, E0782.
|
||||||
|
For more information about an error, try `rustc --explain E0038`.
|
|
@ -1,6 +1,6 @@
|
||||||
#[cfg(FALSE)]
|
#[cfg(FALSE)]
|
||||||
fn syntax() {
|
fn syntax() {
|
||||||
bar::<Item = 'a>(); //~ ERROR associated lifetimes are not supported
|
bar::<Item = 'a>(); //~ ERROR lifetimes are not permitted in this context
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,12 +1,17 @@
|
||||||
error: associated lifetimes are not supported
|
error: lifetimes are not permitted in this context
|
||||||
--> $DIR/recover-assoc-lifetime-constraint.rs:3:11
|
--> $DIR/recover-assoc-lifetime-constraint.rs:3:18
|
||||||
|
|
|
|
||||||
LL | bar::<Item = 'a>();
|
LL | bar::<Item = 'a>();
|
||||||
| ^^^^^^^--
|
| -------^^
|
||||||
| |
|
| | |
|
||||||
| the lifetime is given here
|
| | lifetime is not allowed here
|
||||||
|
| this introduces an associated item binding
|
||||||
|
|
|
|
||||||
= help: if you meant to specify a trait object, write `dyn Trait + 'lifetime`
|
= help: if you meant to specify a trait object, write `dyn /* Trait */ + 'a`
|
||||||
|
help: you might have meant to write a bound here
|
||||||
|
|
|
||||||
|
LL | bar::<Item: 'a>();
|
||||||
|
| ~
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue