@@ -10,7 +10,7 @@ use rustc_hir::def_id::DefId;
1010use rustc_hir:: intravisit:: Visitor ;
1111use rustc_hir:: { Expr , ExprKind , HirId , LangItem , Node , QPath , is_range_literal} ;
1212use rustc_hir_analysis:: check:: potentially_plural_count;
13- use rustc_hir_analysis:: hir_ty_lowering:: { HirTyLowerer , PermitVariants } ;
13+ use rustc_hir_analysis:: hir_ty_lowering:: { HirTyLowerer , IsMethodCall , PermitVariants } ;
1414use rustc_index:: IndexVec ;
1515use rustc_infer:: infer:: { BoundRegionConversionTime , DefineOpaqueTypes , InferOk , TypeTrace } ;
1616use rustc_middle:: ty:: adjustment:: AllowTwoPhase ;
@@ -195,6 +195,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
195195 call_span : Span ,
196196 // Expression of the call site
197197 call_expr : & ' tcx hir:: Expr < ' tcx > ,
198+ is_method : IsMethodCall ,
198199 // Types (as defined in the *signature* of the target function)
199200 formal_input_tys : & [ Ty < ' tcx > ] ,
200201 formal_output : Ty < ' tcx > ,
@@ -206,7 +207,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
206207 c_variadic : bool ,
207208 // Whether the arguments have been bundled in a tuple (ex: closures)
208209 tuple_arguments : TupleArgumentsFlag ,
209- // The DefId for the function being called, for better error messages
210+ // The DefId for the function being called, for callee bound checks and
211+ // better error messages
210212 fn_def_id : Option < DefId > ,
211213 ) {
212214 let tcx = self . tcx ;
@@ -290,6 +292,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
290292 formal_input_tys
291293 } ;
292294
295+ for & ty in formal_input_tys {
296+ ocx. register_obligation ( traits:: Obligation :: new (
297+ self . tcx ,
298+ self . misc ( call_span) ,
299+ self . param_env ,
300+ ty:: ClauseKind :: WellFormed ( ty. into ( ) ) ,
301+ ) ) ;
302+ }
303+
293304 if !ocx. try_evaluate_obligations ( ) . is_empty ( ) {
294305 return Err ( TypeError :: Mismatch ) ;
295306 }
@@ -309,8 +320,83 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
309320
310321 let mut err_code = E0061 ;
311322
323+ let mut expected_meets_callee_bounds = Vec :: with_capacity ( formal_input_tys. len ( ) ) ;
324+ expected_meets_callee_bounds. resize ( formal_input_tys. len ( ) , true ) ;
325+
326+ // Check whether the expected inputs satisfy the callee's where bounds.
327+ // This is skipped for the old solver: attempting trait solving there can
328+ // trigger an overflow, which is a fatal error in the old solver but is
329+ // treated as mere ambiguity by the next solver.
330+ if self . next_trait_solver ( )
331+ && let Some ( expected_input_tys) = & expected_input_tys
332+ && let Some ( fn_def_id) = fn_def_id
333+ // We don't need to check bounds for closures as they are already in the current
334+ // body's param env.
335+ && self . tcx . def_kind ( fn_def_id) != DefKind :: Closure
336+ {
337+ self . probe ( |_| {
338+ let new_args = self . fresh_args_for_item ( call_span, fn_def_id) ;
339+ let fn_sig = self . tcx . fn_sig ( fn_def_id) . instantiate ( self . tcx , new_args) ;
340+ let fn_sig = self . instantiate_binder_with_fresh_vars (
341+ call_span,
342+ BoundRegionConversionTime :: FnCall ,
343+ fn_sig,
344+ ) ;
345+ let ocx = ObligationCtxt :: new ( self ) ;
346+ let origin = self . misc ( call_span) ;
347+ let fn_sig = ocx. normalize ( & origin, self . param_env , fn_sig) ;
348+
349+ let bound_input_tys = fn_sig. inputs ( ) ;
350+ let bound_input_tys = if is_method == IsMethodCall :: Yes {
351+ & bound_input_tys[ 1 ..]
352+ } else {
353+ & bound_input_tys[ ..]
354+ } ;
355+
356+ let fn_bounds = self . tcx . predicates_of ( fn_def_id) . instantiate ( self . tcx , new_args) ;
357+ let fn_bounds = traits:: predicates_for_generics (
358+ |_, sp| self . misc ( sp) ,
359+ self . param_env ,
360+ fn_bounds,
361+ ) ;
362+ ocx. register_obligations ( fn_bounds) ;
363+
364+ // perf: We reuse this by cloning rather than repeating the above lines
365+ let preds = ocx. into_pending_obligations ( ) ;
366+
367+ assert_eq ! ( bound_input_tys. len( ) , formal_input_tys. len( ) , ) ;
368+ for idx in 0 ..formal_input_tys. len ( ) {
369+ let meets_bounds = self
370+ . probe ( |_| {
371+ let ocx = ObligationCtxt :: new ( self ) ;
372+ ocx. register_obligations ( preds. clone ( ) ) ;
373+ ocx. eq (
374+ & origin,
375+ self . param_env ,
376+ bound_input_tys[ idx] ,
377+ expected_input_tys[ idx] ,
378+ ) ?;
379+ if ocx. try_evaluate_obligations ( ) . is_empty ( ) {
380+ Ok ( ( ) )
381+ } else {
382+ Err ( TypeError :: Mismatch )
383+ }
384+ } )
385+ . is_ok ( ) ;
386+ expected_meets_callee_bounds[ idx] = meets_bounds;
387+ }
388+ } ) ;
389+ }
390+
312391 // If the arguments should be wrapped in a tuple (ex: closures), unwrap them here
313392 let ( formal_input_tys, expected_input_tys) = if tuple_arguments == TupleArguments {
393+ // Since the expected inputs are unpacked from a single tuple,
394+ // each input meets the callee bounds if and only if the tuple does.
395+ expected_meets_callee_bounds. resize (
396+ provided_args. len ( ) ,
397+ expected_meets_callee_bounds. first ( ) . copied ( ) . unwrap_or ( true ) ,
398+ ) ;
399+
314400 let tuple_type = self . structurally_resolve_type ( call_span, formal_input_tys[ 0 ] ) ;
315401 match tuple_type. kind ( ) {
316402 // We expected a tuple and got a tuple
@@ -373,7 +459,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
373459 // We're on the happy path here, so we'll do a more involved check and write back types
374460 // To check compatibility, we'll do 3 things:
375461 // 1. Unify the provided argument with the expected type
376- let expectation = Expectation :: rvalue_hint ( self , expected_input_ty) ;
462+ let expectation = if expected_meets_callee_bounds[ idx] {
463+ Expectation :: rvalue_hint ( self , expected_input_ty)
464+ } else {
465+ // If the expected input does not satisfy the callee's bounds, we must
466+ // weaken the expectation; otherwise, coercing to a type that violates
467+ // those bounds would result in a type mismatch.
468+ // See https://github.com/rust-lang/rust/issues/149379.
469+ Expectation :: ExpectRvalueLikeUnsized ( expected_input_ty)
470+ } ;
377471
378472 let checked_ty = self . check_expr_with_expectation ( provided_arg, expectation) ;
379473
0 commit comments