Rollup merge of #90519 - estebank:issue-84003, r=petrochenkov
Keep spans for generics in `#[derive(_)]` desugaring Keep the spans for generics coming from a `derive`d Item, so that errors and suggestions have better detail. Fix #84003.
This commit is contained in:
commit
0311cfa88c
@ -567,8 +567,11 @@ impl<'a> TraitDef<'a> {
|
||||
})
|
||||
});
|
||||
|
||||
let Generics { mut params, mut where_clause, span } =
|
||||
let Generics { mut params, mut where_clause, .. } =
|
||||
self.generics.to_generics(cx, self.span, type_ident, generics);
|
||||
where_clause.span = generics.where_clause.span;
|
||||
let ctxt = self.span.ctxt();
|
||||
let span = generics.span.with_ctxt(ctxt);
|
||||
|
||||
// Create the generic parameters
|
||||
params.extend(generics.params.iter().map(|param| match ¶m.kind {
|
||||
@ -589,12 +592,12 @@ impl<'a> TraitDef<'a> {
|
||||
param.bounds.iter().cloned()
|
||||
).collect();
|
||||
|
||||
cx.typaram(self.span, param.ident, vec![], bounds, None)
|
||||
cx.typaram(param.ident.span.with_ctxt(ctxt), param.ident, vec![], bounds, None)
|
||||
}
|
||||
GenericParamKind::Const { ty, kw_span, .. } => {
|
||||
let const_nodefault_kind = GenericParamKind::Const {
|
||||
ty: ty.clone(),
|
||||
kw_span: *kw_span,
|
||||
kw_span: kw_span.with_ctxt(ctxt),
|
||||
|
||||
// We can't have default values inside impl block
|
||||
default: None,
|
||||
@ -607,28 +610,27 @@ impl<'a> TraitDef<'a> {
|
||||
|
||||
// and similarly for where clauses
|
||||
where_clause.predicates.extend(generics.where_clause.predicates.iter().map(|clause| {
|
||||
match *clause {
|
||||
ast::WherePredicate::BoundPredicate(ref wb) => {
|
||||
match clause {
|
||||
ast::WherePredicate::BoundPredicate(wb) => {
|
||||
let span = wb.span.with_ctxt(ctxt);
|
||||
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
|
||||
span: self.span,
|
||||
bound_generic_params: wb.bound_generic_params.clone(),
|
||||
bounded_ty: wb.bounded_ty.clone(),
|
||||
bounds: wb.bounds.to_vec(),
|
||||
span,
|
||||
..wb.clone()
|
||||
})
|
||||
}
|
||||
ast::WherePredicate::RegionPredicate(ref rb) => {
|
||||
ast::WherePredicate::RegionPredicate(wr) => {
|
||||
let span = wr.span.with_ctxt(ctxt);
|
||||
ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
|
||||
span: self.span,
|
||||
lifetime: rb.lifetime,
|
||||
bounds: rb.bounds.to_vec(),
|
||||
span,
|
||||
..wr.clone()
|
||||
})
|
||||
}
|
||||
ast::WherePredicate::EqPredicate(ref we) => {
|
||||
ast::WherePredicate::EqPredicate(we) => {
|
||||
let span = we.span.with_ctxt(ctxt);
|
||||
ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span: self.span,
|
||||
lhs_ty: we.lhs_ty.clone(),
|
||||
rhs_ty: we.rhs_ty.clone(),
|
||||
span,
|
||||
..we.clone()
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -691,13 +693,13 @@ impl<'a> TraitDef<'a> {
|
||||
.iter()
|
||||
.map(|param| match param.kind {
|
||||
GenericParamKind::Lifetime { .. } => {
|
||||
GenericArg::Lifetime(cx.lifetime(self.span, param.ident))
|
||||
GenericArg::Lifetime(cx.lifetime(param.ident.span.with_ctxt(ctxt), param.ident))
|
||||
}
|
||||
GenericParamKind::Type { .. } => {
|
||||
GenericArg::Type(cx.ty_ident(self.span, param.ident))
|
||||
GenericArg::Type(cx.ty_ident(param.ident.span.with_ctxt(ctxt), param.ident))
|
||||
}
|
||||
GenericParamKind::Const { .. } => {
|
||||
GenericArg::Const(cx.const_ident(self.span, param.ident))
|
||||
GenericArg::Const(cx.const_ident(param.ident.span.with_ctxt(ctxt), param.ident))
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
@ -845,16 +847,17 @@ impl<'a> MethodDef<'a> {
|
||||
nonself_args: &[P<Expr>],
|
||||
fields: &SubstructureFields<'_>,
|
||||
) -> P<Expr> {
|
||||
let span = trait_.span;
|
||||
let substructure = Substructure {
|
||||
type_ident,
|
||||
method_ident: Ident::new(self.name, trait_.span),
|
||||
method_ident: Ident::new(self.name, span),
|
||||
self_args,
|
||||
nonself_args,
|
||||
fields,
|
||||
};
|
||||
let mut f = self.combine_substructure.borrow_mut();
|
||||
let f: &mut CombineSubstructureFunc<'_> = &mut *f;
|
||||
f(cx, trait_.span, &substructure)
|
||||
f(cx, span, &substructure)
|
||||
}
|
||||
|
||||
fn get_ret_ty(
|
||||
@ -882,9 +885,10 @@ impl<'a> MethodDef<'a> {
|
||||
let mut nonself_args = Vec::new();
|
||||
let mut arg_tys = Vec::new();
|
||||
let mut nonstatic = false;
|
||||
let span = trait_.span;
|
||||
|
||||
let ast_explicit_self = self.explicit_self.as_ref().map(|self_ptr| {
|
||||
let (self_expr, explicit_self) = ty::get_explicit_self(cx, trait_.span, self_ptr);
|
||||
let (self_expr, explicit_self) = ty::get_explicit_self(cx, span, self_ptr);
|
||||
|
||||
self_args.push(self_expr);
|
||||
nonstatic = true;
|
||||
@ -893,11 +897,11 @@ impl<'a> MethodDef<'a> {
|
||||
});
|
||||
|
||||
for (ty, name) in self.args.iter() {
|
||||
let ast_ty = ty.to_ty(cx, trait_.span, type_ident, generics);
|
||||
let ident = Ident::new(*name, trait_.span);
|
||||
let ast_ty = ty.to_ty(cx, span, type_ident, generics);
|
||||
let ident = Ident::new(*name, span);
|
||||
arg_tys.push((ident, ast_ty));
|
||||
|
||||
let arg_expr = cx.expr_ident(trait_.span, ident);
|
||||
let arg_expr = cx.expr_ident(span, ident);
|
||||
|
||||
match *ty {
|
||||
// for static methods, just treat any Self
|
||||
@ -906,7 +910,7 @@ impl<'a> MethodDef<'a> {
|
||||
self_args.push(arg_expr);
|
||||
}
|
||||
Ptr(ref ty, _) if matches!(**ty, Self_) && nonstatic => {
|
||||
self_args.push(cx.expr_deref(trait_.span, arg_expr))
|
||||
self_args.push(cx.expr_deref(span, arg_expr))
|
||||
}
|
||||
_ => {
|
||||
nonself_args.push(arg_expr);
|
||||
@ -927,33 +931,33 @@ impl<'a> MethodDef<'a> {
|
||||
arg_types: Vec<(Ident, P<ast::Ty>)>,
|
||||
body: P<Expr>,
|
||||
) -> P<ast::AssocItem> {
|
||||
let span = trait_.span;
|
||||
// Create the generics that aren't for `Self`.
|
||||
let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics);
|
||||
let fn_generics = self.generics.to_generics(cx, span, type_ident, generics);
|
||||
|
||||
let args = {
|
||||
let self_args = explicit_self.map(|explicit_self| {
|
||||
let ident = Ident::with_dummy_span(kw::SelfLower).with_span_pos(trait_.span);
|
||||
let ident = Ident::with_dummy_span(kw::SelfLower).with_span_pos(span);
|
||||
ast::Param::from_self(ast::AttrVec::default(), explicit_self, ident)
|
||||
});
|
||||
let nonself_args =
|
||||
arg_types.into_iter().map(|(name, ty)| cx.param(trait_.span, name, ty));
|
||||
let nonself_args = arg_types.into_iter().map(|(name, ty)| cx.param(span, name, ty));
|
||||
self_args.into_iter().chain(nonself_args).collect()
|
||||
};
|
||||
|
||||
let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident);
|
||||
|
||||
let method_ident = Ident::new(self.name, trait_.span);
|
||||
let method_ident = Ident::new(self.name, span);
|
||||
let fn_decl = cx.fn_decl(args, ast::FnRetTy::Ty(ret_type));
|
||||
let body_block = cx.block_expr(body);
|
||||
|
||||
let unsafety = if self.is_unsafe { ast::Unsafe::Yes(trait_.span) } else { ast::Unsafe::No };
|
||||
let unsafety = if self.is_unsafe { ast::Unsafe::Yes(span) } else { ast::Unsafe::No };
|
||||
|
||||
let trait_lo_sp = trait_.span.shrink_to_lo();
|
||||
let trait_lo_sp = span.shrink_to_lo();
|
||||
|
||||
let sig = ast::FnSig {
|
||||
header: ast::FnHeader { unsafety, ext: ast::Extern::None, ..ast::FnHeader::default() },
|
||||
decl: fn_decl,
|
||||
span: trait_.span,
|
||||
span,
|
||||
};
|
||||
let defaultness = ast::Defaultness::Final;
|
||||
|
||||
@ -961,7 +965,7 @@ impl<'a> MethodDef<'a> {
|
||||
P(ast::AssocItem {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
attrs: self.attributes.clone(),
|
||||
span: trait_.span,
|
||||
span,
|
||||
vis: ast::Visibility {
|
||||
span: trait_lo_sp,
|
||||
kind: ast::VisibilityKind::Inherited,
|
||||
@ -1024,11 +1028,11 @@ impl<'a> MethodDef<'a> {
|
||||
nonself_args: &[P<Expr>],
|
||||
use_temporaries: bool,
|
||||
) -> P<Expr> {
|
||||
let mut raw_fields = Vec::new(); // Vec<[fields of self],
|
||||
// [fields of next Self arg], [etc]>
|
||||
let mut raw_fields = Vec::new(); // Vec<[fields of self], [fields of next Self arg], [etc]>
|
||||
let span = trait_.span;
|
||||
let mut patterns = Vec::new();
|
||||
for i in 0..self_args.len() {
|
||||
let struct_path = cx.path(trait_.span, vec![type_ident]);
|
||||
let struct_path = cx.path(span, vec![type_ident]);
|
||||
let (pat, ident_expr) = trait_.create_struct_pattern(
|
||||
cx,
|
||||
struct_path,
|
||||
@ -1048,7 +1052,7 @@ impl<'a> MethodDef<'a> {
|
||||
let mut other_fields: Vec<vec::IntoIter<_>> = raw_fields.collect();
|
||||
first_field
|
||||
.map(|(span, opt_id, field, attrs)| FieldInfo {
|
||||
span,
|
||||
span: span.with_ctxt(trait_.span.ctxt()),
|
||||
name: opt_id,
|
||||
self_: field,
|
||||
other: other_fields
|
||||
@ -1062,7 +1066,7 @@ impl<'a> MethodDef<'a> {
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
cx.span_bug(trait_.span, "no `self` parameter for method in generic `derive`")
|
||||
cx.span_bug(span, "no `self` parameter for method in generic `derive`")
|
||||
};
|
||||
|
||||
// body of the inner most destructuring match
|
||||
@ -1079,11 +1083,7 @@ impl<'a> MethodDef<'a> {
|
||||
// structs. This is actually right-to-left, but it shouldn't
|
||||
// matter.
|
||||
for (arg_expr, pat) in iter::zip(self_args, patterns) {
|
||||
body = cx.expr_match(
|
||||
trait_.span,
|
||||
arg_expr.clone(),
|
||||
vec![cx.arm(trait_.span, pat.clone(), body)],
|
||||
)
|
||||
body = cx.expr_match(span, arg_expr.clone(), vec![cx.arm(span, pat.clone(), body)])
|
||||
}
|
||||
|
||||
body
|
||||
@ -1193,7 +1193,7 @@ impl<'a> MethodDef<'a> {
|
||||
mut self_args: Vec<P<Expr>>,
|
||||
nonself_args: &[P<Expr>],
|
||||
) -> P<Expr> {
|
||||
let sp = trait_.span;
|
||||
let span = trait_.span;
|
||||
let variants = &enum_def.variants;
|
||||
|
||||
let self_arg_names = iter::once("__self".to_string())
|
||||
@ -1208,7 +1208,7 @@ impl<'a> MethodDef<'a> {
|
||||
|
||||
let self_arg_idents = self_arg_names
|
||||
.iter()
|
||||
.map(|name| Ident::from_str_and_span(name, sp))
|
||||
.map(|name| Ident::from_str_and_span(name, span))
|
||||
.collect::<Vec<Ident>>();
|
||||
|
||||
// The `vi_idents` will be bound, solely in the catch-all, to
|
||||
@ -1218,7 +1218,7 @@ impl<'a> MethodDef<'a> {
|
||||
.iter()
|
||||
.map(|name| {
|
||||
let vi_suffix = format!("{}_vi", &name[..]);
|
||||
Ident::from_str_and_span(&vi_suffix, trait_.span)
|
||||
Ident::from_str_and_span(&vi_suffix, span)
|
||||
})
|
||||
.collect::<Vec<Ident>>();
|
||||
|
||||
@ -1248,7 +1248,7 @@ impl<'a> MethodDef<'a> {
|
||||
self_arg_name,
|
||||
ast::Mutability::Not,
|
||||
);
|
||||
(cx.pat(sp, PatKind::Ref(p, ast::Mutability::Not)), idents)
|
||||
(cx.pat(span, PatKind::Ref(p, ast::Mutability::Not)), idents)
|
||||
};
|
||||
|
||||
// A single arm has form (&VariantK, &VariantK, ...) => BodyK
|
||||
@ -1267,7 +1267,7 @@ impl<'a> MethodDef<'a> {
|
||||
}
|
||||
|
||||
// Here is the pat = `(&VariantK, &VariantK, ...)`
|
||||
let single_pat = cx.pat_tuple(sp, subpats);
|
||||
let single_pat = cx.pat_tuple(span, subpats);
|
||||
|
||||
// For the BodyK, we need to delegate to our caller,
|
||||
// passing it an EnumMatching to indicate which case
|
||||
@ -1284,7 +1284,7 @@ impl<'a> MethodDef<'a> {
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
// For each arg field of self, pull out its getter expr ...
|
||||
.map(|(field_index, (sp, opt_ident, self_getter_expr, attrs))| {
|
||||
.map(|(field_index, (span, opt_ident, self_getter_expr, attrs))| {
|
||||
// ... but FieldInfo also wants getter expr
|
||||
// for matching other arguments of Self type;
|
||||
// so walk across the *other* self_pats_idents
|
||||
@ -1307,7 +1307,7 @@ impl<'a> MethodDef<'a> {
|
||||
.collect::<Vec<P<Expr>>>();
|
||||
|
||||
FieldInfo {
|
||||
span: sp,
|
||||
span,
|
||||
name: opt_ident,
|
||||
self_: self_getter_expr,
|
||||
other: others,
|
||||
@ -1330,7 +1330,7 @@ impl<'a> MethodDef<'a> {
|
||||
&substructure,
|
||||
);
|
||||
|
||||
cx.arm(sp, single_pat, arm_expr)
|
||||
cx.arm(span, single_pat, arm_expr)
|
||||
})
|
||||
.collect();
|
||||
|
||||
@ -1353,12 +1353,12 @@ impl<'a> MethodDef<'a> {
|
||||
// Since we know that all the arguments will match if we reach
|
||||
// the match expression we add the unreachable intrinsics as the
|
||||
// result of the catch all which should help llvm in optimizing it
|
||||
Some(deriving::call_unreachable(cx, sp))
|
||||
Some(deriving::call_unreachable(cx, span))
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
if let Some(arm) = default {
|
||||
match_arms.push(cx.arm(sp, cx.pat_wild(sp), arm));
|
||||
match_arms.push(cx.arm(span, cx.pat_wild(span), arm));
|
||||
}
|
||||
|
||||
// We will usually need the catch-all after matching the
|
||||
@ -1392,23 +1392,23 @@ impl<'a> MethodDef<'a> {
|
||||
|
||||
// We also build an expression which checks whether all discriminants are equal
|
||||
// discriminant_test = __self0_vi == __self1_vi && __self0_vi == __self2_vi && ...
|
||||
let mut discriminant_test = cx.expr_bool(sp, true);
|
||||
let mut discriminant_test = cx.expr_bool(span, true);
|
||||
|
||||
let mut first_ident = None;
|
||||
for (&ident, self_arg) in iter::zip(&vi_idents, &self_args) {
|
||||
let self_addr = cx.expr_addr_of(sp, self_arg.clone());
|
||||
let self_addr = cx.expr_addr_of(span, self_arg.clone());
|
||||
let variant_value =
|
||||
deriving::call_intrinsic(cx, sp, sym::discriminant_value, vec![self_addr]);
|
||||
let let_stmt = cx.stmt_let(sp, false, ident, variant_value);
|
||||
deriving::call_intrinsic(cx, span, sym::discriminant_value, vec![self_addr]);
|
||||
let let_stmt = cx.stmt_let(span, false, ident, variant_value);
|
||||
index_let_stmts.push(let_stmt);
|
||||
|
||||
match first_ident {
|
||||
Some(first) => {
|
||||
let first_expr = cx.expr_ident(sp, first);
|
||||
let id = cx.expr_ident(sp, ident);
|
||||
let test = cx.expr_binary(sp, BinOpKind::Eq, first_expr, id);
|
||||
let first_expr = cx.expr_ident(span, first);
|
||||
let id = cx.expr_ident(span, ident);
|
||||
let test = cx.expr_binary(span, BinOpKind::Eq, first_expr, id);
|
||||
discriminant_test =
|
||||
cx.expr_binary(sp, BinOpKind::And, discriminant_test, test)
|
||||
cx.expr_binary(span, BinOpKind::And, discriminant_test, test)
|
||||
}
|
||||
None => {
|
||||
first_ident = Some(ident);
|
||||
@ -1430,8 +1430,8 @@ impl<'a> MethodDef<'a> {
|
||||
// them when they are fed as r-values into a tuple
|
||||
// expression; here add a layer of borrowing, turning
|
||||
// `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
|
||||
self_args.map_in_place(|self_arg| cx.expr_addr_of(sp, self_arg));
|
||||
let match_arg = cx.expr(sp, ast::ExprKind::Tup(self_args));
|
||||
self_args.map_in_place(|self_arg| cx.expr_addr_of(span, self_arg));
|
||||
let match_arg = cx.expr(span, ast::ExprKind::Tup(self_args));
|
||||
|
||||
// Lastly we create an expression which branches on all discriminants being equal
|
||||
// if discriminant_test {
|
||||
@ -1445,10 +1445,10 @@ impl<'a> MethodDef<'a> {
|
||||
// else {
|
||||
// <delegated expression referring to __self0_vi, et al.>
|
||||
// }
|
||||
let all_match = cx.expr_match(sp, match_arg, match_arms);
|
||||
let arm_expr = cx.expr_if(sp, discriminant_test, all_match, Some(arm_expr));
|
||||
let all_match = cx.expr_match(span, match_arg, match_arms);
|
||||
let arm_expr = cx.expr_if(span, discriminant_test, all_match, Some(arm_expr));
|
||||
index_let_stmts.push(cx.stmt_expr(arm_expr));
|
||||
cx.expr_block(cx.block(sp, index_let_stmts))
|
||||
cx.expr_block(cx.block(span, index_let_stmts))
|
||||
} else if variants.is_empty() {
|
||||
// As an additional wrinkle, For a zero-variant enum A,
|
||||
// currently the compiler
|
||||
@ -1499,16 +1499,16 @@ impl<'a> MethodDef<'a> {
|
||||
// derive Debug on such a type could here generate code
|
||||
// that needs the feature gate enabled.)
|
||||
|
||||
deriving::call_unreachable(cx, sp)
|
||||
deriving::call_unreachable(cx, span)
|
||||
} else {
|
||||
// Final wrinkle: the self_args are expressions that deref
|
||||
// down to desired places, but we cannot actually deref
|
||||
// them when they are fed as r-values into a tuple
|
||||
// expression; here add a layer of borrowing, turning
|
||||
// `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
|
||||
self_args.map_in_place(|self_arg| cx.expr_addr_of(sp, self_arg));
|
||||
let match_arg = cx.expr(sp, ast::ExprKind::Tup(self_args));
|
||||
cx.expr_match(sp, match_arg, match_arms)
|
||||
self_args.map_in_place(|self_arg| cx.expr_addr_of(span, self_arg));
|
||||
let match_arg = cx.expr(span, ast::ExprKind::Tup(self_args));
|
||||
cx.expr_match(span, match_arg, match_arms)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1556,11 +1556,9 @@ impl<'a> TraitDef<'a> {
|
||||
|
||||
let is_tuple = matches!(struct_def, ast::VariantData::Tuple(..));
|
||||
match (just_spans.is_empty(), named_idents.is_empty()) {
|
||||
(false, false) => cx.span_bug(
|
||||
self.span,
|
||||
"a struct with named and unnamed \
|
||||
fields in generic `derive`",
|
||||
),
|
||||
(false, false) => {
|
||||
cx.span_bug(self.span, "a struct with named and unnamed fields in generic `derive`")
|
||||
}
|
||||
// named fields
|
||||
(_, false) => Named(named_idents),
|
||||
// unnamed fields
|
||||
|
@ -211,14 +211,6 @@ fn mk_ty_param(
|
||||
cx.typaram(span, Ident::new(name, span), attrs.to_owned(), bounds, None)
|
||||
}
|
||||
|
||||
fn mk_generics(params: Vec<ast::GenericParam>, span: Span) -> Generics {
|
||||
Generics {
|
||||
params,
|
||||
where_clause: ast::WhereClause { has_where_token: false, predicates: Vec::new(), span },
|
||||
span,
|
||||
}
|
||||
}
|
||||
|
||||
/// Bounds on type parameters.
|
||||
#[derive(Clone)]
|
||||
pub struct Bounds {
|
||||
@ -236,7 +228,7 @@ impl Bounds {
|
||||
self_ty: Ident,
|
||||
self_generics: &Generics,
|
||||
) -> Generics {
|
||||
let generic_params = self
|
||||
let params = self
|
||||
.bounds
|
||||
.iter()
|
||||
.map(|t| {
|
||||
@ -245,7 +237,11 @@ impl Bounds {
|
||||
})
|
||||
.collect();
|
||||
|
||||
mk_generics(generic_params, span)
|
||||
Generics {
|
||||
params,
|
||||
where_clause: ast::WhereClause { has_where_token: false, predicates: Vec::new(), span },
|
||||
span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,8 +17,7 @@ use rustc_index::vec::IndexVec;
|
||||
use rustc_macros::HashStable_Generic;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::{def_id::LocalDefId, BytePos};
|
||||
use rustc_span::{MultiSpan, Span, DUMMY_SP};
|
||||
use rustc_span::{def_id::LocalDefId, BytePos, MultiSpan, Span, DUMMY_SP};
|
||||
use rustc_target::asm::InlineAsmRegOrRegClass;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
@ -526,12 +525,20 @@ pub struct GenericParam<'hir> {
|
||||
}
|
||||
|
||||
impl GenericParam<'hir> {
|
||||
pub fn bounds_span(&self) -> Option<Span> {
|
||||
self.bounds.iter().fold(None, |span, bound| {
|
||||
let span = span.map(|s| s.to(bound.span())).unwrap_or_else(|| bound.span());
|
||||
|
||||
Some(span)
|
||||
})
|
||||
pub fn bounds_span_for_suggestions(&self) -> Option<Span> {
|
||||
self.bounds
|
||||
.iter()
|
||||
.fold(None, |span: Option<Span>, bound| {
|
||||
// We include bounds that come from a `#[derive(_)]` but point at the user's code,
|
||||
// as we use this method to get a span appropriate for suggestions.
|
||||
if !bound.span().can_be_used_for_suggestions() {
|
||||
None
|
||||
} else {
|
||||
let span = span.map(|s| s.to(bound.span())).unwrap_or_else(|| bound.span());
|
||||
Some(span)
|
||||
}
|
||||
})
|
||||
.map(|sp| sp.shrink_to_hi())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -270,7 +270,7 @@ pub fn suggest_constraining_type_param(
|
||||
// `where` clause instead of `trait Base<T: Copy = String>: Super<T>`.
|
||||
&& !matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. })
|
||||
{
|
||||
if let Some(bounds_span) = param.bounds_span() {
|
||||
if let Some(span) = param.bounds_span_for_suggestions() {
|
||||
// If user has provided some bounds, suggest restricting them:
|
||||
//
|
||||
// fn foo<T: Foo>(t: T) { ... }
|
||||
@ -284,7 +284,7 @@ pub fn suggest_constraining_type_param(
|
||||
// --
|
||||
// |
|
||||
// replace with: `T: Bar +`
|
||||
suggest_restrict(bounds_span.shrink_to_hi());
|
||||
suggest_restrict(span);
|
||||
} else {
|
||||
// If user hasn't provided any bounds, suggest adding a new one:
|
||||
//
|
||||
|
@ -1735,7 +1735,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
||||
(generics.span, format!("<{}>", ident))
|
||||
};
|
||||
// Do not suggest if this is coming from macro expansion.
|
||||
if !span.from_expansion() {
|
||||
if span.can_be_used_for_suggestions() {
|
||||
return Some((
|
||||
span.shrink_to_hi(),
|
||||
msg,
|
||||
@ -1803,7 +1803,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
|
||||
);
|
||||
err.span_label(lifetime_ref.span, "undeclared lifetime");
|
||||
let mut suggests_in_band = false;
|
||||
let mut suggest_note = true;
|
||||
let mut suggested_spans = vec![];
|
||||
for missing in &self.missing_named_lifetime_spots {
|
||||
match missing {
|
||||
MissingLifetimeSpot::Generics(generics) => {
|
||||
@ -1821,23 +1821,17 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
|
||||
suggests_in_band = true;
|
||||
(generics.span, format!("<{}>", lifetime_ref))
|
||||
};
|
||||
if !span.from_expansion() {
|
||||
if suggested_spans.contains(&span) {
|
||||
continue;
|
||||
}
|
||||
suggested_spans.push(span);
|
||||
if span.can_be_used_for_suggestions() {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
&format!("consider introducing lifetime `{}` here", lifetime_ref),
|
||||
sugg,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else if suggest_note {
|
||||
suggest_note = false; // Avoid displaying the same help multiple times.
|
||||
err.span_label(
|
||||
span,
|
||||
&format!(
|
||||
"lifetime `{}` is missing in item created through this procedural \
|
||||
macro",
|
||||
lifetime_ref,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
MissingLifetimeSpot::HigherRanked { span, span_type } => {
|
||||
|
@ -551,6 +551,16 @@ impl Span {
|
||||
matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _))
|
||||
}
|
||||
|
||||
/// Gate suggestions that would not be appropriate in a context the user didn't write.
|
||||
pub fn can_be_used_for_suggestions(self) -> bool {
|
||||
!self.from_expansion()
|
||||
// FIXME: If this span comes from a `derive` macro but it points at code the user wrote,
|
||||
// the callsite span and the span will be pointing at different places. It also means that
|
||||
// we can safely provide suggestions on this span.
|
||||
|| (matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _))
|
||||
&& self.parent_callsite().map(|p| (p.lo(), p.hi())) != Some((self.lo(), self.hi())))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn with_root_ctxt(lo: BytePos, hi: BytePos) -> Span {
|
||||
Span::new(lo, hi, SyntaxContext::root(), None)
|
||||
|
@ -262,8 +262,8 @@ fn suggest_restriction(
|
||||
match generics
|
||||
.params
|
||||
.iter()
|
||||
.map(|p| p.bounds_span().unwrap_or(p.span))
|
||||
.filter(|&span| generics.span.contains(span) && span.desugaring_kind().is_none())
|
||||
.map(|p| p.bounds_span_for_suggestions().unwrap_or(p.span.shrink_to_hi()))
|
||||
.filter(|&span| generics.span.contains(span) && span.can_be_used_for_suggestions())
|
||||
.max_by_key(|span| span.hi())
|
||||
{
|
||||
// `fn foo(t: impl Trait)`
|
||||
@ -271,7 +271,7 @@ fn suggest_restriction(
|
||||
None => (generics.span, format!("<{}>", type_param)),
|
||||
// `fn foo<A>(t: impl Trait)`
|
||||
// ^^^ suggest `<A, T: Trait>` here
|
||||
Some(span) => (span.shrink_to_hi(), format!(", {}", type_param)),
|
||||
Some(span) => (span, format!(", {}", type_param)),
|
||||
},
|
||||
// `fn foo(t: impl Trait)`
|
||||
// ^ suggest `where <T as Trait>::A: Bound`
|
||||
|
@ -177,11 +177,9 @@ crate fn placeholder_type_error(
|
||||
sugg.push((arg.span, (*type_name).to_string()));
|
||||
} else {
|
||||
let last = generics.iter().last().unwrap();
|
||||
sugg.push((
|
||||
// Account for bounds, we want `fn foo<T: E, K>(_: K)` not `fn foo<T, K: E>(_: K)`.
|
||||
last.bounds_span().unwrap_or(last.span).shrink_to_hi(),
|
||||
format!(", {}", type_name),
|
||||
));
|
||||
// Account for bounds, we want `fn foo<T: E, K>(_: K)` not `fn foo<T, K: E>(_: K)`.
|
||||
let span = last.bounds_span_for_suggestions().unwrap_or(last.span.shrink_to_hi());
|
||||
sugg.push((span, format!(", {}", type_name)));
|
||||
}
|
||||
|
||||
let mut err = bad_placeholder_type(tcx, placeholder_types, kind);
|
||||
|
@ -10,6 +10,10 @@ note: required because of the requirements on the impl of `IntoNullable` for `<C
|
||||
LL | impl<T: NotNull> IntoNullable for T {
|
||||
| ^^^^^^^^^^^^ ^
|
||||
= note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
help: consider further restricting the associated type
|
||||
|
|
||||
LL | Expr: Expression<SqlType=<Col::SqlType as IntoNullable>::Nullable>, <Col as Expression>::SqlType: NotNull,
|
||||
| +++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,8 +1,17 @@
|
||||
#[derive(Clone, Copy)]
|
||||
//~^ ERROR the trait `Copy` may not be implemented for this type
|
||||
struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
|
||||
struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
|
||||
//~^ ERROR cannot find type `NotDefined` in this scope
|
||||
//~| ERROR cannot find type `NotDefined` in this scope
|
||||
//~| ERROR cannot find type `N` in this scope
|
||||
//~| ERROR cannot find type `N` in this scope
|
||||
//~| ERROR `i32` is not an iterator
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
//~^ ERROR the trait `Copy` may not be implemented for this type
|
||||
struct Bar<T>(T, N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
|
||||
//~^ ERROR cannot find type `NotDefined` in this scope
|
||||
//~| ERROR cannot find type `N` in this scope
|
||||
//~| ERROR `i32` is not an iterator
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,20 +1,61 @@
|
||||
error[E0412]: cannot find type `NotDefined` in this scope
|
||||
error[E0412]: cannot find type `N` in this scope
|
||||
--> $DIR/issue-50480.rs:3:12
|
||||
|
|
||||
LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
|
||||
| ^^^^^^^^^^ not found in this scope
|
||||
LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
|
||||
| -^ not found in this scope
|
||||
| |
|
||||
| help: you might be missing a type parameter: `<N>`
|
||||
|
||||
error[E0412]: cannot find type `NotDefined` in this scope
|
||||
--> $DIR/issue-50480.rs:3:15
|
||||
|
|
||||
LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
|
||||
| ^^^^^^^^^^ not found in this scope
|
||||
|
||||
error[E0412]: cannot find type `N` in this scope
|
||||
--> $DIR/issue-50480.rs:3:12
|
||||
|
|
||||
LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
|
||||
| ^^^^^^^^^^ not found in this scope
|
||||
LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
|
||||
| -^ not found in this scope
|
||||
| |
|
||||
| help: you might be missing a type parameter: `<N>`
|
||||
|
||||
error[E0412]: cannot find type `NotDefined` in this scope
|
||||
--> $DIR/issue-50480.rs:3:15
|
||||
|
|
||||
LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
|
||||
| - ^^^^^^^^^^ not found in this scope
|
||||
| |
|
||||
| help: you might be missing a type parameter: `<NotDefined>`
|
||||
|
||||
error[E0412]: cannot find type `N` in this scope
|
||||
--> $DIR/issue-50480.rs:12:18
|
||||
|
|
||||
LL | struct Bar<T>(T, N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
|
||||
| - ^
|
||||
| |
|
||||
| similarly named type parameter `T` defined here
|
||||
|
|
||||
help: a type parameter with a similar name exists
|
||||
|
|
||||
LL | struct Bar<T>(T, T, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
|
||||
| ~
|
||||
help: you might be missing a type parameter
|
||||
|
|
||||
LL | struct Bar<T, N>(T, N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
|
||||
| +++
|
||||
|
||||
error[E0412]: cannot find type `NotDefined` in this scope
|
||||
--> $DIR/issue-50480.rs:12:21
|
||||
|
|
||||
LL | struct Bar<T>(T, N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
|
||||
| ^^^^^^^^^^ not found in this scope
|
||||
|
||||
error[E0277]: `i32` is not an iterator
|
||||
--> $DIR/issue-50480.rs:3:24
|
||||
--> $DIR/issue-50480.rs:3:27
|
||||
|
|
||||
LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator
|
||||
LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator
|
||||
|
|
||||
= help: the trait `Iterator` is not implemented for `i32`
|
||||
= note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
|
||||
@ -25,14 +66,36 @@ error[E0204]: the trait `Copy` may not be implemented for this type
|
||||
LL | #[derive(Clone, Copy)]
|
||||
| ^^^^
|
||||
LL |
|
||||
LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
|
||||
| -------- ------ this field does not implement `Copy`
|
||||
| |
|
||||
| this field does not implement `Copy`
|
||||
LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
|
||||
| -------- ------ this field does not implement `Copy`
|
||||
| |
|
||||
| this field does not implement `Copy`
|
||||
|
|
||||
= note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
error[E0277]: `i32` is not an iterator
|
||||
--> $DIR/issue-50480.rs:12:33
|
||||
|
|
||||
LL | struct Bar<T>(T, N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator
|
||||
|
|
||||
= help: the trait `Iterator` is not implemented for `i32`
|
||||
= note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
|
||||
|
||||
error[E0204]: the trait `Copy` may not be implemented for this type
|
||||
--> $DIR/issue-50480.rs:10:17
|
||||
|
|
||||
LL | #[derive(Clone, Copy)]
|
||||
| ^^^^
|
||||
LL |
|
||||
LL | struct Bar<T>(T, N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
|
||||
| -------- ------ this field does not implement `Copy`
|
||||
| |
|
||||
| this field does not implement `Copy`
|
||||
|
|
||||
= note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 10 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0204, E0277, E0412.
|
||||
For more information about an error, try `rustc --explain E0204`.
|
||||
|
@ -11,9 +11,8 @@ LL | a: &'b str,
|
||||
error[E0261]: use of undeclared lifetime name `'b`
|
||||
--> $DIR/undeclared-lifetime-used-in-debug-macro-issue-70152.rs:3:9
|
||||
|
|
||||
LL | #[derive(Eq, PartialEq)]
|
||||
| -- lifetime `'b` is missing in item created through this procedural macro
|
||||
LL | struct Test {
|
||||
| - help: consider introducing lifetime `'b` here: `<'b>`
|
||||
LL | a: &'b str,
|
||||
| ^^ undeclared lifetime
|
||||
|
|
||||
|
89
src/test/ui/suggestions/derive-macro-missing-bounds.rs
Normal file
89
src/test/ui/suggestions/derive-macro-missing-bounds.rs
Normal file
@ -0,0 +1,89 @@
|
||||
mod a {
|
||||
use std::fmt::{Debug, Formatter, Result};
|
||||
struct Inner<T>(T);
|
||||
|
||||
impl Debug for Inner<()> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Outer<T>(Inner<T>); //~ ERROR `a::Inner<T>` doesn't implement `Debug`
|
||||
}
|
||||
|
||||
mod b {
|
||||
use std::fmt::{Debug, Formatter, Result};
|
||||
struct Inner<T>(T);
|
||||
|
||||
impl<T: Debug> Debug for Inner<T> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Outer<T>(Inner<T>);
|
||||
}
|
||||
|
||||
mod c {
|
||||
use std::fmt::{Debug, Formatter, Result};
|
||||
struct Inner<T>(T);
|
||||
trait Trait {}
|
||||
|
||||
impl<T: Debug + Trait> Debug for Inner<T> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Outer<T>(Inner<T>); //~ ERROR the trait bound `T: c::Trait` is not satisfied
|
||||
}
|
||||
|
||||
mod d {
|
||||
use std::fmt::{Debug, Formatter, Result};
|
||||
struct Inner<T>(T);
|
||||
trait Trait {}
|
||||
|
||||
impl<T> Debug for Inner<T> where T: Debug, T: Trait {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Outer<T>(Inner<T>); //~ ERROR the trait bound `T: d::Trait` is not satisfied
|
||||
}
|
||||
|
||||
mod e {
|
||||
use std::fmt::{Debug, Formatter, Result};
|
||||
struct Inner<T>(T);
|
||||
trait Trait {}
|
||||
|
||||
impl<T> Debug for Inner<T> where T: Debug + Trait {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Outer<T>(Inner<T>); //~ ERROR the trait bound `T: e::Trait` is not satisfied
|
||||
}
|
||||
|
||||
mod f {
|
||||
use std::fmt::{Debug, Formatter, Result};
|
||||
struct Inner<T>(T);
|
||||
trait Trait {}
|
||||
|
||||
impl<T: Debug> Debug for Inner<T> where T: Trait {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Outer<T>(Inner<T>); //~ ERROR the trait bound `T: f::Trait` is not satisfied
|
||||
}
|
||||
|
||||
fn main() {}
|
107
src/test/ui/suggestions/derive-macro-missing-bounds.stderr
Normal file
107
src/test/ui/suggestions/derive-macro-missing-bounds.stderr
Normal file
@ -0,0 +1,107 @@
|
||||
error[E0277]: `a::Inner<T>` doesn't implement `Debug`
|
||||
--> $DIR/derive-macro-missing-bounds.rs:12:21
|
||||
|
|
||||
LL | #[derive(Debug)]
|
||||
| ----- in this derive macro expansion
|
||||
LL | struct Outer<T>(Inner<T>);
|
||||
| ^^^^^^^^ `a::Inner<T>` cannot be formatted using `{:?}`
|
||||
|
|
||||
= help: the trait `Debug` is not implemented for `a::Inner<T>`
|
||||
= note: add `#[derive(Debug)]` to `a::Inner<T>` or manually `impl Debug for a::Inner<T>`
|
||||
= note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
|
||||
|
|
||||
LL | struct Outer<T>(Inner<T>) where a::Inner<T>: Debug;
|
||||
| ++++++++++++++++++++++++
|
||||
|
||||
error[E0277]: the trait bound `T: c::Trait` is not satisfied
|
||||
--> $DIR/derive-macro-missing-bounds.rs:41:21
|
||||
|
|
||||
LL | #[derive(Debug)]
|
||||
| ----- in this derive macro expansion
|
||||
LL | struct Outer<T>(Inner<T>);
|
||||
| ^^^^^^^^ the trait `c::Trait` is not implemented for `T`
|
||||
|
|
||||
note: required because of the requirements on the impl of `Debug` for `c::Inner<T>`
|
||||
--> $DIR/derive-macro-missing-bounds.rs:34:28
|
||||
|
|
||||
LL | impl<T: Debug + Trait> Debug for Inner<T> {
|
||||
| ^^^^^ ^^^^^^^^
|
||||
= note: 1 redundant requirement hidden
|
||||
= note: required because of the requirements on the impl of `Debug` for `&c::Inner<T>`
|
||||
= note: required for the cast to the object type `dyn Debug`
|
||||
= note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
help: consider restricting type parameter `T`
|
||||
|
|
||||
LL | struct Outer<T: c::Trait>(Inner<T>);
|
||||
| ++++++++++
|
||||
|
||||
error[E0277]: the trait bound `T: d::Trait` is not satisfied
|
||||
--> $DIR/derive-macro-missing-bounds.rs:56:21
|
||||
|
|
||||
LL | #[derive(Debug)]
|
||||
| ----- in this derive macro expansion
|
||||
LL | struct Outer<T>(Inner<T>);
|
||||
| ^^^^^^^^ the trait `d::Trait` is not implemented for `T`
|
||||
|
|
||||
note: required because of the requirements on the impl of `Debug` for `d::Inner<T>`
|
||||
--> $DIR/derive-macro-missing-bounds.rs:49:13
|
||||
|
|
||||
LL | impl<T> Debug for Inner<T> where T: Debug, T: Trait {
|
||||
| ^^^^^ ^^^^^^^^
|
||||
= note: 1 redundant requirement hidden
|
||||
= note: required because of the requirements on the impl of `Debug` for `&d::Inner<T>`
|
||||
= note: required for the cast to the object type `dyn Debug`
|
||||
= note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
help: consider restricting type parameter `T`
|
||||
|
|
||||
LL | struct Outer<T: d::Trait>(Inner<T>);
|
||||
| ++++++++++
|
||||
|
||||
error[E0277]: the trait bound `T: e::Trait` is not satisfied
|
||||
--> $DIR/derive-macro-missing-bounds.rs:71:21
|
||||
|
|
||||
LL | #[derive(Debug)]
|
||||
| ----- in this derive macro expansion
|
||||
LL | struct Outer<T>(Inner<T>);
|
||||
| ^^^^^^^^ the trait `e::Trait` is not implemented for `T`
|
||||
|
|
||||
note: required because of the requirements on the impl of `Debug` for `e::Inner<T>`
|
||||
--> $DIR/derive-macro-missing-bounds.rs:64:13
|
||||
|
|
||||
LL | impl<T> Debug for Inner<T> where T: Debug + Trait {
|
||||
| ^^^^^ ^^^^^^^^
|
||||
= note: 1 redundant requirement hidden
|
||||
= note: required because of the requirements on the impl of `Debug` for `&e::Inner<T>`
|
||||
= note: required for the cast to the object type `dyn Debug`
|
||||
= note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
help: consider restricting type parameter `T`
|
||||
|
|
||||
LL | struct Outer<T: e::Trait>(Inner<T>);
|
||||
| ++++++++++
|
||||
|
||||
error[E0277]: the trait bound `T: f::Trait` is not satisfied
|
||||
--> $DIR/derive-macro-missing-bounds.rs:86:21
|
||||
|
|
||||
LL | #[derive(Debug)]
|
||||
| ----- in this derive macro expansion
|
||||
LL | struct Outer<T>(Inner<T>);
|
||||
| ^^^^^^^^ the trait `f::Trait` is not implemented for `T`
|
||||
|
|
||||
note: required because of the requirements on the impl of `Debug` for `f::Inner<T>`
|
||||
--> $DIR/derive-macro-missing-bounds.rs:79:20
|
||||
|
|
||||
LL | impl<T: Debug> Debug for Inner<T> where T: Trait {
|
||||
| ^^^^^ ^^^^^^^^
|
||||
= note: 1 redundant requirement hidden
|
||||
= note: required because of the requirements on the impl of `Debug` for `&f::Inner<T>`
|
||||
= note: required for the cast to the object type `dyn Debug`
|
||||
= note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
help: consider restricting type parameter `T`
|
||||
|
|
||||
LL | struct Outer<T: f::Trait>(Inner<T>);
|
||||
| ++++++++++
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
Loading…
x
Reference in New Issue
Block a user