Skip to content

Commit 99c258c

Browse files
committed
auto merge of #13261 : pnkfelix/rust/fsk-fix-12856, r=nikomatsakis
Fix #12856. I wanted to put this up first because I wanted to get feedback about the second commit in the series, commit 8599236. Its the more invasive part of the patch and is largely just belt-and-suspenders assertion checking; in the commit message I mentioned at least one other approach we could take here. Or we could drop the belt-and-suspenders and just rely on the guard added in the first patch, commit 8d6a005 (which is really quite trivial on its own). So any feedback on what would be better is appreciated. r? @nikomatsakis
2 parents ff0b0d5 + 3099451 commit 99c258c

File tree

6 files changed

+219
-35
lines changed

6 files changed

+219
-35
lines changed

src/librustc/middle/trans/monomorphize.rs

+1
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ pub fn monomorphic_fn(ccx: &CrateContext,
272272
}
273273

274274
// Ugh -- but this ensures any new variants won't be forgotten
275+
ast_map::NodeLifetime(..) |
275276
ast_map::NodeExpr(..) |
276277
ast_map::NodeStmt(..) |
277278
ast_map::NodeArg(..) |

src/librustc/middle/typeck/variance.rs

+76-2
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ use arena::Arena;
198198
use middle::ty;
199199
use std::fmt;
200200
use syntax::ast;
201+
use syntax::ast_map;
201202
use syntax::ast_util;
202203
use syntax::owned_slice::OwnedSlice;
203204
use 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+
520528
impl<'a> ConstraintContext<'a> {
521529
fn tcx(&self) -> &'a ty::ctxt {
522530
self.terms_cx.tcx
@@ -533,6 +541,70 @@ 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?
560+
fn is_to_be_inferred(&self, param_id: ast::NodeId) -> bool {
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;
606+
}
607+
536608
fn declared_variance(&self,
537609
param_def_id: ast::DefId,
538610
item_def_id: ast::DefId,
@@ -788,8 +860,10 @@ impl<'a> ConstraintContext<'a> {
788860
variance: VarianceTermPtr<'a>) {
789861
match region {
790862
ty::ReEarlyBound(param_id, _, _) => {
791-
let index = self.inferred_index(param_id);
792-
self.add_constraint(index, variance);
863+
if self.is_to_be_inferred(param_id) {
864+
let index = self.inferred_index(param_id);
865+
self.add_constraint(index, variance);
866+
}
793867
}
794868

795869
ty::ReStatic => { }

src/libsyntax/ast_map.rs

+25
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ pub enum Node {
107107

108108
/// NodeStructCtor represents a tuple struct.
109109
NodeStructCtor(@StructDef),
110+
111+
NodeLifetime(@Lifetime),
110112
}
111113

112114
// The odd layout is to bring down the total size.
@@ -127,6 +129,7 @@ enum MapEntry {
127129
EntryLocal(NodeId, @Pat),
128130
EntryBlock(NodeId, P<Block>),
129131
EntryStructCtor(NodeId, @StructDef),
132+
EntryLifetime(NodeId, @Lifetime),
130133

131134
// Roots for node trees.
132135
RootCrate,
@@ -153,6 +156,7 @@ impl MapEntry {
153156
EntryLocal(id, _) => id,
154157
EntryBlock(id, _) => id,
155158
EntryStructCtor(id, _) => id,
159+
EntryLifetime(id, _) => id,
156160
_ => return None
157161
})
158162
}
@@ -170,6 +174,7 @@ impl MapEntry {
170174
EntryLocal(_, p) => NodeLocal(p),
171175
EntryBlock(_, p) => NodeBlock(p),
172176
EntryStructCtor(_, p) => NodeStructCtor(p),
177+
EntryLifetime(_, p) => NodeLifetime(p),
173178
_ => return None
174179
})
175180
}
@@ -213,6 +218,8 @@ impl Map {
213218
self.find_entry(id).and_then(|x| x.to_node())
214219
}
215220

221+
/// Retrieve the parent NodeId for `id`, or `id` itself if no
222+
/// parent is registered in this map.
216223
pub fn get_parent(&self, id: NodeId) -> NodeId {
217224
self.find_entry(id).and_then(|x| x.parent()).unwrap_or(id)
218225
}
@@ -500,6 +507,15 @@ impl<'a, F: FoldOps> Folder for Ctx<'a, F> {
500507
SmallVector::one(stmt)
501508
}
502509

510+
fn fold_type_method(&mut self, m: &TypeMethod) -> TypeMethod {
511+
let parent = self.parent;
512+
self.parent = DUMMY_NODE_ID;
513+
let m = fold::noop_fold_type_method(m, self);
514+
assert_eq!(self.parent, m.id);
515+
self.parent = parent;
516+
m
517+
}
518+
503519
fn fold_method(&mut self, m: @Method) -> @Method {
504520
let parent = self.parent;
505521
self.parent = DUMMY_NODE_ID;
@@ -522,6 +538,12 @@ impl<'a, F: FoldOps> Folder for Ctx<'a, F> {
522538
self.insert(block.id, EntryBlock(self.parent, block));
523539
block
524540
}
541+
542+
fn fold_lifetime(&mut self, lifetime: &Lifetime) -> Lifetime {
543+
let lifetime = fold::noop_fold_lifetime(lifetime, self);
544+
self.insert(lifetime.id, EntryLifetime(self.parent, @lifetime));
545+
lifetime
546+
}
525547
}
526548

527549
pub fn map_crate<F: FoldOps>(krate: Crate, fold_ops: F) -> (Crate, Map) {
@@ -658,6 +680,9 @@ fn node_id_to_str(map: &Map, id: NodeId) -> ~str {
658680
Some(NodeStructCtor(_)) => {
659681
format!("struct_ctor {} (id={})", map.path_to_str(id), id)
660682
}
683+
Some(NodeLifetime(ref l)) => {
684+
format!("lifetime {} (id={})", pprust::lifetime_to_str(*l), id)
685+
}
661686
None => {
662687
format!("unknown node (id={})", id)
663688
}

0 commit comments

Comments
 (0)