@@ -4436,6 +4436,41 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
4436
4436
}
4437
4437
}
4438
4438
4439
+ /// If the type failed selection but the trait is implemented for `(T,)`, suggest that the user
4440
+ /// creates a unary tuple
4441
+ ///
4442
+ /// This is a common gotcha when using libraries that emulate variadic functions with traits for tuples.
4443
+ pub ( super ) fn suggest_tuple_wrapping (
4444
+ & self ,
4445
+ err : & mut Diag < ' _ > ,
4446
+ root_obligation : & PredicateObligation < ' tcx > ,
4447
+ obligation : & PredicateObligation < ' tcx > ,
4448
+ ) {
4449
+ let ObligationCauseCode :: FunctionArg { arg_hir_id, .. } = obligation. cause . code ( ) else {
4450
+ return ;
4451
+ } ;
4452
+
4453
+ let Some ( root_pred) = root_obligation. predicate . as_trait_clause ( ) else { return } ;
4454
+
4455
+ let trait_ref = root_pred. map_bound ( |root_pred| {
4456
+ root_pred
4457
+ . trait_ref
4458
+ . with_self_ty ( self . tcx , Ty :: new_tup ( self . tcx , & [ root_pred. trait_ref . self_ty ( ) ] ) )
4459
+ } ) ;
4460
+
4461
+ let obligation =
4462
+ Obligation :: new ( self . tcx , obligation. cause . clone ( ) , obligation. param_env , trait_ref) ;
4463
+
4464
+ if self . predicate_must_hold_modulo_regions ( & obligation) {
4465
+ let arg_span = self . tcx . hir ( ) . span ( * arg_hir_id) ;
4466
+ err. multipart_suggestion_verbose (
4467
+ format ! ( "use a unary tuple instead" ) ,
4468
+ vec ! [ ( arg_span. shrink_to_lo( ) , "(" . into( ) ) , ( arg_span. shrink_to_hi( ) , ",)" . into( ) ) ] ,
4469
+ Applicability :: MaybeIncorrect ,
4470
+ ) ;
4471
+ }
4472
+ }
4473
+
4439
4474
pub ( super ) fn explain_hrtb_projection (
4440
4475
& self ,
4441
4476
diag : & mut Diag < ' _ > ,
0 commit comments