diff options
Diffstat (limited to 'compiler/rustc_macros/src/diagnostics/utils.rs')
-rw-r--r-- | compiler/rustc_macros/src/diagnostics/utils.rs | 67 |
1 files changed, 37 insertions, 30 deletions
diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs index 6f52a3de1..27b8f676f 100644 --- a/compiler/rustc_macros/src/diagnostics/utils.rs +++ b/compiler/rustc_macros/src/diagnostics/utils.rs @@ -80,7 +80,7 @@ fn report_error_if_not_applied_to_ty( path: &[&str], ty_name: &str, ) -> Result<(), DiagnosticDeriveError> { - if !type_matches_path(info.ty, path) { + if !type_matches_path(info.ty.inner_type(), path) { report_type_error(attr, ty_name)?; } @@ -105,8 +105,8 @@ pub(crate) fn report_error_if_not_applied_to_span( attr: &Attribute, info: &FieldInfo<'_>, ) -> Result<(), DiagnosticDeriveError> { - if !type_matches_path(info.ty, &["rustc_span", "Span"]) - && !type_matches_path(info.ty, &["rustc_errors", "MultiSpan"]) + if !type_matches_path(info.ty.inner_type(), &["rustc_span", "Span"]) + && !type_matches_path(info.ty.inner_type(), &["rustc_errors", "MultiSpan"]) { report_type_error(attr, "`Span` or `MultiSpan`")?; } @@ -115,44 +115,50 @@ pub(crate) fn report_error_if_not_applied_to_span( } /// Inner type of a field and type of wrapper. +#[derive(Copy, Clone)] pub(crate) enum FieldInnerTy<'ty> { /// Field is wrapped in a `Option<$inner>`. Option(&'ty Type), /// Field is wrapped in a `Vec<$inner>`. Vec(&'ty Type), /// Field isn't wrapped in an outer type. - None, + Plain(&'ty Type), } impl<'ty> FieldInnerTy<'ty> { /// Returns inner type for a field, if there is one. /// - /// - If `ty` is an `Option`, returns `FieldInnerTy::Option { inner: (inner type) }`. - /// - If `ty` is a `Vec`, returns `FieldInnerTy::Vec { inner: (inner type) }`. - /// - Otherwise returns `None`. + /// - If `ty` is an `Option<Inner>`, returns `FieldInnerTy::Option(Inner)`. + /// - If `ty` is a `Vec<Inner>`, returns `FieldInnerTy::Vec(Inner)`. + /// - Otherwise returns `FieldInnerTy::Plain(ty)`. pub(crate) fn from_type(ty: &'ty Type) -> Self { - let variant: &dyn Fn(&'ty Type) -> FieldInnerTy<'ty> = - if type_matches_path(ty, &["std", "option", "Option"]) { - &FieldInnerTy::Option - } else if type_matches_path(ty, &["std", "vec", "Vec"]) { - &FieldInnerTy::Vec - } else { - return FieldInnerTy::None; + fn single_generic_type(ty: &Type) -> &Type { + let Type::Path(ty_path) = ty else { + panic!("expected path type"); }; - if let Type::Path(ty_path) = ty { let path = &ty_path.path; let ty = path.segments.iter().last().unwrap(); - if let syn::PathArguments::AngleBracketed(bracketed) = &ty.arguments { - if bracketed.args.len() == 1 { - if let syn::GenericArgument::Type(ty) = &bracketed.args[0] { - return variant(ty); - } - } - } + let syn::PathArguments::AngleBracketed(bracketed) = &ty.arguments else { + panic!("expected bracketed generic arguments"); + }; + + assert_eq!(bracketed.args.len(), 1); + + let syn::GenericArgument::Type(ty) = &bracketed.args[0] else { + panic!("expected generic parameter to be a type generic"); + }; + + ty } - unreachable!(); + if type_matches_path(ty, &["std", "option", "Option"]) { + FieldInnerTy::Option(single_generic_type(ty)) + } else if type_matches_path(ty, &["std", "vec", "Vec"]) { + FieldInnerTy::Vec(single_generic_type(ty)) + } else { + FieldInnerTy::Plain(ty) + } } /// Returns `true` if `FieldInnerTy::with` will result in iteration for this inner type (i.e. @@ -160,15 +166,16 @@ impl<'ty> FieldInnerTy<'ty> { pub(crate) fn will_iterate(&self) -> bool { match self { FieldInnerTy::Vec(..) => true, - FieldInnerTy::Option(..) | FieldInnerTy::None => false, + FieldInnerTy::Option(..) | FieldInnerTy::Plain(_) => false, } } - /// Returns `Option` containing inner type if there is one. - pub(crate) fn inner_type(&self) -> Option<&'ty Type> { + /// Returns the inner type. + pub(crate) fn inner_type(&self) -> &'ty Type { match self { - FieldInnerTy::Option(inner) | FieldInnerTy::Vec(inner) => Some(inner), - FieldInnerTy::None => None, + FieldInnerTy::Option(inner) | FieldInnerTy::Vec(inner) | FieldInnerTy::Plain(inner) => { + inner + } } } @@ -185,7 +192,7 @@ impl<'ty> FieldInnerTy<'ty> { #inner } }, - FieldInnerTy::None => quote! { #inner }, + FieldInnerTy::Plain(..) => quote! { #inner }, } } } @@ -194,7 +201,7 @@ impl<'ty> FieldInnerTy<'ty> { /// `generate_*` methods from walking the attributes themselves. pub(crate) struct FieldInfo<'a> { pub(crate) binding: &'a BindingInfo<'a>, - pub(crate) ty: &'a Type, + pub(crate) ty: FieldInnerTy<'a>, pub(crate) span: &'a proc_macro2::Span, } |