@@ -492,6 +492,20 @@ fn polymorphize<'tcx>(
492492 let unused = tcx. unused_generic_params ( def_id) ;
493493 debug ! ( "polymorphize: unused={:?}" , unused) ;
494494
495+ // If this is a closure or generator then we need to handle the case where another closure
496+ // from the function is captured as an upvar and hasn't been polymorphized. In this case,
497+ // the unpolymorphized upvar closure would result in a polymorphized closure producing
498+ // multiple mono items (and eventually symbol clashes).
499+ let upvars_ty = if tcx. is_closure ( def_id) {
500+ Some ( substs. as_closure ( ) . tupled_upvars_ty ( ) )
501+ } else if tcx. type_of ( def_id) . is_generator ( ) {
502+ Some ( substs. as_generator ( ) . tupled_upvars_ty ( ) )
503+ } else {
504+ None
505+ } ;
506+ let has_upvars = upvars_ty. map ( |ty| ty. tuple_fields ( ) . count ( ) > 0 ) . unwrap_or ( false ) ;
507+ debug ! ( "polymorphize: upvars_ty={:?} has_upvars={:?}" , upvars_ty, has_upvars) ;
508+
495509 struct PolymorphizationFolder < ' tcx > {
496510 tcx : TyCtxt < ' tcx > ,
497511 } ;
@@ -512,14 +526,6 @@ fn polymorphize<'tcx>(
512526 self . tcx . mk_closure ( def_id, polymorphized_substs)
513527 }
514528 }
515- ty:: FnDef ( def_id, substs) => {
516- let polymorphized_substs = polymorphize ( self . tcx , def_id, substs) ;
517- if substs == polymorphized_substs {
518- ty
519- } else {
520- self . tcx . mk_fn_def ( def_id, polymorphized_substs)
521- }
522- }
523529 ty:: Generator ( def_id, substs, movability) => {
524530 let polymorphized_substs = polymorphize ( self . tcx , def_id, substs) ;
525531 if substs == polymorphized_substs {
@@ -537,24 +543,31 @@ fn polymorphize<'tcx>(
537543 let is_unused = unused. contains ( param. index ) . unwrap_or ( false ) ;
538544 debug ! ( "polymorphize: param={:?} is_unused={:?}" , param, is_unused) ;
539545 match param. kind {
540- // If parameter is a const or type parameter..
546+ // Upvar case: If parameter is a type parameter..
547+ ty:: GenericParamDefKind :: Type { .. } if
548+ // ..and has upvars..
549+ has_upvars &&
550+ // ..and this param has the same type as the tupled upvars..
551+ upvars_ty == Some ( substs[ param. index as usize ] . expect_ty ( ) ) => {
552+ // ..then double-check that polymorphization marked it used..
553+ debug_assert ! ( !is_unused) ;
554+ // ..and polymorphize any closures/generators captured as upvars.
555+ let upvars_ty = upvars_ty. unwrap ( ) ;
556+ let polymorphized_upvars_ty = upvars_ty. fold_with (
557+ & mut PolymorphizationFolder { tcx } ) ;
558+ debug ! ( "polymorphize: polymorphized_upvars_ty={:?}" , polymorphized_upvars_ty) ;
559+ ty:: GenericArg :: from ( polymorphized_upvars_ty)
560+ } ,
561+
562+ // Simple case: If parameter is a const or type parameter..
541563 ty:: GenericParamDefKind :: Const | ty:: GenericParamDefKind :: Type { .. } if
542564 // ..and is within range and unused..
543565 unused. contains ( param. index ) . unwrap_or ( false ) =>
544566 // ..then use the identity for this parameter.
545567 tcx. mk_param_from_def ( param) ,
546568
547- // If the parameter does not contain any closures or generators, then use the
548- // substitution directly.
549- _ if !substs. may_polymorphize ( ) => substs[ param. index as usize ] ,
550-
551- // Otherwise, use the substitution after polymorphizing.
552- _ => {
553- let arg = substs[ param. index as usize ] ;
554- let polymorphized_arg = arg. fold_with ( & mut PolymorphizationFolder { tcx } ) ;
555- debug ! ( "polymorphize: arg={:?} polymorphized_arg={:?}" , arg, polymorphized_arg) ;
556- ty:: GenericArg :: from ( polymorphized_arg)
557- }
569+ // Otherwise, use the parameter as before.
570+ _ => substs[ param. index as usize ] ,
558571 }
559572 } )
560573}
0 commit comments