@@ -492,6 +492,20 @@ fn polymorphize<'tcx>(
492
492
let unused = tcx. unused_generic_params ( def_id) ;
493
493
debug ! ( "polymorphize: unused={:?}" , unused) ;
494
494
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
+
495
509
struct PolymorphizationFolder < ' tcx > {
496
510
tcx : TyCtxt < ' tcx > ,
497
511
} ;
@@ -512,14 +526,6 @@ fn polymorphize<'tcx>(
512
526
self . tcx . mk_closure ( def_id, polymorphized_substs)
513
527
}
514
528
}
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
- }
523
529
ty:: Generator ( def_id, substs, movability) => {
524
530
let polymorphized_substs = polymorphize ( self . tcx , def_id, substs) ;
525
531
if substs == polymorphized_substs {
@@ -537,24 +543,31 @@ fn polymorphize<'tcx>(
537
543
let is_unused = unused. contains ( param. index ) . unwrap_or ( false ) ;
538
544
debug ! ( "polymorphize: param={:?} is_unused={:?}" , param, is_unused) ;
539
545
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..
541
563
ty:: GenericParamDefKind :: Const | ty:: GenericParamDefKind :: Type { .. } if
542
564
// ..and is within range and unused..
543
565
unused. contains ( param. index ) . unwrap_or ( false ) =>
544
566
// ..then use the identity for this parameter.
545
567
tcx. mk_param_from_def ( param) ,
546
568
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 ] ,
558
571
}
559
572
} )
560
573
}
0 commit comments