@@ -198,6 +198,7 @@ use arena::Arena;
198
198
use middle:: ty;
199
199
use std:: fmt;
200
200
use syntax:: ast;
201
+ use syntax:: ast_map;
201
202
use syntax:: ast_util;
202
203
use syntax:: owned_slice:: OwnedSlice ;
203
204
use syntax:: visit;
@@ -517,6 +518,13 @@ impl<'a> Visitor<()> for ConstraintContext<'a> {
517
518
}
518
519
}
519
520
521
+ /// Is `param_id` a lifetime according to `map`?
522
+ fn is_lifetime ( map : & ast_map:: Map , param_id : ast:: NodeId ) -> bool {
523
+ match map. find ( param_id) {
524
+ Some ( ast_map:: NodeLifetime ( ..) ) => true , _ => false
525
+ }
526
+ }
527
+
520
528
impl < ' a > ConstraintContext < ' a > {
521
529
fn tcx ( & self ) -> & ' a ty:: ctxt {
522
530
self . terms_cx . tcx
@@ -533,8 +541,68 @@ impl<'a> ConstraintContext<'a> {
533
541
}
534
542
}
535
543
544
+ fn find_binding_for_lifetime ( & self , param_id : ast:: NodeId ) -> ast:: NodeId {
545
+ let tcx = self . terms_cx . tcx ;
546
+ assert ! ( is_lifetime( & tcx. map, param_id) ) ;
547
+ match tcx. named_region_map . find ( & param_id) {
548
+ Some ( & ast:: DefEarlyBoundRegion ( _, lifetime_decl_id) )
549
+ => lifetime_decl_id,
550
+ Some ( _) => fail ! ( "should not encounter non early-bound cases" ) ,
551
+
552
+ // The lookup should only fail when `param_id` is
553
+ // itself a lifetime binding: use it as the decl_id.
554
+ None => param_id,
555
+ }
556
+
557
+ }
558
+
559
+ /// Is `param_id` a type parameter for which we infer variance?
536
560
fn is_to_be_inferred ( & self , param_id : ast:: NodeId ) -> bool {
537
- self . terms_cx . inferred_map . contains_key ( & param_id)
561
+ let result = self . terms_cx . inferred_map . contains_key ( & param_id) ;
562
+
563
+ // To safe-guard against invalid inferred_map constructions,
564
+ // double-check if variance is inferred at some use of a type
565
+ // parameter (by inspecting parent of its binding declaration
566
+ // to see if it is introduced by a type or by a fn/impl).
567
+
568
+ let check_result = |this : & ConstraintContext | -> bool {
569
+ let tcx = this. terms_cx . tcx ;
570
+ let decl_id = this. find_binding_for_lifetime ( param_id) ;
571
+ // Currently only called on lifetimes; double-checking that.
572
+ assert ! ( is_lifetime( & tcx. map, param_id) ) ;
573
+ let parent_id = tcx. map . get_parent ( decl_id) ;
574
+ let parent = tcx. map . find ( parent_id) . unwrap_or_else (
575
+ || fail ! ( "tcx.map missing entry for id: {}" , parent_id) ) ;
576
+
577
+ let is_inferred;
578
+ macro_rules! cannot_happen { ( ) => { {
579
+ fail!( "invalid parent: {:s} for {:s}" ,
580
+ tcx. map. node_to_str( parent_id) ,
581
+ tcx. map. node_to_str( param_id) ) ;
582
+ } } }
583
+
584
+ match parent {
585
+ ast_map:: NodeItem ( p) => {
586
+ match p. node {
587
+ ast:: ItemTy ( ..) |
588
+ ast:: ItemEnum ( ..) |
589
+ ast:: ItemStruct ( ..) |
590
+ ast:: ItemTrait ( ..) => is_inferred = true ,
591
+ ast:: ItemFn ( ..) => is_inferred = false ,
592
+ _ => cannot_happen ! ( ) ,
593
+ }
594
+ }
595
+ ast_map:: NodeTraitMethod ( ..) => is_inferred = false ,
596
+ ast_map:: NodeMethod ( _) => is_inferred = false ,
597
+ _ => cannot_happen ! ( ) ,
598
+ }
599
+
600
+ return is_inferred;
601
+ } ;
602
+
603
+ assert_eq ! ( result, check_result( self ) ) ;
604
+
605
+ return result;
538
606
}
539
607
540
608
fn declared_variance ( & self ,
0 commit comments