Implement #[derive(From)]
This commit is contained in:
parent
c0839ea7d2
commit
1f3a7471bf
10 changed files with 530 additions and 6 deletions
|
|
@ -222,6 +222,15 @@ builtin_macros_format_unused_args = multiple unused formatting arguments
|
|||
|
||||
builtin_macros_format_use_positional = consider using a positional formatting argument instead
|
||||
|
||||
builtin_macros_derive_from_wrong_target = `#[derive(From)]` used on {$kind}
|
||||
|
||||
builtin_macros_derive_from_wrong_field_count = `#[derive(From)]` used on a struct with {$multiple_fields ->
|
||||
[true] multiple fields
|
||||
*[false] no fields
|
||||
}
|
||||
|
||||
builtin_macros_derive_from_usage_note = `#[derive(From)]` can only be used on structs with exactly one field
|
||||
|
||||
builtin_macros_multiple_default_attrs = multiple `#[default]` attributes
|
||||
.note = only one `#[default]` attribute is needed
|
||||
.label = `#[default]` used here
|
||||
|
|
|
|||
|
|
@ -1,13 +1,132 @@
|
|||
use rustc_ast as ast;
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::{Span, sym};
|
||||
use rustc_ast::{ItemKind, VariantData};
|
||||
use rustc_errors::MultiSpan;
|
||||
use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt};
|
||||
use rustc_span::{Ident, Span, kw, sym};
|
||||
use thin_vec::thin_vec;
|
||||
|
||||
use crate::deriving::generic::ty::{Bounds, Path, PathKind, Ty};
|
||||
use crate::deriving::generic::{
|
||||
BlockOrExpr, FieldlessVariantsStrategy, MethodDef, SubstructureFields, TraitDef,
|
||||
combine_substructure,
|
||||
};
|
||||
use crate::deriving::pathvec_std;
|
||||
use crate::errors;
|
||||
|
||||
/// Generate an implementation of the `From` trait, provided that `item`
|
||||
/// is a struct or a tuple struct with exactly one field.
|
||||
pub(crate) fn expand_deriving_from(
|
||||
cx: &ExtCtxt<'_>,
|
||||
span: Span,
|
||||
mitem: &ast::MetaItem,
|
||||
item: &Annotatable,
|
||||
annotatable: &Annotatable,
|
||||
push: &mut dyn FnMut(Annotatable),
|
||||
is_const: bool,
|
||||
) {
|
||||
let Annotatable::Item(item) = &annotatable else {
|
||||
cx.dcx().bug("derive(From) used on something else than an item");
|
||||
};
|
||||
|
||||
// #[derive(From)] is currently usable only on structs with exactly one field.
|
||||
let field = if let ItemKind::Struct(_, _, data) = &item.kind
|
||||
&& let [field] = data.fields()
|
||||
{
|
||||
Some(field.clone())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let from_type = match &field {
|
||||
Some(field) => Ty::AstTy(field.ty.clone()),
|
||||
// We don't have a type to put into From<...> if we don't have a single field, so just put
|
||||
// unit there.
|
||||
None => Ty::Unit,
|
||||
};
|
||||
let path =
|
||||
Path::new_(pathvec_std!(convert::From), vec![Box::new(from_type.clone())], PathKind::Std);
|
||||
|
||||
// Generate code like this:
|
||||
//
|
||||
// struct S(u32);
|
||||
// #[automatically_derived]
|
||||
// impl ::core::convert::From<u32> for S {
|
||||
// #[inline]
|
||||
// fn from(value: u32) -> S {
|
||||
// Self(value)
|
||||
// }
|
||||
// }
|
||||
let from_trait_def = TraitDef {
|
||||
span,
|
||||
path,
|
||||
skip_path_as_bound: true,
|
||||
needs_copy_as_bound_if_packed: false,
|
||||
additional_bounds: Vec::new(),
|
||||
supports_unions: false,
|
||||
methods: vec![MethodDef {
|
||||
name: sym::from,
|
||||
generics: Bounds { bounds: vec![] },
|
||||
explicit_self: false,
|
||||
nonself_args: vec![(from_type, sym::value)],
|
||||
ret_ty: Ty::Self_,
|
||||
attributes: thin_vec![cx.attr_word(sym::inline, span)],
|
||||
fieldless_variants_strategy: FieldlessVariantsStrategy::Default,
|
||||
combine_substructure: combine_substructure(Box::new(|cx, span, substructure| {
|
||||
let Some(field) = &field else {
|
||||
let item_span = item.kind.ident().map(|ident| ident.span).unwrap_or(item.span);
|
||||
let err_span = MultiSpan::from_spans(vec![span, item_span]);
|
||||
let error = match &item.kind {
|
||||
ItemKind::Struct(_, _, data) => {
|
||||
cx.dcx().emit_err(errors::DeriveFromWrongFieldCount {
|
||||
span: err_span,
|
||||
multiple_fields: data.fields().len() > 1,
|
||||
})
|
||||
}
|
||||
ItemKind::Enum(_, _, _) | ItemKind::Union(_, _, _) => {
|
||||
cx.dcx().emit_err(errors::DeriveFromWrongTarget {
|
||||
span: err_span,
|
||||
kind: &format!("{} {}", item.kind.article(), item.kind.descr()),
|
||||
})
|
||||
}
|
||||
_ => cx.dcx().bug("Invalid derive(From) ADT input"),
|
||||
};
|
||||
|
||||
return BlockOrExpr::new_expr(DummyResult::raw_expr(span, Some(error)));
|
||||
};
|
||||
|
||||
let self_kw = Ident::new(kw::SelfUpper, span);
|
||||
let expr: Box<ast::Expr> = match substructure.fields {
|
||||
SubstructureFields::StaticStruct(variant, _) => match variant {
|
||||
// Self {
|
||||
// field: value
|
||||
// }
|
||||
VariantData::Struct { .. } => cx.expr_struct_ident(
|
||||
span,
|
||||
self_kw,
|
||||
thin_vec![cx.field_imm(
|
||||
span,
|
||||
field.ident.unwrap(),
|
||||
cx.expr_ident(span, Ident::new(sym::value, span))
|
||||
)],
|
||||
),
|
||||
// Self(value)
|
||||
VariantData::Tuple(_, _) => cx.expr_call_ident(
|
||||
span,
|
||||
self_kw,
|
||||
thin_vec![cx.expr_ident(span, Ident::new(sym::value, span))],
|
||||
),
|
||||
variant => {
|
||||
cx.dcx().bug(format!("Invalid derive(From) ADT variant: {variant:?}"));
|
||||
}
|
||||
},
|
||||
_ => cx.dcx().bug("Invalid derive(From) ADT input"),
|
||||
};
|
||||
BlockOrExpr::new_expr(expr)
|
||||
})),
|
||||
}],
|
||||
associated_types: Vec::new(),
|
||||
is_const,
|
||||
is_staged_api_crate: cx.ecfg.features.staged_api(),
|
||||
};
|
||||
|
||||
from_trait_def.expand(cx, mitem, annotatable, push);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
//! when specifying impls to be derived.
|
||||
|
||||
pub(crate) use Ty::*;
|
||||
use rustc_ast::{self as ast, Expr, GenericArg, GenericParamKind, Generics, SelfKind};
|
||||
use rustc_ast::{self as ast, Expr, GenericArg, GenericParamKind, Generics, SelfKind, TyKind};
|
||||
use rustc_expand::base::ExtCtxt;
|
||||
use rustc_span::source_map::respan;
|
||||
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw};
|
||||
|
|
@ -65,7 +65,7 @@ impl Path {
|
|||
}
|
||||
}
|
||||
|
||||
/// A type. Supports pointers, Self, and literals.
|
||||
/// A type. Supports pointers, Self, literals, unit or an arbitrary AST path.
|
||||
#[derive(Clone)]
|
||||
pub(crate) enum Ty {
|
||||
Self_,
|
||||
|
|
@ -76,6 +76,8 @@ pub(crate) enum Ty {
|
|||
Path(Path),
|
||||
/// For () return types.
|
||||
Unit,
|
||||
/// An arbitrary type.
|
||||
AstTy(Box<ast::Ty>),
|
||||
}
|
||||
|
||||
pub(crate) fn self_ref() -> Ty {
|
||||
|
|
@ -101,6 +103,7 @@ impl Ty {
|
|||
let ty = ast::TyKind::Tup(ThinVec::new());
|
||||
cx.ty(span, ty)
|
||||
}
|
||||
AstTy(ty) => ty.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -132,6 +135,10 @@ impl Ty {
|
|||
cx.path_all(span, false, vec![self_ty], params)
|
||||
}
|
||||
Path(p) => p.to_path(cx, span, self_ty, generics),
|
||||
AstTy(ty) => match &ty.kind {
|
||||
TyKind::Path(_, path) => path.clone(),
|
||||
_ => cx.dcx().span_bug(span, "non-path in a path in generic `derive`"),
|
||||
},
|
||||
Ref(..) => cx.dcx().span_bug(span, "ref in a path in generic `derive`"),
|
||||
Unit => cx.dcx().span_bug(span, "unit in a path in generic `derive`"),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -446,6 +446,24 @@ pub(crate) struct DefaultHasArg {
|
|||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_derive_from_wrong_target)]
|
||||
#[note(builtin_macros_derive_from_usage_note)]
|
||||
pub(crate) struct DeriveFromWrongTarget<'a> {
|
||||
#[primary_span]
|
||||
pub(crate) span: MultiSpan,
|
||||
pub(crate) kind: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_derive_from_wrong_field_count)]
|
||||
#[note(builtin_macros_derive_from_usage_note)]
|
||||
pub(crate) struct DeriveFromWrongFieldCount {
|
||||
#[primary_span]
|
||||
pub(crate) span: MultiSpan,
|
||||
pub(crate) multiple_fields: bool,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_derive_macro_call)]
|
||||
pub(crate) struct DeriveMacroCall {
|
||||
|
|
|
|||
|
|
@ -392,6 +392,7 @@ symbols! {
|
|||
__D,
|
||||
__H,
|
||||
__S,
|
||||
__T,
|
||||
__awaitee,
|
||||
__try_var,
|
||||
_t,
|
||||
|
|
@ -745,6 +746,7 @@ symbols! {
|
|||
contracts_ensures,
|
||||
contracts_internals,
|
||||
contracts_requires,
|
||||
convert,
|
||||
convert_identity,
|
||||
copy,
|
||||
copy_closures,
|
||||
|
|
@ -2331,6 +2333,7 @@ symbols! {
|
|||
va_start,
|
||||
val,
|
||||
validity,
|
||||
value,
|
||||
values,
|
||||
var,
|
||||
variant_count,
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#![crate_type = "lib"]
|
||||
#![allow(dead_code)]
|
||||
#![allow(deprecated)]
|
||||
#![feature(derive_from)]
|
||||
|
||||
// Empty struct.
|
||||
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||
|
|
@ -38,6 +39,14 @@ struct PackedPoint {
|
|||
y: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, From, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||
struct TupleSingleField(u32);
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, From, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||
struct SingleField {
|
||||
foo: bool,
|
||||
}
|
||||
|
||||
// A large struct. Note: because this derives `Copy`, it gets the simple
|
||||
// `clone` implemention that just does `*self`.
|
||||
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||
|
|
@ -86,7 +95,7 @@ struct PackedManualCopy(u32);
|
|||
impl Copy for PackedManualCopy {}
|
||||
|
||||
// A struct with an unsized field. Some derives are not usable in this case.
|
||||
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[derive(Debug, From, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||
struct Unsized([u32]);
|
||||
|
||||
trait Trait {
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#![crate_type = "lib"]
|
||||
#![allow(dead_code)]
|
||||
#![allow(deprecated)]
|
||||
#![feature(derive_from)]
|
||||
#[macro_use]
|
||||
extern crate std;
|
||||
#[prelude_import]
|
||||
|
|
@ -249,6 +250,148 @@ impl ::core::cmp::Ord for PackedPoint {
|
|||
}
|
||||
}
|
||||
|
||||
struct TupleSingleField(u32);
|
||||
#[automatically_derived]
|
||||
impl ::core::clone::Clone for TupleSingleField {
|
||||
#[inline]
|
||||
fn clone(&self) -> TupleSingleField {
|
||||
let _: ::core::clone::AssertParamIsClone<u32>;
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl ::core::marker::Copy for TupleSingleField { }
|
||||
#[automatically_derived]
|
||||
impl ::core::fmt::Debug for TupleSingleField {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
::core::fmt::Formatter::debug_tuple_field1_finish(f,
|
||||
"TupleSingleField", &&self.0)
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl ::core::default::Default for TupleSingleField {
|
||||
#[inline]
|
||||
fn default() -> TupleSingleField {
|
||||
TupleSingleField(::core::default::Default::default())
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl ::core::convert::From<u32> for TupleSingleField {
|
||||
#[inline]
|
||||
fn from(value: u32) -> TupleSingleField { Self(value) }
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl ::core::hash::Hash for TupleSingleField {
|
||||
#[inline]
|
||||
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
|
||||
::core::hash::Hash::hash(&self.0, state)
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl ::core::marker::StructuralPartialEq for TupleSingleField { }
|
||||
#[automatically_derived]
|
||||
impl ::core::cmp::PartialEq for TupleSingleField {
|
||||
#[inline]
|
||||
fn eq(&self, other: &TupleSingleField) -> bool { self.0 == other.0 }
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl ::core::cmp::Eq for TupleSingleField {
|
||||
#[inline]
|
||||
#[doc(hidden)]
|
||||
#[coverage(off)]
|
||||
fn assert_receiver_is_total_eq(&self) -> () {
|
||||
let _: ::core::cmp::AssertParamIsEq<u32>;
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl ::core::cmp::PartialOrd for TupleSingleField {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &TupleSingleField)
|
||||
-> ::core::option::Option<::core::cmp::Ordering> {
|
||||
::core::cmp::PartialOrd::partial_cmp(&self.0, &other.0)
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl ::core::cmp::Ord for TupleSingleField {
|
||||
#[inline]
|
||||
fn cmp(&self, other: &TupleSingleField) -> ::core::cmp::Ordering {
|
||||
::core::cmp::Ord::cmp(&self.0, &other.0)
|
||||
}
|
||||
}
|
||||
|
||||
struct SingleField {
|
||||
foo: bool,
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl ::core::clone::Clone for SingleField {
|
||||
#[inline]
|
||||
fn clone(&self) -> SingleField {
|
||||
let _: ::core::clone::AssertParamIsClone<bool>;
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl ::core::marker::Copy for SingleField { }
|
||||
#[automatically_derived]
|
||||
impl ::core::fmt::Debug for SingleField {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
::core::fmt::Formatter::debug_struct_field1_finish(f, "SingleField",
|
||||
"foo", &&self.foo)
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl ::core::default::Default for SingleField {
|
||||
#[inline]
|
||||
fn default() -> SingleField {
|
||||
SingleField { foo: ::core::default::Default::default() }
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl ::core::convert::From<bool> for SingleField {
|
||||
#[inline]
|
||||
fn from(value: bool) -> SingleField { Self { foo: value } }
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl ::core::hash::Hash for SingleField {
|
||||
#[inline]
|
||||
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
|
||||
::core::hash::Hash::hash(&self.foo, state)
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl ::core::marker::StructuralPartialEq for SingleField { }
|
||||
#[automatically_derived]
|
||||
impl ::core::cmp::PartialEq for SingleField {
|
||||
#[inline]
|
||||
fn eq(&self, other: &SingleField) -> bool { self.foo == other.foo }
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl ::core::cmp::Eq for SingleField {
|
||||
#[inline]
|
||||
#[doc(hidden)]
|
||||
#[coverage(off)]
|
||||
fn assert_receiver_is_total_eq(&self) -> () {
|
||||
let _: ::core::cmp::AssertParamIsEq<bool>;
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl ::core::cmp::PartialOrd for SingleField {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &SingleField)
|
||||
-> ::core::option::Option<::core::cmp::Ordering> {
|
||||
::core::cmp::PartialOrd::partial_cmp(&self.foo, &other.foo)
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl ::core::cmp::Ord for SingleField {
|
||||
#[inline]
|
||||
fn cmp(&self, other: &SingleField) -> ::core::cmp::Ordering {
|
||||
::core::cmp::Ord::cmp(&self.foo, &other.foo)
|
||||
}
|
||||
}
|
||||
|
||||
// A large struct. Note: because this derives `Copy`, it gets the simple
|
||||
// `clone` implemention that just does `*self`.
|
||||
struct Big {
|
||||
|
|
@ -572,6 +715,11 @@ impl ::core::fmt::Debug for Unsized {
|
|||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl ::core::convert::From<[u32]> for Unsized {
|
||||
#[inline]
|
||||
fn from(value: [u32]) -> Unsized { Self(value) }
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl ::core::hash::Hash for Unsized {
|
||||
#[inline]
|
||||
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
|
||||
|
|
|
|||
38
tests/ui/deriving/deriving-from-wrong-target.rs
Normal file
38
tests/ui/deriving/deriving-from-wrong-target.rs
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
//@ edition: 2021
|
||||
//@ check-fail
|
||||
|
||||
#![feature(derive_from)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
#[derive(From)]
|
||||
//~^ ERROR `#[derive(From)]` used on a struct with no fields
|
||||
struct S1;
|
||||
|
||||
#[derive(From)]
|
||||
//~^ ERROR `#[derive(From)]` used on a struct with no fields
|
||||
struct S2 {}
|
||||
|
||||
#[derive(From)]
|
||||
//~^ ERROR `#[derive(From)]` used on a struct with multiple fields
|
||||
struct S3(u32, bool);
|
||||
|
||||
#[derive(From)]
|
||||
//~^ ERROR `#[derive(From)]` used on a struct with multiple fields
|
||||
struct S4 {
|
||||
a: u32,
|
||||
b: bool,
|
||||
}
|
||||
|
||||
#[derive(From)]
|
||||
//~^ ERROR `#[derive(From)]` used on an enum
|
||||
enum E1 {}
|
||||
|
||||
#[derive(From)]
|
||||
//~^ ERROR the size for values of type `T` cannot be known at compilation time [E0277]
|
||||
//~| ERROR the size for values of type `T` cannot be known at compilation time [E0277]
|
||||
struct SUnsizedField<T: ?Sized> {
|
||||
last: T,
|
||||
//~^ ERROR the size for values of type `T` cannot be known at compilation time [E0277]
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
115
tests/ui/deriving/deriving-from-wrong-target.stderr
Normal file
115
tests/ui/deriving/deriving-from-wrong-target.stderr
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
error: `#[derive(From)]` used on a struct with no fields
|
||||
--> $DIR/deriving-from-wrong-target.rs:7:10
|
||||
|
|
||||
LL | #[derive(From)]
|
||||
| ^^^^
|
||||
LL |
|
||||
LL | struct S1;
|
||||
| ^^
|
||||
|
|
||||
= note: `#[derive(From)]` can only be used on structs with exactly one field
|
||||
|
||||
error: `#[derive(From)]` used on a struct with no fields
|
||||
--> $DIR/deriving-from-wrong-target.rs:11:10
|
||||
|
|
||||
LL | #[derive(From)]
|
||||
| ^^^^
|
||||
LL |
|
||||
LL | struct S2 {}
|
||||
| ^^
|
||||
|
|
||||
= note: `#[derive(From)]` can only be used on structs with exactly one field
|
||||
|
||||
error: `#[derive(From)]` used on a struct with multiple fields
|
||||
--> $DIR/deriving-from-wrong-target.rs:15:10
|
||||
|
|
||||
LL | #[derive(From)]
|
||||
| ^^^^
|
||||
LL |
|
||||
LL | struct S3(u32, bool);
|
||||
| ^^
|
||||
|
|
||||
= note: `#[derive(From)]` can only be used on structs with exactly one field
|
||||
|
||||
error: `#[derive(From)]` used on a struct with multiple fields
|
||||
--> $DIR/deriving-from-wrong-target.rs:19:10
|
||||
|
|
||||
LL | #[derive(From)]
|
||||
| ^^^^
|
||||
LL |
|
||||
LL | struct S4 {
|
||||
| ^^
|
||||
|
|
||||
= note: `#[derive(From)]` can only be used on structs with exactly one field
|
||||
|
||||
error: `#[derive(From)]` used on an enum
|
||||
--> $DIR/deriving-from-wrong-target.rs:26:10
|
||||
|
|
||||
LL | #[derive(From)]
|
||||
| ^^^^
|
||||
LL |
|
||||
LL | enum E1 {}
|
||||
| ^^
|
||||
|
|
||||
= note: `#[derive(From)]` can only be used on structs with exactly one field
|
||||
|
||||
error[E0277]: the size for values of type `T` cannot be known at compilation time
|
||||
--> $DIR/deriving-from-wrong-target.rs:30:10
|
||||
|
|
||||
LL | #[derive(From)]
|
||||
| ^^^^ doesn't have a size known at compile-time
|
||||
...
|
||||
LL | struct SUnsizedField<T: ?Sized> {
|
||||
| - this type parameter needs to be `Sized`
|
||||
|
|
||||
note: required by an implicit `Sized` bound in `From`
|
||||
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
||||
help: consider removing the `?Sized` bound to make the type parameter `Sized`
|
||||
|
|
||||
LL - struct SUnsizedField<T: ?Sized> {
|
||||
LL + struct SUnsizedField<T> {
|
||||
|
|
||||
|
||||
error[E0277]: the size for values of type `T` cannot be known at compilation time
|
||||
--> $DIR/deriving-from-wrong-target.rs:30:10
|
||||
|
|
||||
LL | #[derive(From)]
|
||||
| ^^^^ doesn't have a size known at compile-time
|
||||
...
|
||||
LL | struct SUnsizedField<T: ?Sized> {
|
||||
| - this type parameter needs to be `Sized`
|
||||
|
|
||||
note: required because it appears within the type `SUnsizedField<T>`
|
||||
--> $DIR/deriving-from-wrong-target.rs:33:8
|
||||
|
|
||||
LL | struct SUnsizedField<T: ?Sized> {
|
||||
| ^^^^^^^^^^^^^
|
||||
= note: the return type of a function must have a statically known size
|
||||
help: consider removing the `?Sized` bound to make the type parameter `Sized`
|
||||
|
|
||||
LL - struct SUnsizedField<T: ?Sized> {
|
||||
LL + struct SUnsizedField<T> {
|
||||
|
|
||||
|
||||
error[E0277]: the size for values of type `T` cannot be known at compilation time
|
||||
--> $DIR/deriving-from-wrong-target.rs:34:11
|
||||
|
|
||||
LL | struct SUnsizedField<T: ?Sized> {
|
||||
| - this type parameter needs to be `Sized`
|
||||
LL | last: T,
|
||||
| ^ doesn't have a size known at compile-time
|
||||
|
|
||||
= help: unsized fn params are gated as an unstable feature
|
||||
help: consider removing the `?Sized` bound to make the type parameter `Sized`
|
||||
|
|
||||
LL - struct SUnsizedField<T: ?Sized> {
|
||||
LL + struct SUnsizedField<T> {
|
||||
|
|
||||
help: function arguments must have a statically known size, borrowed types always have a known size
|
||||
|
|
||||
LL | last: &T,
|
||||
| +
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
58
tests/ui/deriving/deriving-from.rs
Normal file
58
tests/ui/deriving/deriving-from.rs
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
//@ edition: 2021
|
||||
//@ run-pass
|
||||
|
||||
#![feature(derive_from)]
|
||||
|
||||
#[derive(From)]
|
||||
struct TupleSimple(u32);
|
||||
|
||||
#[derive(From)]
|
||||
struct TupleNonPathType([u32; 4]);
|
||||
|
||||
#[derive(From)]
|
||||
struct TupleWithRef<'a, T>(&'a T);
|
||||
|
||||
#[derive(From)]
|
||||
struct TupleSWithBound<T: std::fmt::Debug>(T);
|
||||
|
||||
#[derive(From)]
|
||||
struct RawIdentifier {
|
||||
r#use: u32,
|
||||
}
|
||||
|
||||
#[derive(From)]
|
||||
struct Field {
|
||||
foo: bool,
|
||||
}
|
||||
|
||||
#[derive(From)]
|
||||
struct Const<const C: usize> {
|
||||
foo: [u32; C],
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let a = 42u32;
|
||||
let b: [u32; 4] = [0, 1, 2, 3];
|
||||
let c = true;
|
||||
|
||||
let s1: TupleSimple = a.into();
|
||||
assert_eq!(s1.0, a);
|
||||
|
||||
let s2: TupleNonPathType = b.into();
|
||||
assert_eq!(s2.0, b);
|
||||
|
||||
let s3: TupleWithRef<u32> = (&a).into();
|
||||
assert_eq!(s3.0, &a);
|
||||
|
||||
let s4: TupleSWithBound<u32> = a.into();
|
||||
assert_eq!(s4.0, a);
|
||||
|
||||
let s5: RawIdentifier = a.into();
|
||||
assert_eq!(s5.r#use, a);
|
||||
|
||||
let s6: Field = c.into();
|
||||
assert_eq!(s6.foo, c);
|
||||
|
||||
let s7: Const<4> = b.into();
|
||||
assert_eq!(s7.foo, b);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue