@@ -19,11 +19,10 @@ use rustc_errors::{
1919use rustc_hir as hir;
2020use rustc_hir:: def:: { DefKind , Res } ;
2121use rustc_hir:: def_id:: DefId ;
22- use rustc_hir:: intravisit:: Visitor ;
22+ use rustc_hir:: intravisit:: { Map , Visitor } ;
2323use rustc_hir:: is_range_literal;
2424use rustc_hir:: lang_items:: LangItem ;
25- use rustc_hir:: { CoroutineKind , CoroutineSource , Node } ;
26- use rustc_hir:: { Expr , HirId } ;
25+ use rustc_hir:: { CoroutineKind , CoroutineSource , Expr , HirId , Node } ;
2726use rustc_infer:: infer:: error_reporting:: TypeErrCtxt ;
2827use rustc_infer:: infer:: type_variable:: { TypeVariableOrigin , TypeVariableOriginKind } ;
2928use rustc_infer:: infer:: { BoundRegionConversionTime , DefineOpaqueTypes , InferOk } ;
@@ -3029,63 +3028,80 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
30293028 err. help ( "unsized locals are gated as an unstable feature" ) ;
30303029 }
30313030 }
3032- ObligationCauseCode :: SizedArgumentType ( ty_span) => {
3033- if let Some ( span) = ty_span {
3034- let trait_len = if let ty:: PredicateKind :: Clause ( clause) =
3035- predicate. kind ( ) . skip_binder ( )
3036- && let ty:: ClauseKind :: Trait ( trait_pred) = clause
3037- && let ty:: Dynamic ( preds, ..) = trait_pred. self_ty ( ) . kind ( )
3038- {
3039- let span = if let Ok ( snippet) =
3040- self . tcx . sess . source_map ( ) . span_to_snippet ( span)
3041- && snippet. starts_with ( "dyn " )
3042- {
3043- let pos = snippet. len ( ) - snippet[ 3 ..] . trim_start ( ) . len ( ) ;
3044- span. with_hi ( span. lo ( ) + BytePos ( pos as u32 ) )
3045- } else {
3046- span. shrink_to_lo ( )
3047- } ;
3048- err. span_suggestion_verbose (
3049- span,
3050- "you can use `impl Trait` as the argument type" ,
3051- "impl " . to_string ( ) ,
3052- Applicability :: MaybeIncorrect ,
3053- ) ;
3054- preds
3055- . iter ( )
3056- . filter ( |pred| {
3057- // We only want to count `dyn Foo + Bar`, not `dyn Foo<Bar>`,
3058- // because the later doesn't need parentheses.
3059- matches ! (
3060- pred. skip_binder( ) ,
3061- ty:: ExistentialPredicate :: Trait ( _)
3062- | ty:: ExistentialPredicate :: AutoTrait ( _)
3063- )
3064- } )
3065- . count ( )
3066- } else {
3067- 1
3068- } ;
3069- let sugg = if trait_len == 1 {
3070- vec ! [ ( span. shrink_to_lo( ) , "&" . to_string( ) ) ]
3071- } else if let Ok ( snippet) = self . tcx . sess . source_map ( ) . span_to_snippet ( span)
3072- && snippet. starts_with ( '(' )
3073- {
3074- // We don't want to suggest `&((dyn Foo + Bar))` when we have
3075- // `(dyn Foo + Bar)`.
3076- vec ! [ ( span. shrink_to_lo( ) , "&" . to_string( ) ) ]
3077- } else {
3078- vec ! [
3079- ( span. shrink_to_lo( ) , "&(" . to_string( ) ) ,
3080- ( span. shrink_to_hi( ) , ")" . to_string( ) ) ,
3081- ]
3082- } ;
3083- err. multipart_suggestion_verbose (
3084- "function arguments must have a statically known size, borrowed types \
3085- always have a known size",
3086- sugg,
3087- Applicability :: MachineApplicable ,
3088- ) ;
3031+ ObligationCauseCode :: SizedArgumentType ( hir_id) => {
3032+ let mut ty = None ;
3033+ let borrowed_msg = "function arguments must have a statically known size, borrowed \
3034+ types always have a known size";
3035+ if let Some ( hir_id) = hir_id
3036+ && let Some ( hir:: Node :: Param ( param) ) = self . tcx . hir ( ) . find ( hir_id)
3037+ && let Some ( item) = self . tcx . hir ( ) . find_parent ( hir_id)
3038+ && let Some ( decl) = item. fn_decl ( )
3039+ && let Some ( t) = decl. inputs . iter ( ) . find ( |t| param. ty_span . contains ( t. span ) )
3040+ {
3041+ // We use `contains` because the type might be surrounded by parentheses,
3042+ // which makes `ty_span` and `t.span` disagree with each other, but one
3043+ // fully contains the other: `foo: (dyn Foo + Bar)`
3044+ // ^-------------^
3045+ // ||
3046+ // |t.span
3047+ // param._ty_span
3048+ ty = Some ( t) ;
3049+ } else if let Some ( hir_id) = hir_id
3050+ && let Some ( hir:: Node :: Ty ( t) ) = self . tcx . hir ( ) . find ( hir_id)
3051+ {
3052+ ty = Some ( t) ;
3053+ }
3054+ if let Some ( ty) = ty {
3055+ match ty. kind {
3056+ hir:: TyKind :: TraitObject ( traits, _, _) => {
3057+ let ( span, kw) = match traits {
3058+ [ first, ..] if first. span . lo ( ) == ty. span . lo ( ) => {
3059+ // Missing `dyn` in front of trait object.
3060+ ( ty. span . shrink_to_lo ( ) , "dyn " )
3061+ }
3062+ [ first, ..] => ( ty. span . until ( first. span ) , "" ) ,
3063+ [ ] => span_bug ! ( ty. span, "trait object with no traits: {ty:?}" ) ,
3064+ } ;
3065+ let needs_parens = traits. len ( ) != 1 ;
3066+ err. span_suggestion_verbose (
3067+ span,
3068+ "you can use `impl Trait` as the argument type" ,
3069+ "impl " . to_string ( ) ,
3070+ Applicability :: MaybeIncorrect ,
3071+ ) ;
3072+ let sugg = if !needs_parens {
3073+ vec ! [ ( span. shrink_to_lo( ) , format!( "&{kw}" ) ) ]
3074+ } else {
3075+ vec ! [
3076+ ( span. shrink_to_lo( ) , format!( "&({kw}" ) ) ,
3077+ ( ty. span. shrink_to_hi( ) , ")" . to_string( ) ) ,
3078+ ]
3079+ } ;
3080+ err. multipart_suggestion_verbose (
3081+ borrowed_msg,
3082+ sugg,
3083+ Applicability :: MachineApplicable ,
3084+ ) ;
3085+ }
3086+ hir:: TyKind :: Slice ( _ty) => {
3087+ err. span_suggestion_verbose (
3088+ ty. span . shrink_to_lo ( ) ,
3089+ "function arguments must have a statically known size, borrowed \
3090+ slices always have a known size",
3091+ "&" ,
3092+ Applicability :: MachineApplicable ,
3093+ ) ;
3094+ }
3095+ hir:: TyKind :: Path ( _) => {
3096+ err. span_suggestion_verbose (
3097+ ty. span . shrink_to_lo ( ) ,
3098+ borrowed_msg,
3099+ "&" ,
3100+ Applicability :: MachineApplicable ,
3101+ ) ;
3102+ }
3103+ _ => { }
3104+ }
30893105 } else {
30903106 err. note ( "all function arguments must have a statically known size" ) ;
30913107 }
0 commit comments