diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs index 6f2dbc182b04f..f7b444e439f40 100644 --- a/src/librustc/middle/trans/monomorphize.rs +++ b/src/librustc/middle/trans/monomorphize.rs @@ -272,6 +272,7 @@ pub fn monomorphic_fn(ccx: &CrateContext, } // Ugh -- but this ensures any new variants won't be forgotten + ast_map::NodeLifetime(..) | ast_map::NodeExpr(..) | ast_map::NodeStmt(..) | ast_map::NodeArg(..) | diff --git a/src/librustc/middle/typeck/variance.rs b/src/librustc/middle/typeck/variance.rs index c6c79608f6c31..ecf4f67e7cd73 100644 --- a/src/librustc/middle/typeck/variance.rs +++ b/src/librustc/middle/typeck/variance.rs @@ -198,6 +198,7 @@ use arena::Arena; use middle::ty; use std::fmt; use syntax::ast; +use syntax::ast_map; use syntax::ast_util; use syntax::owned_slice::OwnedSlice; use syntax::visit; @@ -517,6 +518,13 @@ impl<'a> Visitor<()> for ConstraintContext<'a> { } } +/// Is `param_id` a lifetime according to `map`? +fn is_lifetime(map: &ast_map::Map, param_id: ast::NodeId) -> bool { + match map.find(param_id) { + Some(ast_map::NodeLifetime(..)) => true, _ => false + } +} + impl<'a> ConstraintContext<'a> { fn tcx(&self) -> &'a ty::ctxt { self.terms_cx.tcx @@ -533,6 +541,70 @@ impl<'a> ConstraintContext<'a> { } } + fn find_binding_for_lifetime(&self, param_id: ast::NodeId) -> ast::NodeId { + let tcx = self.terms_cx.tcx; + assert!(is_lifetime(&tcx.map, param_id)); + match tcx.named_region_map.find(¶m_id) { + Some(&ast::DefEarlyBoundRegion(_, lifetime_decl_id)) + => lifetime_decl_id, + Some(_) => fail!("should not encounter non early-bound cases"), + + // The lookup should only fail when `param_id` is + // itself a lifetime binding: use it as the decl_id. + None => param_id, + } + + } + + /// Is `param_id` a type parameter for which we infer variance? + fn is_to_be_inferred(&self, param_id: ast::NodeId) -> bool { + let result = self.terms_cx.inferred_map.contains_key(¶m_id); + + // To safe-guard against invalid inferred_map constructions, + // double-check if variance is inferred at some use of a type + // parameter (by inspecting parent of its binding declaration + // to see if it is introduced by a type or by a fn/impl). + + let check_result = |this:&ConstraintContext| -> bool { + let tcx = this.terms_cx.tcx; + let decl_id = this.find_binding_for_lifetime(param_id); + // Currently only called on lifetimes; double-checking that. + assert!(is_lifetime(&tcx.map, param_id)); + let parent_id = tcx.map.get_parent(decl_id); + let parent = tcx.map.find(parent_id).unwrap_or_else( + || fail!("tcx.map missing entry for id: {}", parent_id)); + + let is_inferred; + macro_rules! cannot_happen { () => { { + fail!("invalid parent: {:s} for {:s}", + tcx.map.node_to_str(parent_id), + tcx.map.node_to_str(param_id)); + } } } + + match parent { + ast_map::NodeItem(p) => { + match p.node { + ast::ItemTy(..) | + ast::ItemEnum(..) | + ast::ItemStruct(..) | + ast::ItemTrait(..) => is_inferred = true, + ast::ItemFn(..) => is_inferred = false, + _ => cannot_happen!(), + } + } + ast_map::NodeTraitMethod(..) => is_inferred = false, + ast_map::NodeMethod(_) => is_inferred = false, + _ => cannot_happen!(), + } + + return is_inferred; + }; + + assert_eq!(result, check_result(self)); + + return result; + } + fn declared_variance(&self, param_def_id: ast::DefId, item_def_id: ast::DefId, @@ -788,8 +860,10 @@ impl<'a> ConstraintContext<'a> { variance: VarianceTermPtr<'a>) { match region { ty::ReEarlyBound(param_id, _, _) => { - let index = self.inferred_index(param_id); - self.add_constraint(index, variance); + if self.is_to_be_inferred(param_id) { + let index = self.inferred_index(param_id); + self.add_constraint(index, variance); + } } ty::ReStatic => { } diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs index 4c7803f022a15..45954800e7e9a 100644 --- a/src/libsyntax/ast_map.rs +++ b/src/libsyntax/ast_map.rs @@ -107,6 +107,8 @@ pub enum Node { /// NodeStructCtor represents a tuple struct. NodeStructCtor(@StructDef), + + NodeLifetime(@Lifetime), } // The odd layout is to bring down the total size. @@ -127,6 +129,7 @@ enum MapEntry { EntryLocal(NodeId, @Pat), EntryBlock(NodeId, P), EntryStructCtor(NodeId, @StructDef), + EntryLifetime(NodeId, @Lifetime), // Roots for node trees. RootCrate, @@ -153,6 +156,7 @@ impl MapEntry { EntryLocal(id, _) => id, EntryBlock(id, _) => id, EntryStructCtor(id, _) => id, + EntryLifetime(id, _) => id, _ => return None }) } @@ -170,6 +174,7 @@ impl MapEntry { EntryLocal(_, p) => NodeLocal(p), EntryBlock(_, p) => NodeBlock(p), EntryStructCtor(_, p) => NodeStructCtor(p), + EntryLifetime(_, p) => NodeLifetime(p), _ => return None }) } @@ -213,6 +218,8 @@ impl Map { self.find_entry(id).and_then(|x| x.to_node()) } + /// Retrieve the parent NodeId for `id`, or `id` itself if no + /// parent is registered in this map. pub fn get_parent(&self, id: NodeId) -> NodeId { self.find_entry(id).and_then(|x| x.parent()).unwrap_or(id) } @@ -500,6 +507,15 @@ impl<'a, F: FoldOps> Folder for Ctx<'a, F> { SmallVector::one(stmt) } + fn fold_type_method(&mut self, m: &TypeMethod) -> TypeMethod { + let parent = self.parent; + self.parent = DUMMY_NODE_ID; + let m = fold::noop_fold_type_method(m, self); + assert_eq!(self.parent, m.id); + self.parent = parent; + m + } + fn fold_method(&mut self, m: @Method) -> @Method { let parent = self.parent; self.parent = DUMMY_NODE_ID; @@ -522,6 +538,12 @@ impl<'a, F: FoldOps> Folder for Ctx<'a, F> { self.insert(block.id, EntryBlock(self.parent, block)); block } + + fn fold_lifetime(&mut self, lifetime: &Lifetime) -> Lifetime { + let lifetime = fold::noop_fold_lifetime(lifetime, self); + self.insert(lifetime.id, EntryLifetime(self.parent, @lifetime)); + lifetime + } } pub fn map_crate(krate: Crate, fold_ops: F) -> (Crate, Map) { @@ -658,6 +680,9 @@ fn node_id_to_str(map: &Map, id: NodeId) -> ~str { Some(NodeStructCtor(_)) => { format!("struct_ctor {} (id={})", map.path_to_str(id), id) } + Some(NodeLifetime(ref l)) => { + format!("lifetime {} (id={})", pprust::lifetime_to_str(*l), id) + } None => { format!("unknown node (id={})", id) } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 63df5566fa5df..cc3ae025263d1 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -32,14 +32,17 @@ pub trait Folder { view_paths.iter().map(|view_path| { let inner_view_path = match view_path.node { ViewPathSimple(ref ident, ref path, node_id) => { + let id = self.new_id(node_id); ViewPathSimple(ident.clone(), self.fold_path(path), - self.new_id(node_id)) + id) } ViewPathGlob(ref path, node_id) => { - ViewPathGlob(self.fold_path(path), self.new_id(node_id)) + let id = self.new_id(node_id); + ViewPathGlob(self.fold_path(path), id) } ViewPathList(ref path, ref path_list_idents, node_id) => { + let id = self.new_id(node_id); ViewPathList(self.fold_path(path), path_list_idents.iter().map(|path_list_ident| { let id = self.new_id(path_list_ident.node @@ -55,7 +58,7 @@ pub trait Folder { path_list_ident.span) } }).collect(), - self.new_id(node_id)) + id) } }; @Spanned { @@ -78,10 +81,11 @@ pub trait Folder { } fn fold_struct_field(&mut self, sf: &StructField) -> StructField { + let id = self.new_id(sf.node.id); Spanned { node: ast::StructField_ { kind: sf.node.kind, - id: self.new_id(sf.node.id), + id: id, ty: self.fold_ty(sf.node.ty), attrs: sf.node.attrs.iter().map(|e| fold_attribute_(*e, self)).collect() }, @@ -146,6 +150,7 @@ pub trait Folder { } fn fold_ty(&mut self, t: P) -> P { + let id = self.new_id(t.id); let node = match t.node { TyNil | TyBot | TyInfer => t.node.clone(), TyBox(ty) => TyBox(self.fold_ty(ty)), @@ -161,7 +166,7 @@ pub trait Folder { onceness: f.onceness, bounds: fold_opt_bounds(&f.bounds, self), decl: self.fold_fn_decl(f.decl), - lifetimes: f.lifetimes.iter().map(|l| fold_lifetime(l, self)).collect(), + lifetimes: f.lifetimes.iter().map(|l| self.fold_lifetime(l)).collect(), }, fold_opt_lifetime(region, self)) } TyProc(ref f) => { @@ -170,12 +175,12 @@ pub trait Folder { onceness: f.onceness, bounds: fold_opt_bounds(&f.bounds, self), decl: self.fold_fn_decl(f.decl), - lifetimes: f.lifetimes.iter().map(|l| fold_lifetime(l, self)).collect(), + lifetimes: f.lifetimes.iter().map(|l| self.fold_lifetime(l)).collect(), }) } TyBareFn(ref f) => { TyBareFn(@BareFnTy { - lifetimes: f.lifetimes.iter().map(|l| fold_lifetime(l, self)).collect(), + lifetimes: f.lifetimes.iter().map(|l| self.fold_lifetime(l)).collect(), fn_style: f.fn_style, abi: f.abi, decl: self.fold_fn_decl(f.decl) @@ -183,9 +188,10 @@ pub trait Folder { } TyTup(ref tys) => TyTup(tys.iter().map(|&ty| self.fold_ty(ty)).collect()), TyPath(ref path, ref bounds, id) => { + let id = self.new_id(id); TyPath(self.fold_path(path), fold_opt_bounds(bounds, self), - self.new_id(id)) + id) } TyFixedLengthVec(ty, e) => { TyFixedLengthVec(self.fold_ty(ty), self.fold_expr(e)) @@ -193,7 +199,7 @@ pub trait Folder { TyTypeof(expr) => TyTypeof(self.fold_expr(expr)), }; P(Ty { - id: self.new_id(t.id), + id: id, span: self.new_span(t.span), node: node, }) @@ -218,6 +224,7 @@ pub trait Folder { } fn fold_variant(&mut self, v: &Variant) -> P { + let id = self.new_id(v.node.id); let kind; match v.node.kind { TupleVariantKind(ref variant_args) => { @@ -243,7 +250,7 @@ pub trait Folder { name: v.node.name, attrs: attrs, kind: kind, - id: self.new_id(v.node.id), + id: id, disr_expr: de, vis: v.node.vis, }; @@ -263,15 +270,16 @@ pub trait Folder { global: p.global, segments: p.segments.iter().map(|segment| ast::PathSegment { identifier: self.fold_ident(segment.identifier), - lifetimes: segment.lifetimes.iter().map(|l| fold_lifetime(l, self)).collect(), + lifetimes: segment.lifetimes.iter().map(|l| self.fold_lifetime(l)).collect(), types: segment.types.iter().map(|&typ| self.fold_ty(typ)).collect(), }).collect() } } fn fold_local(&mut self, l: @Local) -> @Local { + let id = self.new_id(l.id); // Needs to be first, for ast_map. @Local { - id: self.new_id(l.id), // Needs to be first, for ast_map. + id: id, ty: self.fold_ty(l.ty), pat: self.fold_pat(l.pat), init: l.init.map(|e| self.fold_expr(e)), @@ -319,6 +327,10 @@ pub trait Folder { } } } + + fn fold_lifetime(&mut self, l: &Lifetime) -> Lifetime { + noop_fold_lifetime(l, self) + } } /* some little folds that probably aren't useful to have in Folder itself*/ @@ -353,8 +365,9 @@ fn fold_attribute_(at: Attribute, fld: &mut T) -> Attribute { //used in noop_fold_foreign_item and noop_fold_fn_decl fn fold_arg_(a: &Arg, fld: &mut T) -> Arg { + let id = fld.new_id(a.id); // Needs to be first, for ast_map. Arg { - id: fld.new_id(a.id), // Needs to be first, for ast_map. + id: id, ty: fld.fold_ty(a.ty), pat: fld.fold_pat(a.pat), } @@ -425,9 +438,10 @@ fn fold_ty_param_bound(tpb: &TyParamBound, fld: &mut T) } pub fn fold_ty_param(tp: &TyParam, fld: &mut T) -> TyParam { + let id = fld.new_id(tp.id); TyParam { ident: tp.ident, - id: fld.new_id(tp.id), + id: id, bounds: tp.bounds.map(|x| fold_ty_param_bound(x, fld)), default: tp.default.map(|x| fld.fold_ty(x)) } @@ -438,9 +452,10 @@ pub fn fold_ty_params(tps: &OwnedSlice, fld: &mut T) tps.map(|tp| fold_ty_param(tp, fld)) } -pub fn fold_lifetime(l: &Lifetime, fld: &mut T) -> Lifetime { +pub fn noop_fold_lifetime(l: &Lifetime, fld: &mut T) -> Lifetime { + let id = fld.new_id(l.id); Lifetime { - id: fld.new_id(l.id), + id: id, span: fld.new_span(l.span), name: l.name } @@ -448,12 +463,12 @@ pub fn fold_lifetime(l: &Lifetime, fld: &mut T) -> Lifetime { pub fn fold_lifetimes(lts: &Vec, fld: &mut T) -> Vec { - lts.iter().map(|l| fold_lifetime(l, fld)).collect() + lts.iter().map(|l| fld.fold_lifetime(l)).collect() } pub fn fold_opt_lifetime(o_lt: &Option, fld: &mut T) -> Option { - o_lt.as_ref().map(|lt| fold_lifetime(lt, fld)) + o_lt.as_ref().map(|lt| fld.fold_lifetime(lt)) } pub fn fold_generics(generics: &Generics, fld: &mut T) -> Generics { @@ -469,17 +484,19 @@ fn fold_struct_def(struct_def: @StructDef, fld: &mut T) -> @StructDef } fn fold_trait_ref(p: &TraitRef, fld: &mut T) -> TraitRef { + let id = fld.new_id(p.ref_id); ast::TraitRef { path: fld.fold_path(&p.path), - ref_id: fld.new_id(p.ref_id), + ref_id: id, } } fn fold_struct_field(f: &StructField, fld: &mut T) -> StructField { + let id = fld.new_id(f.node.id); Spanned { node: ast::StructField_ { kind: f.node.kind, - id: fld.new_id(f.node.id), + id: id, ty: fld.fold_ty(f.node.ty), attrs: f.node.attrs.iter().map(|a| fold_attribute_(*a, fld)).collect(), }, @@ -512,9 +529,10 @@ fn fold_opt_bounds(b: &Option>, folder: &mut } fn fold_variant_arg_(va: &VariantArg, folder: &mut T) -> VariantArg { + let id = folder.new_id(va.id); ast::VariantArg { ty: folder.fold_ty(va.ty), - id: folder.new_id(va.id) + id: id, } } @@ -539,10 +557,11 @@ pub fn noop_fold_view_item(vi: &ViewItem, folder: &mut T) } pub fn noop_fold_block(b: P, folder: &mut T) -> P { + let id = folder.new_id(b.id); // Needs to be first, for ast_map. let view_items = b.view_items.iter().map(|x| folder.fold_view_item(x)).collect(); let stmts = b.stmts.iter().flat_map(|s| folder.fold_stmt(*s).move_iter()).collect(); P(Block { - id: folder.new_id(b.id), // Needs to be first, for ast_map. + id: id, view_items: view_items, stmts: stmts, expr: b.expr.map(|x| folder.fold_expr(x)), @@ -606,8 +625,9 @@ pub fn noop_fold_item_underscore(i: &Item_, folder: &mut T) -> Item_ } pub fn noop_fold_type_method(m: &TypeMethod, fld: &mut T) -> TypeMethod { + let id = fld.new_id(m.id); // Needs to be first, for ast_map. TypeMethod { - id: fld.new_id(m.id), // Needs to be first, for ast_map. + id: id, ident: fld.fold_ident(m.ident), attrs: m.attrs.iter().map(|a| fold_attribute_(*a, fld)).collect(), fn_style: m.fn_style, @@ -658,8 +678,9 @@ pub fn noop_fold_item(i: &Item, folder: &mut T) -> SmallVector<@Item> } pub fn noop_fold_foreign_item(ni: &ForeignItem, folder: &mut T) -> @ForeignItem { + let id = folder.new_id(ni.id); // Needs to be first, for ast_map. @ForeignItem { - id: folder.new_id(ni.id), // Needs to be first, for ast_map. + id: id, ident: folder.fold_ident(ni.ident), attrs: ni.attrs.iter().map(|x| fold_attribute_(*x, folder)).collect(), node: match ni.node { @@ -681,8 +702,9 @@ pub fn noop_fold_foreign_item(ni: &ForeignItem, folder: &mut T) -> @F } pub fn noop_fold_method(m: &Method, folder: &mut T) -> @Method { + let id = folder.new_id(m.id); // Needs to be first, for ast_map. @Method { - id: folder.new_id(m.id), // Needs to be first, for ast_map. + id: id, ident: folder.fold_ident(m.ident), attrs: m.attrs.iter().map(|a| fold_attribute_(*a, folder)).collect(), generics: fold_generics(&m.generics, folder), @@ -696,6 +718,7 @@ pub fn noop_fold_method(m: &Method, folder: &mut T) -> @Method { } pub fn noop_fold_pat(p: @Pat, folder: &mut T) -> @Pat { + let id = folder.new_id(p.id); let node = match p.node { PatWild => PatWild, PatWildMulti => PatWildMulti, @@ -733,13 +756,14 @@ pub fn noop_fold_pat(p: @Pat, folder: &mut T) -> @Pat { }; @Pat { - id: folder.new_id(p.id), + id: id, span: folder.new_span(p.span), node: node, } } pub fn noop_fold_expr(e: @Expr, folder: &mut T) -> @Expr { + let id = folder.new_id(e.id); let node = match e.node { ExprVstore(e, v) => { ExprVstore(folder.fold_expr(e), v) @@ -849,7 +873,7 @@ pub fn noop_fold_expr(e: @Expr, folder: &mut T) -> @Expr { }; @Expr { - id: folder.new_id(e.id), + id: id, node: node, span: folder.new_span(e.span), } @@ -857,16 +881,19 @@ pub fn noop_fold_expr(e: @Expr, folder: &mut T) -> @Expr { pub fn noop_fold_stmt(s: &Stmt, folder: &mut T) -> SmallVector<@Stmt> { let nodes = match s.node { - StmtDecl(d, nid) => { + StmtDecl(d, id) => { + let id = folder.new_id(id); folder.fold_decl(d).move_iter() - .map(|d| StmtDecl(d, folder.new_id(nid))) + .map(|d| StmtDecl(d, id)) .collect() } - StmtExpr(e, nid) => { - SmallVector::one(StmtExpr(folder.fold_expr(e), folder.new_id(nid))) + StmtExpr(e, id) => { + let id = folder.new_id(id); + SmallVector::one(StmtExpr(folder.fold_expr(e), id)) } - StmtSemi(e, nid) => { - SmallVector::one(StmtSemi(folder.fold_expr(e), folder.new_id(nid))) + StmtSemi(e, id) => { + let id = folder.new_id(id); + SmallVector::one(StmtSemi(folder.fold_expr(e), id)) } StmtMac(ref mac, semi) => SmallVector::one(StmtMac(folder.fold_mac(mac), semi)) }; diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 928ec09b3aec2..429540efd37e7 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -183,6 +183,18 @@ pub fn generics_to_str(generics: &ast::Generics) -> ~str { to_str(|s| s.print_generics(generics)) } +pub fn ty_method_to_str(p: &ast::TypeMethod) -> ~str { + to_str(|s| s.print_ty_method(p)) +} + +pub fn method_to_str(p: &ast::Method) -> ~str { + to_str(|s| s.print_method(p)) +} + +pub fn fn_block_to_str(p: &ast::FnDecl) -> ~str { + to_str(|s| s.print_fn_block_args(p)) +} + pub fn path_to_str(p: &ast::Path) -> ~str { to_str(|s| s.print_path(p, false)) } diff --git a/src/test/run-pass/regions-no-variance-from-fn-generics.rs b/src/test/run-pass/regions-no-variance-from-fn-generics.rs new file mode 100644 index 0000000000000..3814de79bb6b3 --- /dev/null +++ b/src/test/run-pass/regions-no-variance-from-fn-generics.rs @@ -0,0 +1,45 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Issue #12856: a lifetime formal binding introduced by a generic fn +// should not upset the variance inference for actual occurrences of +// that lifetime in type expressions. + +trait HasLife<'a> { } + +trait UseLife01 { + fn refs<'a, H: HasLife<'a>>(&'a self) -> H; +} + +trait UseLife02 { + fn refs<'a, T, H: HasType<&'a T>>(&'a self) -> H; +} + + +trait HasType { } + +trait UseLife03 { + fn refs<'a, H: HasType<&'a T>>(&'a self) -> H; +} + + +// (The functions below were not actually a problem observed during +// fixing of #12856; they just seem like natural tests to put in to +// cover a couple more points in the testing space) + +pub fn top_refs_1<'a, H: HasLife<'a>>(_s: &'a ()) -> H { + unimplemented!() +} + +pub fn top_refs_2<'a, T, H: HasType<&'a T>>(_s: &'a ()) -> H { + unimplemented!() +} + +pub fn main() {}