@@ -19,11 +19,10 @@ use rustc_errors::{
19
19
use rustc_hir as hir;
20
20
use rustc_hir:: def:: { DefKind , Res } ;
21
21
use rustc_hir:: def_id:: DefId ;
22
- use rustc_hir:: intravisit:: Visitor ;
22
+ use rustc_hir:: intravisit:: { Map , Visitor } ;
23
23
use rustc_hir:: is_range_literal;
24
24
use 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 } ;
27
26
use rustc_infer:: infer:: error_reporting:: TypeErrCtxt ;
28
27
use rustc_infer:: infer:: type_variable:: { TypeVariableOrigin , TypeVariableOriginKind } ;
29
28
use rustc_infer:: infer:: { BoundRegionConversionTime , DefineOpaqueTypes , InferOk } ;
@@ -3029,63 +3028,80 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
3029
3028
err. help ( "unsized locals are gated as an unstable feature" ) ;
3030
3029
}
3031
3030
}
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
+ }
3089
3105
} else {
3090
3106
err. note ( "all function arguments must have a statically known size" ) ;
3091
3107
}
0 commit comments