@@ -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:: { CoroutineDesugaring , CoroutineKind , CoroutineSource , Node } ;
26- use rustc_hir:: { Expr , HirId } ;
25+ use rustc_hir:: { CoroutineDesugaring , 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 } ;
@@ -3200,63 +3199,80 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
32003199 err. help ( "unsized locals are gated as an unstable feature" ) ;
32013200 }
32023201 }
3203- ObligationCauseCode :: SizedArgumentType ( ty_span) => {
3204- if let Some ( span) = ty_span {
3205- let trait_len = if let ty:: PredicateKind :: Clause ( clause) =
3206- predicate. kind ( ) . skip_binder ( )
3207- && let ty:: ClauseKind :: Trait ( trait_pred) = clause
3208- && let ty:: Dynamic ( preds, ..) = trait_pred. self_ty ( ) . kind ( )
3209- {
3210- let span = if let Ok ( snippet) =
3211- self . tcx . sess . source_map ( ) . span_to_snippet ( span)
3212- && snippet. starts_with ( "dyn " )
3213- {
3214- let pos = snippet. len ( ) - snippet[ 3 ..] . trim_start ( ) . len ( ) ;
3215- span. with_hi ( span. lo ( ) + BytePos ( pos as u32 ) )
3216- } else {
3217- span. shrink_to_lo ( )
3218- } ;
3219- err. span_suggestion_verbose (
3220- span,
3221- "you can use `impl Trait` as the argument type" ,
3222- "impl " . to_string ( ) ,
3223- Applicability :: MaybeIncorrect ,
3224- ) ;
3225- preds
3226- . iter ( )
3227- . filter ( |pred| {
3228- // We only want to count `dyn Foo + Bar`, not `dyn Foo<Bar>`,
3229- // because the later doesn't need parentheses.
3230- matches ! (
3231- pred. skip_binder( ) ,
3232- ty:: ExistentialPredicate :: Trait ( _)
3233- | ty:: ExistentialPredicate :: AutoTrait ( _)
3234- )
3235- } )
3236- . count ( )
3237- } else {
3238- 1
3239- } ;
3240- let sugg = if trait_len == 1 {
3241- vec ! [ ( span. shrink_to_lo( ) , "&" . to_string( ) ) ]
3242- } else if let Ok ( snippet) = self . tcx . sess . source_map ( ) . span_to_snippet ( span)
3243- && snippet. starts_with ( '(' )
3244- {
3245- // We don't want to suggest `&((dyn Foo + Bar))` when we have
3246- // `(dyn Foo + Bar)`.
3247- vec ! [ ( span. shrink_to_lo( ) , "&" . to_string( ) ) ]
3248- } else {
3249- vec ! [
3250- ( span. shrink_to_lo( ) , "&(" . to_string( ) ) ,
3251- ( span. shrink_to_hi( ) , ")" . to_string( ) ) ,
3252- ]
3253- } ;
3254- err. multipart_suggestion_verbose (
3255- "function arguments must have a statically known size, borrowed types \
3256- always have a known size",
3257- sugg,
3258- Applicability :: MachineApplicable ,
3259- ) ;
3202+ ObligationCauseCode :: SizedArgumentType ( hir_id) => {
3203+ let mut ty = None ;
3204+ let borrowed_msg = "function arguments must have a statically known size, borrowed \
3205+ types always have a known size";
3206+ if let Some ( hir_id) = hir_id
3207+ && let Some ( hir:: Node :: Param ( param) ) = self . tcx . hir ( ) . find ( hir_id)
3208+ && let Some ( item) = self . tcx . hir ( ) . find_parent ( hir_id)
3209+ && let Some ( decl) = item. fn_decl ( )
3210+ && let Some ( t) = decl. inputs . iter ( ) . find ( |t| param. ty_span . contains ( t. span ) )
3211+ {
3212+ // We use `contains` because the type might be surrounded by parentheses,
3213+ // which makes `ty_span` and `t.span` disagree with each other, but one
3214+ // fully contains the other: `foo: (dyn Foo + Bar)`
3215+ // ^-------------^
3216+ // ||
3217+ // |t.span
3218+ // param._ty_span
3219+ ty = Some ( t) ;
3220+ } else if let Some ( hir_id) = hir_id
3221+ && let Some ( hir:: Node :: Ty ( t) ) = self . tcx . hir ( ) . find ( hir_id)
3222+ {
3223+ ty = Some ( t) ;
3224+ }
3225+ if let Some ( ty) = ty {
3226+ match ty. kind {
3227+ hir:: TyKind :: TraitObject ( traits, _, _) => {
3228+ let ( span, kw) = match traits {
3229+ [ first, ..] if first. span . lo ( ) == ty. span . lo ( ) => {
3230+ // Missing `dyn` in front of trait object.
3231+ ( ty. span . shrink_to_lo ( ) , "dyn " )
3232+ }
3233+ [ first, ..] => ( ty. span . until ( first. span ) , "" ) ,
3234+ [ ] => span_bug ! ( ty. span, "trait object with no traits: {ty:?}" ) ,
3235+ } ;
3236+ let needs_parens = traits. len ( ) != 1 ;
3237+ err. span_suggestion_verbose (
3238+ span,
3239+ "you can use `impl Trait` as the argument type" ,
3240+ "impl " . to_string ( ) ,
3241+ Applicability :: MaybeIncorrect ,
3242+ ) ;
3243+ let sugg = if !needs_parens {
3244+ vec ! [ ( span. shrink_to_lo( ) , format!( "&{kw}" ) ) ]
3245+ } else {
3246+ vec ! [
3247+ ( span. shrink_to_lo( ) , format!( "&({kw}" ) ) ,
3248+ ( ty. span. shrink_to_hi( ) , ")" . to_string( ) ) ,
3249+ ]
3250+ } ;
3251+ err. multipart_suggestion_verbose (
3252+ borrowed_msg,
3253+ sugg,
3254+ Applicability :: MachineApplicable ,
3255+ ) ;
3256+ }
3257+ hir:: TyKind :: Slice ( _ty) => {
3258+ err. span_suggestion_verbose (
3259+ ty. span . shrink_to_lo ( ) ,
3260+ "function arguments must have a statically known size, borrowed \
3261+ slices always have a known size",
3262+ "&" ,
3263+ Applicability :: MachineApplicable ,
3264+ ) ;
3265+ }
3266+ hir:: TyKind :: Path ( _) => {
3267+ err. span_suggestion_verbose (
3268+ ty. span . shrink_to_lo ( ) ,
3269+ borrowed_msg,
3270+ "&" ,
3271+ Applicability :: MachineApplicable ,
3272+ ) ;
3273+ }
3274+ _ => { }
3275+ }
32603276 } else {
32613277 err. note ( "all function arguments must have a statically known size" ) ;
32623278 }
0 commit comments