@@ -198,6 +198,7 @@ use arena::Arena;
198198use middle:: ty;
199199use std:: fmt;
200200use syntax:: ast;
201+ use syntax:: ast_map;
201202use syntax:: ast_util;
202203use syntax:: owned_slice:: OwnedSlice ;
203204use syntax:: visit;
@@ -517,6 +518,13 @@ impl<'a> Visitor<()> for ConstraintContext<'a> {
517518 }
518519}
519520
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+
520528impl < ' a > ConstraintContext < ' a > {
521529 fn tcx ( & self ) -> & ' a ty:: ctxt {
522530 self . terms_cx . tcx
@@ -533,8 +541,68 @@ impl<'a> ConstraintContext<'a> {
533541 }
534542 }
535543
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?
536560 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;
538606 }
539607
540608 fn declared_variance ( & self ,
0 commit comments